diff options
54 files changed, 2187 insertions, 449 deletions
@@ -1,11 +1,22 @@ -copyright +# blob **/*.o -stm32f091/main.elf -stm32f091/main.bin **/.cache **/compile_commands.json + +# stm32-specific files +stm32f091/main.elf +stm32f091/main.bin +stm32f091/wifi.h + +# client-specific files client/makefile client/client client/moc_* + +# others +shared/main .qmake.stash .vscode/.cortex-debug.registers.state.json +copyright +temp/ +**/.DS_Store diff --git a/.vscode/launch.json b/.vscode/launch.json index 9c586dc..b104e0f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -31,9 +31,8 @@ "executable": "${workspaceFolder}/stm32f091/main.elf", "request": "launch", "type": "cortex-debug", - "runToEntryPoint": "main", "servertype": "stlink", - "preLaunchTask": "stm32/build", + "preLaunchTask": "stm32/flash", "linux": { "stlinkPath": "/usr/bin/st-util" }, diff --git a/client/Client.cpp b/client/Client.cpp new file mode 100644 index 0000000..46952b6 --- /dev/null +++ b/client/Client.cpp @@ -0,0 +1,65 @@ +#include "Client.h" + + + +Client::Client(QObject *parent) : QObject(parent) +{ + // initislise timer and socket + socket = new QTcpSocket(this); + timer = new QTimer(this); +} +Client::~Client() +{ + // delete if called again + delete socket; + delete timer; +} + +void Client::ClientEcho() +{ + QTime time1 = QTime::currentTime(); + NextMinute = time1.minute()+1; + + connect(timer, SIGNAL(timeout()),this,SLOT(timeFunction())); // connect timer to time every minute + + // connect to readyread to receive data; + connect(socket,&QTcpSocket::readyRead, [&]() { + QTextStream T(socket); + QString text = T.readAll(); // reads all data + Handlemsg.ParseToSQL(Handlemsg.ParseMessage(text, (totalRecords-'0'))); + + + }); + + timer->start(1000); +} + +void Client::timeFunction() +{ + if(_missingRecords>1){ + totalRecords = _missingRecords; + } + else{ + totalRecords=1; + } + QByteArray msgToSend= (msg.toUtf8() + totalRecords + offsetRecords +'\n'); + + QTime time = QTime::currentTime(); + qint16 currentMinute = time.minute(); + + if(currentMinute==NextMinute){ + socket->connectToHost(networkAddress, tcpPortAddress); + + socket->write(msgToSend); + NextMinute++; + } +} + +void Client::missingRecords() +{ + QSqlQuery queryTimeData; + queryTimeData.exec("SELECT (unix_timestamp(now()) - unix_timestamp(`time`))/60 as delta FROM `WSdb`.`tblMain` limit 1"); + + _missingRecords = queryTimeData.value(0).toInt(); + +} diff --git a/client/Client.h b/client/Client.h new file mode 100644 index 0000000..10af3e1 --- /dev/null +++ b/client/Client.h @@ -0,0 +1,45 @@ +#ifndef CLIENT_H +#define CLIENT_H +#include <QTcpSocket> +#include <QTextStream> +#include <QTimer> +#include <QDateTime> +#include <QSqlQuery> + +#include "HandleMessage.h" + +// class client for wheather station +class Client : public QObject +{ + Q_OBJECT +public: + Client(QObject *parent = 0); + virtual ~Client(); + +public slots: + void ClientEcho(); // function to ask data from wheather station + void timeFunction(); // function to look every second what time currently is en handle if minute is passed + +private: + void missingRecords(); + + int _missingRecords; + QTcpSocket *socket; // tcpsocket for communicating + QTimer *timer; // timer to read every second what time it curruntly is. + + qint16 NextMinute; // timing for next minute + // qint16 currentMinute; // timing for currentMinute + HandleMessage Handlemsg; // add HandleMessage to Client.h + + int tcpPortAddress = 80; // port of communication via tcp + QString networkAddress = "192.168.137.76"; // network address for commincation via tcp + + QString msg = "last-records "; // part of mesage to send to wheather staion + char totalRecords = '1'; // total records to ask wheather station + char offsetRecords = '0'; // offset from reqeusting records + + + +}; + +#endif // CLIENT_H diff --git a/client/HandleMessage.cpp b/client/HandleMessage.cpp new file mode 100644 index 0000000..aa73828 --- /dev/null +++ b/client/HandleMessage.cpp @@ -0,0 +1,47 @@ +#include "HandleMessage.h" + + +HandleMessage::HandleMessage(QObject *parent) : QObject(parent) +{ + +} + +QString HandleMessage::ParseMessage(const QString Msg , int totalRecords ) +{ + QString message= Msg.section('\n',2,(3+totalRecords)); + + return message; + +} + +void HandleMessage::ParseToSQL(QString input) +{ + QSqlQuery queryInsertData; + QString output = "INSERT INTO `WSdb`.`tblMain` () VALUES "; + QStringList data; + QStringList list = input.split("\n"); + for (int i = 0; i < list.size(); ++i) { + + output += "("; + + data=list[i].split(","); + + for (int j = 1; j < data.size(); ++j) { + bool valid; + output.append(QString::number(data[j].toInt(&valid, 16))); + if (j <= data[j].size()) { + output.append(","); + } + + } + output.append(")"); + + if (i+1 < list.size()){ + output.append(","); + } + } + queryInsertData.exec(output); +} + + + diff --git a/client/HandleMessage.h b/client/HandleMessage.h new file mode 100644 index 0000000..bfc5063 --- /dev/null +++ b/client/HandleMessage.h @@ -0,0 +1,26 @@ +#ifndef HANDLEMESSAGE_H +#define HANDLEMESSAGE_H + +#include <QDebug> +#include <QObject> +#include <QString> +#include <QVector> +#include <QSqlQuery> + +class HandleMessage : public QObject +{ + Q_OBJECT +public: + HandleMessage(QObject *parent = 0); + + QString ParseMessage(const QString , int); + void ParseToSQL(QString); + + + +private: + +}; + + +#endif // HANDLEMESSAGE_H diff --git a/client/client.pro b/client/client.pro index 71ab6d5..76f2b56 100644 --- a/client/client.pro +++ b/client/client.pro @@ -1,20 +1,18 @@ QT += core gui sql charts network HEADERS += \ - csv_import.h \ + Client.h \ + HandleMessage.h \ dbconnector.h \ main.h \ - mainwindow.h \ - mytcpsocket.h \ - timetest.h + mainwindow.h SOURCES += \ - csv_import.cpp \ + Client.cpp \ + HandleMessage.cpp \ dbconnector.cpp \ main.cpp \ - mainwindow.cpp \ - mytcpsocket.cpp \ - timetest.cpp + mainwindow.cpp FORMS += \ diff --git a/client/client.pro.user b/client/client.pro.user new file mode 100644 index 0000000..7ccbc7b --- /dev/null +++ b/client/client.pro.user @@ -0,0 +1,260 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE QtCreatorProject> +<!-- Written by QtCreator 8.0.1, 2022-10-29T18:40:37. --> +<qtcreator> + <data> + <variable>EnvironmentId</variable> + <value type="QByteArray">{aa240e53-c124-4cf0-84a8-30bfe8a2cf83}</value> + </data> + <data> + <variable>ProjectExplorer.Project.ActiveTarget</variable> + <value type="qlonglong">0</value> + </data> + <data> + <variable>ProjectExplorer.Project.EditorSettings</variable> + <valuemap type="QVariantMap"> + <value type="bool" key="EditorConfiguration.AutoIndent">true</value> + <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value> + <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0"> + <value type="QString" key="language">Cpp</value> + <valuemap type="QVariantMap" key="value"> + <value type="QByteArray" key="CurrentPreferences">CppGlobal</value> + </valuemap> + </valuemap> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1"> + <value type="QString" key="language">QmlJS</value> + <valuemap type="QVariantMap" key="value"> + <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value> + </valuemap> + </valuemap> + <value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value> + <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value> + <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value> + <value type="int" key="EditorConfiguration.IndentSize">4</value> + <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value> + <value type="int" key="EditorConfiguration.MarginColumn">80</value> + <value type="bool" key="EditorConfiguration.MouseHiding">true</value> + <value type="bool" key="EditorConfiguration.MouseNavigation">true</value> + <value type="int" key="EditorConfiguration.PaddingMode">1</value> + <value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value> + <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value> + <value type="bool" key="EditorConfiguration.ShowMargin">false</value> + <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value> + <value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value> + <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value> + <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value> + <value type="int" key="EditorConfiguration.TabSize">8</value> + <value type="bool" key="EditorConfiguration.UseGlobal">true</value> + <value type="bool" key="EditorConfiguration.UseIndenter">false</value> + <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value> + <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value> + <value type="bool" key="EditorConfiguration.cleanIndentation">true</value> + <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value> + <value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value> + <value type="bool" key="EditorConfiguration.inEntireDocument">false</value> + <value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.PluginSettings</variable> + <valuemap type="QVariantMap"> + <valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks"> + <value type="bool" key="AutoTest.Framework.Boost">true</value> + <value type="bool" key="AutoTest.Framework.CTest">false</value> + <value type="bool" key="AutoTest.Framework.Catch">true</value> + <value type="bool" key="AutoTest.Framework.GTest">true</value> + <value type="bool" key="AutoTest.Framework.QtQuickTest">true</value> + <value type="bool" key="AutoTest.Framework.QtTest">true</value> + </valuemap> + <valuemap type="QVariantMap" key="AutoTest.CheckStates"/> + <value type="int" key="AutoTest.RunAfterBuild">0</value> + <value type="bool" key="AutoTest.UseGlobal">true</value> + <valuemap type="QVariantMap" key="ClangTools"> + <value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value> + <value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value> + <value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value> + <value type="int" key="ClangTools.ParallelJobs">4</value> + <valuelist type="QVariantList" key="ClangTools.SelectedDirs"/> + <valuelist type="QVariantList" key="ClangTools.SelectedFiles"/> + <valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/> + <value type="bool" key="ClangTools.UseGlobalSettings">true</value> + </valuemap> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.Target.0</variable> + <valuemap type="QVariantMap"> + <value type="QString" key="DeviceType">Desktop</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 6.4.0 MinGW 64-bit</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 6.4.0 MinGW 64-bit</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt6.640.win64_mingw_kit</value> + <value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> + <value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> + <value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> + <value type="int" key="EnableQmlDebugging">0</value> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:\Github2\avans-whether-station\build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Debug</value> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">D:/Github2/avans-whether-station/build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Debug</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + <valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1"> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:\Github2\avans-whether-station\build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Release</value> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">D:/Github2/avans-whether-station/build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Release</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + <valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="int" key="QtQuickCompiler">0</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2"> + <value type="int" key="EnableQmlDebugging">0</value> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:\Github2\avans-whether-station\build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Profile</value> + <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">D:/Github2/avans-whether-station/build-client-Desktop_Qt_6_4_0_MinGW_64_bit-Profile</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + <valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="int" key="QtQuickCompiler">0</value> + <value type="int" key="SeparateDebugInfo">0</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">3</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> + <valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/> + <value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> + <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value> + <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value> + <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value> + <valuelist type="QVariantList" key="CustomOutputParsers"/> + <value type="int" key="PE.EnvironmentAspect.Base">2</value> + <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value> + <value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value> + <value type="bool" key="RunConfiguration.UseCppDebugger">false</value> + <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value> + <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> + <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> + </valuemap> + <value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.TargetCount</variable> + <value type="qlonglong">1</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.FileVersion</variable> + <value type="int">22</value> + </data> + <data> + <variable>Version</variable> + <value type="int">22</value> + </data> +</qtcreator> diff --git a/client/dialog.cpp b/client/dialog.cpp new file mode 100644 index 0000000..58c3e72 --- /dev/null +++ b/client/dialog.cpp @@ -0,0 +1,14 @@ +#include "dialog.h" +#include "ui_dialog.h" + +Dialog::Dialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::Dialog) +{ + ui->setupUi(this); +} + +Dialog::~Dialog() +{ + delete ui; +} diff --git a/client/dialog.h b/client/dialog.h new file mode 100644 index 0000000..17537d1 --- /dev/null +++ b/client/dialog.h @@ -0,0 +1,22 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include <QDialog> + +namespace Ui { +class Dialog; +} + +class Dialog : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog(QWidget *parent = nullptr); + ~Dialog(); + +private: + Ui::Dialog *ui; +}; + +#endif // DIALOG_H diff --git a/client/dialog.ui b/client/dialog.ui new file mode 100644 index 0000000..9fbffd2 --- /dev/null +++ b/client/dialog.ui @@ -0,0 +1,18 @@ +<ui version="4.0"> + <class>Dialog</class> + <widget name="Dialog" class="QDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + </widget> + <resources/> + <connections/> +</ui> diff --git a/client/main.cpp b/client/main.cpp index 0a1c4e4..267248c 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -14,19 +14,12 @@ #include "mainwindow.h" #include "main.h" #include "ui_mainwindow.h" -#include "mytcpsocket.h" -#include "timetest.h" -#include "csv_import.h" -#include <QDebug> QSqlDatabase dbRef = QSqlDatabase(); int main(int argc, char *argv[]) { QApplication a(argc, argv); - TimeTest time; - MyTcpSocket s; - // s.doConnect(); MainWindow w; dbRef = QSqlDatabase::addDatabase("QMYSQL"); diff --git a/client/mainwindow.cpp b/client/mainwindow.cpp index e1736e6..49fcc26 100644 --- a/client/mainwindow.cpp +++ b/client/mainwindow.cpp @@ -11,6 +11,7 @@ MainWindow::MainWindow(QWidget *parent) , ui(new Ui::MainWindow) { ui->setupUi(this); + client.ClientEcho(); } MainWindow::~MainWindow() @@ -19,6 +20,11 @@ MainWindow::~MainWindow() delete ui; } +void MainWindow::timeFunction() +{ + client.timeFunction(); +} + void MainWindow::on_actionConnection_triggered() { _dbConenctor = new dbConnector(this); diff --git a/client/mainwindow.h b/client/mainwindow.h index 25e22ec..6bcc329 100644 --- a/client/mainwindow.h +++ b/client/mainwindow.h @@ -13,6 +13,7 @@ #include <QWidgetSet> #include "main.h" +#include "Client.h" QT_BEGIN_NAMESPACE @@ -33,7 +34,7 @@ private slots: // void on_actionAbout_triggered(); // void on_pushButton_clicked(); - + void timeFunction(); void on_actionConnection_triggered(); void on_actionRefresh_triggered(); @@ -42,7 +43,7 @@ private slots: private: Ui::MainWindow *ui; - + Client client; dbConnector *_dbConenctor; QChart *_pChart; diff --git a/client/mainwindow.ui b/client/mainwindow.ui index a31ffdc..bbcdf9c 100644 --- a/client/mainwindow.ui +++ b/client/mainwindow.ui @@ -17,8 +17,8 @@ <widget class="QLabel" name="label"> <property name="geometry"> <rect> - <x>270</x> - <y>190</y> + <x>260</x> + <y>240</y> <width>181</width> <height>51</height> </rect> @@ -34,7 +34,7 @@ <x>0</x> <y>0</y> <width>800</width> - <height>24</height> + <height>26</height> </rect> </property> <widget class="QMenu" name="menuAbouy"> diff --git a/client/mytcpsocket.cpp b/client/mytcpsocket.cpp deleted file mode 100644 index 92dd67a..0000000 --- a/client/mytcpsocket.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include <mytcpsocket.h> - -MyTcpSocket::MyTcpSocket(QObject *parent) : - QObject(parent) -{ -} - -void MyTcpSocket::doConnect() -{ - socket = new QTcpSocket(this); - - connect(socket, SIGNAL(connected()),this, SLOT(connected())); - connect(socket, SIGNAL(disconnected()),this, SLOT(disconnected())); - // connect(socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64))); - connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead())); - qDebug() << "connectig..."; - - socket->connectToHost("192.168.137.141",80); - - if(!socket->waitForConnected(5000)){ - qDebug()<<"Error: "<< socket->errorString(); - } -} - -void MyTcpSocket::connected(){ - qDebug() << "connected..."; - - socket->write("Weerdata: Temp:?\r\n\r\n\r\n\r\n"); - -} -void MyTcpSocket::disconnected(){ - qDebug() << "disconnected..."; - -} - -void MyTcpSocket::bytesWritten(qint64 bytes){ - qDebug() << bytes << "bytes written..."; - -} -void MyTcpSocket::readyRead(){ - qDebug() << "reading..."; - - qDebug() << socket->readAll(); -} diff --git a/client/mytcpsocket.h b/client/mytcpsocket.h deleted file mode 100644 index 4a7e543..0000000 --- a/client/mytcpsocket.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MYTCPSOCKET_H -#define MYTCPSOCKET_H - -#include <QObject> -#include <QTcpSocket> -#include <QAbstractSocket> -#include <QDebug> - -class MyTcpSocket : public QObject -{ - Q_OBJECT -public: - explicit MyTcpSocket(QObject *parent = 0); - - void doConnect(); -signals: -public slots: - void connected(); - void disconnected(); - void bytesWritten(qint64 bytes); - void readyRead(); -private: - QTcpSocket *socket; - - - - - -}; - - -#endif // MYTCPSOCKET_H diff --git a/client/settingsmenu.cpp b/client/settingsmenu.cpp new file mode 100644 index 0000000..139c616 --- /dev/null +++ b/client/settingsmenu.cpp @@ -0,0 +1,47 @@ +#include "settingsmenu.h" +//#include "ui_SettingsMenu.h" +#include "main.h" + +#include "mainwindow.h" + +SettingsMenu::SettingsMenu(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsMenu) +{ + _dbip = "localhost"; + ui->setupUi(this); +} + +SettingsMenu::~SettingsMenu() +{ + delete ui; +} + +void SettingsMenu::on_pushButton_cancel_clicked() +{ + SettingsMenu::~SettingsMenu(); +} + +void SettingsMenu::on_pushButton_login_clicked() +{ + _dbip = ui->lineEdit_adress->text(); + _dbName = ui->lineEdit_database->text(); + QString username = ui->lineEdit_username->text(); + QString password = ui->lineEdit_password->text(); + + dbRef.setHostName(_dbip); + dbRef.setUserName(username); + dbRef.setPassword(password); + dbRef.setDatabaseName(_dbName); + + if(dbRef.open()){ + QMessageBox::information(this, "Connection", "GREAT SUCCES!"); + SettingsMenu::~SettingsMenu(); + } else { + QMessageBox::warning(this, "No connection", "Failed to connect"); + } +} + + + + diff --git a/client/settingsmenu.h b/client/settingsmenu.h new file mode 100644 index 0000000..881906d --- /dev/null +++ b/client/settingsmenu.h @@ -0,0 +1,34 @@ +#pragma once + +#include <QDialog> + +#include <QMessageBox> +//#include <QtSql> +//#include <QSqlDatabase> + + +namespace Ui { +class SettingsMenu; +} + +class SettingsMenu : public QDialog +{ + Q_OBJECT + +public: + explicit SettingsMenu(QWidget *parent = nullptr); + ~SettingsMenu(); + +private slots: + + void on_pushButton_cancel_clicked(); + + void on_pushButton_login_clicked(); + +private: + Ui::SettingsMenu *ui; + + QString _dbName = ""; + QString _dbip = ""; + QString _ESPip = ""; +}; diff --git a/client/settingsmenu.ui b/client/settingsmenu.ui new file mode 100644 index 0000000..0de180f --- /dev/null +++ b/client/settingsmenu.ui @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SettingsMenu</class> + <widget class="QDialog" name="SettingsMenu"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>362</width> + <height>273</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QWidget" name="formLayoutWidget"> + <property name="geometry"> + <rect> + <x>60</x> + <y>60</y> + <width>241</width> + <height>173</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Adress</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_adress"> + <property name="text"> + <string>localhost</string> + </property> + <property name="placeholderText"> + <string>Hostname/IP-Adress</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Database</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEdit_database"> + <property name="text"> + <string>WSdb</string> + </property> + <property name="placeholderText"> + <string>Database name</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Username</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="lineEdit_username"> + <property name="text"> + <string>root</string> + </property> + <property name="echoMode"> + <enum>QLineEdit::PasswordEchoOnEdit</enum> + </property> + <property name="placeholderText"> + <string>Username</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Password</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="lineEdit_password"> + <property name="font"> + <font> + <underline>false</underline> + <strikeout>false</strikeout> + <kerning>true</kerning> + </font> + </property> + <property name="text"> + <string>Ab12345!</string> + </property> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + <property name="placeholderText"> + <string>Password</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="connectLabel"> + <property name="text"> + <string>Connect</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="pushButton_login"> + <property name="text"> + <string>Login</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_cancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/client/timetest.cpp b/client/timetest.cpp deleted file mode 100644 index 2e575f2..0000000 --- a/client/timetest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "timetest.h" - -TimeTest::TimeTest(QObject *parent) : QObject(parent) -{ - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()),this,SLOT(myfunction())); - timer->start(5000); -} - -qint16 TimeTest::myfunction() -{ - QTime time = QTime::currentTime(); - qint16 time_text = time.minute(); - - return time_text; - - -} diff --git a/client/timetest.h b/client/timetest.h deleted file mode 100644 index aa1d8a5..0000000 --- a/client/timetest.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TIMETEST_H -#define TIMETEST_H -#include <QTimer> -#include <QDebug> -#include <QObject> -#include <QDateTime> - -class TimeTest : public QObject -{ - Q_OBJECT -public: - explicit TimeTest(QObject *parent = 0); - -signals: -public slots: - qint16 myfunction(); - -private: - QTimer *timer; - - - - -}; - - -#endif // TIMETEST_H diff --git a/client/ui_dbconnector.h b/client/ui_dbconnector.h new file mode 100644 index 0000000..dec4d7b --- /dev/null +++ b/client/ui_dbconnector.h @@ -0,0 +1,163 @@ +/******************************************************************************** +** Form generated from reading UI file 'dbconnector.ui' +** +** Created by: Qt User Interface Compiler version 5.15.6 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_DBCONNECTOR_H +#define UI_DBCONNECTOR_H + +#include <QtCore/QVariant> +#include <QtWidgets/QApplication> +#include <QtWidgets/QDialog> +#include <QtWidgets/QFormLayout> +#include <QtWidgets/QFrame> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QLabel> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QWidget> + +QT_BEGIN_NAMESPACE + +class Ui_dbConnector +{ +public: + QWidget *formLayoutWidget; + QFormLayout *formLayout; + QLabel *label_3; + QLineEdit *lineEdit_adress; + QLabel *label_4; + QLineEdit *lineEdit_database; + QFrame *line; + QLabel *label; + QLineEdit *lineEdit_username; + QLabel *label_2; + QLineEdit *lineEdit_password; + QLabel *connectLabel; + QHBoxLayout *horizontalLayout; + QPushButton *pushButton_login; + QPushButton *pushButton_cancel; + + void setupUi(QDialog *dbConnector) + { + if (dbConnector->objectName().isEmpty()) + dbConnector->setObjectName(QString::fromUtf8("dbConnector")); + dbConnector->resize(362, 273); + formLayoutWidget = new QWidget(dbConnector); + formLayoutWidget->setObjectName(QString::fromUtf8("formLayoutWidget")); + formLayoutWidget->setGeometry(QRect(60, 60, 241, 173)); + formLayout = new QFormLayout(formLayoutWidget); + formLayout->setObjectName(QString::fromUtf8("formLayout")); + formLayout->setContentsMargins(0, 0, 0, 0); + label_3 = new QLabel(formLayoutWidget); + label_3->setObjectName(QString::fromUtf8("label_3")); + + formLayout->setWidget(0, QFormLayout::LabelRole, label_3); + + lineEdit_adress = new QLineEdit(formLayoutWidget); + lineEdit_adress->setObjectName(QString::fromUtf8("lineEdit_adress")); + + formLayout->setWidget(0, QFormLayout::FieldRole, lineEdit_adress); + + label_4 = new QLabel(formLayoutWidget); + label_4->setObjectName(QString::fromUtf8("label_4")); + + formLayout->setWidget(1, QFormLayout::LabelRole, label_4); + + lineEdit_database = new QLineEdit(formLayoutWidget); + lineEdit_database->setObjectName(QString::fromUtf8("lineEdit_database")); + + formLayout->setWidget(1, QFormLayout::FieldRole, lineEdit_database); + + line = new QFrame(formLayoutWidget); + line->setObjectName(QString::fromUtf8("line")); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + formLayout->setWidget(2, QFormLayout::SpanningRole, line); + + label = new QLabel(formLayoutWidget); + label->setObjectName(QString::fromUtf8("label")); + + formLayout->setWidget(3, QFormLayout::LabelRole, label); + + lineEdit_username = new QLineEdit(formLayoutWidget); + lineEdit_username->setObjectName(QString::fromUtf8("lineEdit_username")); + lineEdit_username->setEchoMode(QLineEdit::PasswordEchoOnEdit); + + formLayout->setWidget(3, QFormLayout::FieldRole, lineEdit_username); + + label_2 = new QLabel(formLayoutWidget); + label_2->setObjectName(QString::fromUtf8("label_2")); + + formLayout->setWidget(4, QFormLayout::LabelRole, label_2); + + lineEdit_password = new QLineEdit(formLayoutWidget); + lineEdit_password->setObjectName(QString::fromUtf8("lineEdit_password")); + QFont font; + font.setUnderline(false); + font.setStrikeOut(false); + font.setKerning(true); + lineEdit_password->setFont(font); + lineEdit_password->setEchoMode(QLineEdit::Password); + + formLayout->setWidget(4, QFormLayout::FieldRole, lineEdit_password); + + connectLabel = new QLabel(formLayoutWidget); + connectLabel->setObjectName(QString::fromUtf8("connectLabel")); + + formLayout->setWidget(5, QFormLayout::LabelRole, connectLabel); + + horizontalLayout = new QHBoxLayout(); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + pushButton_login = new QPushButton(formLayoutWidget); + pushButton_login->setObjectName(QString::fromUtf8("pushButton_login")); + + horizontalLayout->addWidget(pushButton_login); + + pushButton_cancel = new QPushButton(formLayoutWidget); + pushButton_cancel->setObjectName(QString::fromUtf8("pushButton_cancel")); + + horizontalLayout->addWidget(pushButton_cancel); + + + formLayout->setLayout(5, QFormLayout::FieldRole, horizontalLayout); + + + retranslateUi(dbConnector); + + QMetaObject::connectSlotsByName(dbConnector); + } // setupUi + + void retranslateUi(QDialog *dbConnector) + { + dbConnector->setWindowTitle(QCoreApplication::translate("dbConnector", "Dialog", nullptr)); + label_3->setText(QCoreApplication::translate("dbConnector", "Adress", nullptr)); + lineEdit_adress->setText(QCoreApplication::translate("dbConnector", "localhost", nullptr)); + lineEdit_adress->setPlaceholderText(QCoreApplication::translate("dbConnector", "Hostname/IP-Adress", nullptr)); + label_4->setText(QCoreApplication::translate("dbConnector", "Database", nullptr)); + lineEdit_database->setText(QCoreApplication::translate("dbConnector", "WSdb", nullptr)); + lineEdit_database->setPlaceholderText(QCoreApplication::translate("dbConnector", "Database name", nullptr)); + label->setText(QCoreApplication::translate("dbConnector", "Username", nullptr)); + lineEdit_username->setText(QCoreApplication::translate("dbConnector", "root", nullptr)); + lineEdit_username->setPlaceholderText(QCoreApplication::translate("dbConnector", "Username", nullptr)); + label_2->setText(QCoreApplication::translate("dbConnector", "Password", nullptr)); + lineEdit_password->setText(QCoreApplication::translate("dbConnector", "Ab12345!", nullptr)); + lineEdit_password->setPlaceholderText(QCoreApplication::translate("dbConnector", "Password", nullptr)); + connectLabel->setText(QCoreApplication::translate("dbConnector", "Connect", nullptr)); + pushButton_login->setText(QCoreApplication::translate("dbConnector", "Login", nullptr)); + pushButton_cancel->setText(QCoreApplication::translate("dbConnector", "Cancel", nullptr)); + } // retranslateUi + +}; + +namespace Ui { + class dbConnector: public Ui_dbConnector {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_DBCONNECTOR_H diff --git a/client/ui_mainwindow.h b/client/ui_mainwindow.h new file mode 100644 index 0000000..69c476b --- /dev/null +++ b/client/ui_mainwindow.h @@ -0,0 +1,110 @@ +/******************************************************************************** +** Form generated from reading UI file 'mainwindow.ui' +** +** Created by: Qt User Interface Compiler version 5.15.6 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_MAINWINDOW_H +#define UI_MAINWINDOW_H + +#include <QtCore/QVariant> +// #include <QtWidgets/QAction> +#include <QtWidgets/QApplication> +#include <QtWidgets/QLabel> +#include <QtWidgets/QMainWindow> +#include <QtWidgets/QMenu> +#include <QtWidgets/QMenuBar> +#include <QtWidgets/QStatusBar> +#include <QtWidgets/QWidget> + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QAction *actionRefresh; + QAction *actionLOAD; + QAction *actionQuerry; + QAction *actionConnection; + QAction *actionDisconnenct; + QWidget *centralwidget; + QLabel *label; + QMenuBar *menubar; + QMenu *menuAbouy; + QMenu *menuDatabase; + QStatusBar *statusbar; + + void setupUi(QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->resize(800, 600); + actionRefresh = new QAction(MainWindow); + actionRefresh->setObjectName(QString::fromUtf8("actionRefresh")); + actionLOAD = new QAction(MainWindow); + actionLOAD->setObjectName(QString::fromUtf8("actionLOAD")); + actionQuerry = new QAction(MainWindow); + actionQuerry->setObjectName(QString::fromUtf8("actionQuerry")); + actionConnection = new QAction(MainWindow); + actionConnection->setObjectName(QString::fromUtf8("actionConnection")); + actionDisconnenct = new QAction(MainWindow); + actionDisconnenct->setObjectName(QString::fromUtf8("actionDisconnenct")); + centralwidget = new QWidget(MainWindow); + centralwidget->setObjectName(QString::fromUtf8("centralwidget")); + label = new QLabel(centralwidget); + label->setObjectName(QString::fromUtf8("label")); + label->setGeometry(QRect(270, 190, 181, 51)); + MainWindow->setCentralWidget(centralwidget); + menubar = new QMenuBar(MainWindow); + menubar->setObjectName(QString::fromUtf8("menubar")); + menubar->setGeometry(QRect(0, 0, 800, 24)); + menuAbouy = new QMenu(menubar); + menuAbouy->setObjectName(QString::fromUtf8("menuAbouy")); + menuDatabase = new QMenu(menubar); + menuDatabase->setObjectName(QString::fromUtf8("menuDatabase")); + MainWindow->setMenuBar(menubar); + statusbar = new QStatusBar(MainWindow); + statusbar->setObjectName(QString::fromUtf8("statusbar")); + MainWindow->setStatusBar(statusbar); + + menubar->addAction(menuAbouy->menuAction()); + menubar->addAction(menuDatabase->menuAction()); + menuAbouy->addAction(actionRefresh); + menuDatabase->addAction(actionConnection); + menuDatabase->addAction(actionDisconnenct); + + retranslateUi(MainWindow); + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr)); + actionRefresh->setText(QCoreApplication::translate("MainWindow", "Refresh", nullptr)); +#if QT_CONFIG(shortcut) + actionRefresh->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+R", nullptr)); +#endif // QT_CONFIG(shortcut) + actionLOAD->setText(QCoreApplication::translate("MainWindow", "Load", nullptr)); + actionQuerry->setText(QCoreApplication::translate("MainWindow", "Query", nullptr)); + actionConnection->setText(QCoreApplication::translate("MainWindow", "Connect", nullptr)); +#if QT_CONFIG(shortcut) + actionConnection->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+O", nullptr)); +#endif // QT_CONFIG(shortcut) + actionDisconnenct->setText(QCoreApplication::translate("MainWindow", "Disconnenct", nullptr)); + label->setText(QCoreApplication::translate("MainWindow", "Please load data first", nullptr)); + menuAbouy->setTitle(QCoreApplication::translate("MainWindow", "Home", nullptr)); + menuDatabase->setTitle(QCoreApplication::translate("MainWindow", "Database", nullptr)); + } // retranslateUi + +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAINWINDOW_H @@ -6,8 +6,10 @@ `client/client.pro` should be tracked under version control, not `client/makefile` - the stm32 makefile uses git submodules to pull necessary files for - compilation. make sure to initialize and sync the git submodules, or re-clone - using the `--recursive` flag. + compilation. make sure to initialize and sync the git submodules, or use the + `--recursive` flag when cloning +- the stm32 firmware expects the esp8266 module to have the official espressif + firmware, not the ai-thinker firmware that the module comes pre-flashed with ## support diff --git a/scripts/compiledb-full-path-mingw.sh b/scripts/compiledb-full-path-mingw.sh index 8f95756..be45ca7 100755 --- a/scripts/compiledb-full-path-mingw.sh +++ b/scripts/compiledb-full-path-mingw.sh @@ -10,4 +10,4 @@ fixpath () { fixpath arm-none-eabi-gcc fixpath arm-none-eabi-objcopy -sed "s#\"/c/#\"C:/#g" -i "$COMPILEDB_FILE" +sed 's#"/\(.\)/#"\U\1:/#g' -i "$COMPILEDB_FILE"
\ No newline at end of file diff --git a/scripts/db-init.sql b/scripts/db-init.sql index 4c4c4d4..2b0581c 100644 --- a/scripts/db-init.sql +++ b/scripts/db-init.sql @@ -1,9 +1,11 @@ -CREATE SCHEMA `WSdb`; -CREATE TABLE `DAB1Pract1`.`tblMain` ( - `ID` INT GENERATED ALWAYS AS (), - `temperature` DECIMAL(5,2) NULL, - `humidity` DECIMAL(5,2) NULL, - `pressure` DECIMAL(5,2) NULL, - `time` DATETIME NULL, - PRIMARY KEY (`ID`), - UNIQUE INDEX `ID_UNIQUE` (`ID` ASC) VISIBLE); +drop schema if exists `WSdb`; +create schema if not exists `WSdb`; +drop table if exists `WSdb`.`tblMain`; +create table if not exists `WSdb`.`tblMain` ( + id int unsigned not null auto_increment, + temperature decimal(5,2) null, + humidity decimal(5,2) null, + pressure decimal(5,2) null, + time datetime null, + primary key (id) +); diff --git a/scripts/db-privileges.sql b/scripts/db-privileges.sql new file mode 100644 index 0000000..75f8fcc --- /dev/null +++ b/scripts/db-privileges.sql @@ -0,0 +1 @@ +grant all privileges on WSdb.* to 'user'@'localhost'; diff --git a/scripts/dummy-server.py b/scripts/dummy-server.py new file mode 100755 index 0000000..9350cab --- /dev/null +++ b/scripts/dummy-server.py @@ -0,0 +1,48 @@ +#!/bin/python3 + +""" +this is a garbage python script that opens a tcp socket on localhost:33 for +connecting with the qt client +""" + +import socketserver +from random import randint + +def hexpad(n, pad): + return hex(n)[2:].zfill(pad) + +def bs(str): + return bytes(str, 'utf-8') + +def r(max): + return randint(0, max) + +class DummyServer(socketserver.BaseRequestHandler): + def error(self): + self.request.sendall(bs("error\n")) + + def ok(self, rows): + response = "id,temperature,humidity,atmospheric_pressure\n" + line_len = len("xxxx,xx,xx,xx\n") + retstr = f"ok,{hex(len(response) + rows * line_len)[2:]}\n" + retstr += response + for row in range(rows): + retstr += f"{hexpad(row, 4)},{hexpad(r(0xff), 2)},{hexpad(r(0xff), 2)},{hexpad(r(0xff), 2)}\n" + self.request.sendall(bs(retstr)) + + def handle(self): + self.data = self.request.recv(1024).strip() + if len(self.data) > 40: return self.error() + if not self.data.startswith(bs('last-records')): return self.error() + self.data = self.data.replace(bs('last-records'), bs('')) + try: + self.ok(int(self.data)) + except ValueError: + self.error() + +if __name__ == "__main__": + socketserver.TCPServer.allow_reuse_address = True + with socketserver.TCPServer(("localhost", 33), DummyServer) as server: + server.serve_forever() + + diff --git a/shared/bin.c b/shared/bin.c new file mode 100644 index 0000000..def2aa8 --- /dev/null +++ b/shared/bin.c @@ -0,0 +1,11 @@ +#include <stdlib.h> +#include <stdint.h> +#include <memory.h> + +#include "bin.h" + +ws_s_bin *ws_bin_s_alloc(uint16_t bytes) { + ws_s_bin *temp = malloc(sizeof(ws_s_bin) + sizeof(uint8_t) * bytes); + temp->bytes = bytes; + return temp; +} diff --git a/shared/bin.h b/shared/bin.h new file mode 100644 index 0000000..bfcda0c --- /dev/null +++ b/shared/bin.h @@ -0,0 +1,13 @@ +#pragma once + +#include <stdint.h> + +/** @brief binary data container with length */ +typedef struct { + uint16_t bytes; + uint8_t data[]; +} ws_s_bin; + +/** @brief allocate new ws_s_bin struct */ +ws_s_bin *ws_bin_s_alloc(uint16_t bytes); + diff --git a/shared/protocol.c b/shared/protocol.c new file mode 100644 index 0000000..8887070 --- /dev/null +++ b/shared/protocol.c @@ -0,0 +1,147 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "protocol.h" +#include "util.h" + +#define WS_CMD_MAP(parsed_cmd, name, code) \ + if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; + +static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_cmd* parsed_cmd) { + if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command + WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); + + return WS_PROTOCOL_CMD_UNKNOWN; +} + +void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input) { + switch(input) { + case WS_PROTOCOL_C_EOL: { + break; + } + + case WS_PROTOCOL_C_SPACE: { + if (!state->valid) return; + state->arg_len++; + return; + } + + case WS_PROTOCOL_C_NULL: { + state->valid = false; + return; + } + + default: { + if (!state->valid) return; + state->cmd[state->cmd_len++] = input; + state->args_len[state->arg_len] += 1; + if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; + return; + } + } + // arg_len is used as an index while parsing, so add 1 to get length + state->arg_len++; + + // parse cmd into argc and argv + if (state->valid) ws_protocol_req_cmd_init(state); + // create response + ws_s_protocol_res* response = ws_protocol_parse_req_finished(state->target); + + // send response + char response_first_line[16]; + sprintf(response_first_line, "%s,%x\n", response->success == WS_PROTOCOL_CMD_RETURN_OK ? "ok" : "error", response->msg->bytes); + ws_protocol_send_data(response_first_line, strlen(response_first_line)); + if (!response->csh) ws_protocol_send_data((char*) response->msg->data, response->msg->bytes); + else (*g_ws_protocol_res_handlers[response->cmd_code])(state->target, response, true); + + // free response data containers + free(response->msg); + free(response); + + // reset parser + ws_protocol_req_parser_reset(state); + + return; +} + +ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd) { + ws_s_protocol_res* response = malloc(sizeof(ws_s_protocol_res)); + response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + response->csh = false; + response->msg = NULL; + response->cmd_code = ws_protocol_get_req_cmd_code(parsed_cmd); + + if (response->cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit; + if (response->cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit; + + ws_protocol_res_handler_t* ws_protocol_res_handler = g_ws_protocol_res_handlers[response->cmd_code]; + if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit; + (*ws_protocol_res_handler)(parsed_cmd, response, false); + +ws_protocol_parse_exit: + + if (response->msg == NULL) response->msg = ws_bin_s_alloc(0); + return response; +} + +void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length) { + for (unsigned int i = 0; i < length; i++) ws_protocol_parse_req_byte(state, input[i]); +} + +ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { + ws_s_protocol_req_parser_state* parser_state = malloc(sizeof(ws_s_protocol_req_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); + parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); + parser_state->target = NULL; + ws_protocol_req_parser_reset(parser_state); + return parser_state; +} + +void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { + state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); + unsigned int args = WS_MIN(state->arg_len, WS_PROTOCOL_CMD_MAX_ARGUMENTS); + for (unsigned int i = 0; i < args; i++) + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); + + state->target->argc = args; + + unsigned int head = 0; + for (unsigned int i = 0; i < state->arg_len; i++) { + strncpy(state->target->argv[i], &state->cmd[head], state->args_len[i]); + state->target->argv[i][state->args_len[i]] = 0x00; // terminate argument with null byte + head += state->args_len[i]; + } +} + +void ws_protocol_req_parser_free(ws_s_protocol_req_parser_state* state) { + if (state == NULL) return; + if (state->target != NULL) ws_protocol_req_cmd_free(state->target); + state->target = NULL; + free(state->cmd); + free(state); + return; +} + +void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state) { + if (state->target != NULL) ws_protocol_req_cmd_free(state->target); + state->target = NULL; + state->valid = true; + state->cmd_len = 0; + state->arg_len = 0; + memset(state->args_len, 0, sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); +} + +void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd) { + for (int i = 0; i < cmd->argc; i++) + free(cmd->argv[i]); + free(cmd); + return; +} + +unsigned short ws_protocol_get_header_size(ws_s_protocol_res* response) { + unsigned short size = 2; // comma and trailing newline + if (response->success == WS_PROTOCOL_CMD_RETURN_OK) size += 2; // ok + if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) size += 5; // error + size += ws_log16(response->msg->bytes) + 1; // amount of characters for message size (hex) + return size; +}
\ No newline at end of file diff --git a/shared/protocol.h b/shared/protocol.h new file mode 100644 index 0000000..96c039a --- /dev/null +++ b/shared/protocol.h @@ -0,0 +1,151 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include "bin.h" + +#define WS_PROTOCOL_CMD_MAX_ARGUMENTS (3) +#define WS_PROTOCOL_CMD_BUFFER_LEN (40) + +#define WS_PROTOCOL_CMD_AMOUNT (1) + +#define WS_PROTOCOL_C_EOL (0x0a) +#define WS_PROTOCOL_C_SPACE (0x20) +#define WS_PROTOCOL_C_NULL (0x00) + +/** + * @brief parsed request cmd struct, holds arguments similar to argc and argv + * provided to `int main()` + */ +typedef struct { + int argc; /** argument count */ + char* argv[]; /** argument array, null terminated strings */ +} ws_s_protocol_parsed_req_cmd; + +/** + * @brief holds parser state variables for `ws_protocol_parse_req_byte` function. + * each incoming tcp request should get it's own parser 'instance' + */ +typedef struct { + ws_s_protocol_parsed_req_cmd* target; /** parsed cmd reference */ + bool valid; /** command still valid flag */ + char* cmd; /** raw cmd */ + uint16_t cmd_len; /** raw cmd string length */ + uint16_t arg_len; /** amount of arguments */ + uint16_t args_len[]; /** array of argument lengths */ +} ws_s_protocol_req_parser_state; + +/** @brief return values for command handlers */ +typedef enum { + WS_PROTOCOL_CMD_RETURN_OK = 0, + WS_PROTOCOL_CMD_RETURN_ERROR = 1, +} ws_e_protocol_cmd_return_value; + +/** @brief cmd codes (used to call handlers) */ +typedef enum { + WS_PROTOCOL_CMD_UNKNOWN = -1, + + WS_PROTOCOL_CMD_LAST_RECORDS = 0, +} ws_e_protocol_cmd; + +/** @brief request response data struct */ +typedef struct { + ws_e_protocol_cmd_return_value success; /** status code for response + validity, defaults to + WS_PROTOCOL_CMD_RETURN_ERROR */ + bool csh; /** whether the response handler has logic for a custom send + handler, false by default */ + ws_s_bin* msg; /** pointer to response data, uninitialized by default */ + ws_e_protocol_cmd cmd_code; /** cmd code */ +} ws_s_protocol_res; + +/** + * @brief allocate parser struct + * + * @return pointer to newly allocated struct + */ +ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc(); +/** @brief deallocate parser struct, automatically frees all child pointers */ +void ws_protocol_req_parser_free(ws_s_protocol_req_parser_state* state); +/** @brief reset parser state to parse a new request */ +void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state); +/** + * @brief initialize ws_s_protocol_parsed_req_cmd struct pointer of + * ws_s_protocol_req_parser_state (internal only) + */ +void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state); +/** @brief deallocate ws_s_protocol_parsed_req_cmd struct pointer (internal only) */ +void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd); + +/** + * @brief parse incoming data byte by byte until a finished command is detected + * + * @param state parser state object, each incoming request should have it's own parser state + * @param input input byte + */ +void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input); +/** + * @brief parse incoming data chunk + * + * @param state parser state object, each incoming request should have it's own parser state + * @param input input byte array + * @param length input byte array length + */ +void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length); +/** + * @brief handle complete command + * + * this function gets called when ws_protocol_parse_req_byte(s) has detected a + * finished command. this function decides which command handler gets called, + * given that argv[0] contains a valid command. command argument parsing is + * handled by the command handler function. + * + * @return response + * + * @param parsed_cmd cmd parsed into ws_s_protocol_parsed_req_cmd struct + */ +ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd); + +/** + * @brief create a `last-records` request command + * @return ws_s_bin containing the command string + */ +ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); + +/** + * @brief response handler + * + * gets fired when the weather station receives a complete command, and returns + * a response struct with a success code and an optional message. if + * response->csh is set to `true` within the handler, it gets fired a second + * time after the response header is sent, but with the `send` parameter set to + * `true`. this is so response handlers can send large amounts of data without + * allocating large areas of memory. + * + * @param parsed_cmd complete parsed command from ws_protocol_parse_req_* + * @param response response struct with uninitialized pointer to msg + * @param send `false` on first run, `true` on second run if `response->csh` was set to true + */ +typedef void ws_protocol_res_handler_t(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*, bool); + +ws_protocol_res_handler_t ws_protocol_res_last_records; + +/** + * @brief data sender wrapper + * + * this function should be implemented in the source files of each target + * platform, as the send interface will be different on desktop and on the + * stm32. + * + * @param data pointer to data char array + * @param length length of data array + */ +void ws_protocol_send_data(const char* data, unsigned int length); + +/** @brief response handlers, called when a command is parsed */ +static ws_protocol_res_handler_t* g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT] = { + [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records, +}; + +unsigned short ws_protocol_get_header_size(ws_s_protocol_res* response); diff --git a/shared/protocol.md b/shared/protocol.md new file mode 100644 index 0000000..1e52e42 --- /dev/null +++ b/shared/protocol.md @@ -0,0 +1,57 @@ +# Protocol spec + +This is a brief overview of the protocol specifications that the weather +station uses to send and receive data between the weather station and qt +client. This protocol is text-based, and used over a TCP connection. This +document will only go into detail about the data sent over this connection, not +requirements about the connection itself. + +The protocol is only used in a request-response fashion, so all commands are +assumed to be sent by the qt client, and responded to by the weather station. + +~Functions for generating commands and parsing incoming data are provided by +the protocol.c and protocol.h files in this folder.~ A server using these files +should implement every protocol handler function in a seperate c file, along +with a data sending function that is also used internally. + +- LF for newline instead of CRLF +- Commands are single-line +- Spaces used for separating command arguments +- Commands with malformed data are discarded and return error +- Response consist of `ok` or `error`, a comma, and the byte length of the + remaining response (if any) +- Numbers are sent as hexadecimal + +## Commands + +### `last-records <n> <o>` + +Returns the last `n` records with offset `<o>` in csv format. The first line +has the csv table header, with the fields `id`, `temperature`, `humidity`, and +`atmospheric_pressure`. The rest of the response consists of 1 record per line. +The amount of records is limited to the amount of valid records in the backlog +buffer. When the amount of returned records is 0, the response consists of the +csv header, but without any following records. + +Offset `<o>` is a positive integer, representing the starting point for the +most recent record that is returned, this will get subtracted from the id of +the most recent record. E.g. if the last record has id `00f0`, and a request is +sent with parameters `n=3` and `o=5`, the records with id's `00eb`, `00ea`, and +`00e9` will be returned. + +## Example transaction + +In the following example, newlines are indicated by `<0a>`, request by lines +starting with `<`, and response by lines starting with `>`. + +``` +< last-records 5 0<0a> +> ok,73<0a> +> id,temperature,humidity,atmospheric_pressure<0a> +> 10dc,2f,c5,7f<0a> +> 10dd,30,c6,7f<0a> +> 10de,31,c7,7f<0a> +> 10df,35,ca,7e<0a> +> 10e0,34,c9,7e<0a> +``` + diff --git a/shared/shared.mk b/shared/shared.mk new file mode 100644 index 0000000..f9586ff --- /dev/null +++ b/shared/shared.mk @@ -0,0 +1 @@ +OBJS += $(patsubst %.c,%-stm.o, $(wildcard ../shared/*.c)) diff --git a/shared/util.c b/shared/util.c new file mode 100644 index 0000000..ea972b0 --- /dev/null +++ b/shared/util.c @@ -0,0 +1,7 @@ +#include "util.h" + +unsigned int ws_log16(unsigned int x) { + unsigned int l = 0; + while (x >>= 4) ++l; // bitshift right by 4 until x == 0 + return l; +}
\ No newline at end of file diff --git a/shared/util.h b/shared/util.h new file mode 100644 index 0000000..94a3dfe --- /dev/null +++ b/shared/util.h @@ -0,0 +1,6 @@ +#pragma once + +#define WS_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define WS_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +unsigned int ws_log16(unsigned int x); diff --git a/stm32f091/backlog.c b/stm32f091/backlog.c index 3f21924..662fc75 100644 --- a/stm32f091/backlog.c +++ b/stm32f091/backlog.c @@ -2,33 +2,41 @@ #include "backlog.h" -ws_s_backlog_database* WS_G_BACKLOG_DATABASE = NULL; +ws_s_backlog_database* g_ws_backlog_database = NULL; void ws_backlog_alloc(uint16_t record_amt) { - WS_G_BACKLOG_DATABASE = malloc(sizeof(ws_s_backlog_database) + sizeof(ws_s_backlog_record) * record_amt); - WS_G_BACKLOG_DATABASE->buffer_size = record_amt; - WS_G_BACKLOG_DATABASE->buffer_start = 0; - WS_G_BACKLOG_DATABASE->buffer_end = 0; + g_ws_backlog_database = malloc(sizeof(ws_s_backlog_database) + sizeof(ws_s_backlog_record) * record_amt); + g_ws_backlog_database->buffer_size = record_amt; + g_ws_backlog_database->buffer_start = 0; + g_ws_backlog_database->buffer_end = 0; } void ws_backlog_add_record(ws_s_backlog_record record) { static uint16_t id = 0; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].id = id++; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_atm_pressure = record.sens_atm_pressure; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_humidity = record.sens_humidity; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_temperature = record.sens_temperature; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].id = id++; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_atm_pressure = record.sens_atm_pressure; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_humidity = record.sens_humidity; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_temperature = record.sens_temperature; // shift buffer start/end - WS_G_BACKLOG_DATABASE->buffer_end = (WS_G_BACKLOG_DATABASE->buffer_end + 1) % WS_G_BACKLOG_DATABASE->buffer_size; - if (WS_G_BACKLOG_DATABASE->buffer_end == WS_G_BACKLOG_DATABASE->buffer_start) - WS_G_BACKLOG_DATABASE->buffer_start = (WS_G_BACKLOG_DATABASE->buffer_start + 1) % WS_G_BACKLOG_DATABASE->buffer_size; + g_ws_backlog_database->buffer_end = (g_ws_backlog_database->buffer_end + 1) % g_ws_backlog_database->buffer_size; + if (g_ws_backlog_database->buffer_end == g_ws_backlog_database->buffer_start) + g_ws_backlog_database->buffer_start = (g_ws_backlog_database->buffer_start + 1) % g_ws_backlog_database->buffer_size; } ws_s_backlog_record* ws_backlog_get_record(uint16_t record_index) { - return &WS_G_BACKLOG_DATABASE->records[record_index]; + return &g_ws_backlog_database->records[record_index]; } ws_s_backlog_record* ws_backlog_get_last_record(uint16_t record_offset) { - return ws_backlog_get_record((WS_G_BACKLOG_DATABASE->buffer_end - record_offset - 1) % WS_G_BACKLOG_DATABASE->buffer_size); + return ws_backlog_get_record((g_ws_backlog_database->buffer_end - record_offset - 1) % g_ws_backlog_database->buffer_size); +} + +uint16_t ws_backlog_get_record_count() { + // add buffer_size to the result of the modulo operation if it's result is negative + // (only works when buffer_size is less than 2^15) + // this is a consequence of the way in which c handles negative numbers in modulo operations + int16_t mod = (g_ws_backlog_database->buffer_end - g_ws_backlog_database->buffer_start) % g_ws_backlog_database->buffer_size; + return mod < 0 ? mod + g_ws_backlog_database->buffer_size : mod; } diff --git a/stm32f091/backlog.h b/stm32f091/backlog.h index 465b3c0..c8ea019 100644 --- a/stm32f091/backlog.h +++ b/stm32f091/backlog.h @@ -30,7 +30,7 @@ typedef struct { #pragma pack(pop) /** @brief global record backlog database pointer */ -extern ws_s_backlog_database* WS_G_BACKLOG_DATABASE; +extern ws_s_backlog_database* g_ws_backlog_database; /** * @brief add record to database @@ -55,3 +55,5 @@ ws_s_backlog_record* ws_backlog_get_record(uint16_t record_index); /** @brief get pointer to last record with offset `record_offset` from the database */ ws_s_backlog_record* ws_backlog_get_last_record(uint16_t record_offset); +/** @brief return amount of valid records in database */ +uint16_t ws_backlog_get_record_count(); diff --git a/stm32f091/consts.h b/stm32f091/consts.h new file mode 100644 index 0000000..3d2ef5a --- /dev/null +++ b/stm32f091/consts.h @@ -0,0 +1,27 @@ +#pragma once + +#include "wifi.h" + +#define WS_SERVER_PORT "80" +#define WS_SERVER_MAX_CHANNELS 4 + +#define WS_DMA_RX_BUFFER_SIZE 100 +#define WS_DMA_TX_BUFFER_SIZE 1024 + +#define WS_PINOUT_I2C_SDA_PIN GPIO_PIN_9 +#define WS_PINOUT_I2C_SDA_PORT GPIOB +#define WS_PINOUT_I2C_SCL_PIN GPIO_PIN_8 +#define WS_PINOUT_I2C_SCL_PORT GPIOB + +#define WS_PINOUT_USART1_RX_PIN GPIO_PIN_10 +#define WS_PINOUT_USART1_RX_PORT GPIOA +#define WS_PINOUT_USART1_TX_PIN GPIO_PIN_9 +#define WS_PINOUT_USART1_TX_PORT GPIOA + +#define WS_PINOUT_USART2_RX_PIN GPIO_PIN_3 +#define WS_PINOUT_USART2_RX_PORT GPIOA +#define WS_PINOUT_USART2_TX_PIN GPIO_PIN_2 +#define WS_PINOUT_USART2_TX_PORT GPIOA + +// print esp communication over usb serial (green for tx, red for rx) +#define WS_DBG_PRINT_ESP_OVER_USART2 diff --git a/stm32f091/esp8266.c b/stm32f091/esp8266.c index 6f12191..74ec347 100644 --- a/stm32f091/esp8266.c +++ b/stm32f091/esp8266.c @@ -2,208 +2,88 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stm32f0xx.h> #include "esp8266.h" #include "setup.h" - -void ws_esp8266_ATsendCommand(uint8_t* data){ - char dataChar[20]; - uint8_t Tx_send[]="AT+CIPSEND=0,"; - - itoa(strlen((char*)data),dataChar,10); - strcat((char*)Tx_send,dataChar); - strcat((char*)Tx_send,"\r\n"); - HAL_UART_Transmit(&huart1, Tx_send, strlen((char*)Tx_send),1000); - HAL_Delay(2000); - HAL_UART_Transmit(&huart1, data, strlen((char*)data),1000); - HAL_Delay(1000); - HAL_UART_Transmit(&huart2, data, strlen((char*)data),1000); - HAL_Delay(5000); -} -int ws_esp8266_checkOK(uint8_t *receiveData,int length){ - char *ret=""; - char *ret1=""; - HAL_UART_Transmit(&huart2, receiveData,length,1000); - ret = strstr((char*)receiveData,"OK"); - // ret = strstr((char*)receiveData,"change"); - // memset(receiveData,0,30); - if((ret[0]='O') && (ret[1]=='K')){ - //HAL_UART_Transmit(&huart2, (uint8_t*)ret, sizeof(ret), 100); - return 1; - - } -// else if((ret1[0]='c') && (ret1[1]=='h')){ -// //HAL_UART_Transmit(&huart2, (uint8_t*)ret, sizeof(ret), 100); -// return 1; -// -// } - else{ - return 0; - } - +#include "consts.h" +#include "server.h" +#include "util.h" + +// macro for concise sending of multiple commands +#define ws_esp8266_send_seq(cmd) { \ + uint8_t _cmd[] = cmd; \ + ws_server_send(_cmd, sizeof(_cmd)); \ } -int ws_esp8266_receivingMsg(uint8_t *receiveData,int length){ - char *ret=""; - HAL_UART_Transmit(&huart2, receiveData,length,1000); - ret = strstr((char*)receiveData,"+IPD"); - // memset(receiveData,0,30); - if((ret[0]='+') && (ret[1]=='I')){ - //HAL_UART_Transmit(&huart2, (uint8_t*)ret, sizeof(ret), 100); - return 1; - } - else{ - return 0; - } +uint8_t g_ws_esp8266_dma_rx_buffer[WS_DMA_RX_BUFFER_SIZE]; +unsigned int g_ws_esp8266_dma_rx_head = 0; +unsigned int g_ws_esp8266_dma_rx_tail = 0; +uint8_t g_ws_esp8266_dma_tx_buffer[WS_DMA_TX_BUFFER_SIZE]; -} -int ws_esp8266_unlink(uint8_t *receiveData,int length){ - char *ret=""; - HAL_UART_Transmit(&huart2, receiveData,length,1000); - ret = strstr((char*)receiveData,"UNLINK"); - // memset(receiveData,0,30); - if((ret[0]='U') && (ret[1]=='N')){ - //HAL_UART_Transmit(&huart2, (uint8_t*)ret, sizeof(ret), 100); - return 1; - - } - else{ - return 0; - } +void DMA1_Ch1_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_usart1_rx); } +void DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_usart1_tx); } +void USART1_IRQHandler(void) { + if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) { + __HAL_UART_CLEAR_IDLEFLAG(&huart1); + // https://stackoverflow.com/questions/71039052/hal-uartex-rxeventcallback-circular-dma-what-address-is-the-data + g_ws_esp8266_dma_rx_head = huart1.RxXferSize - huart1.hdmarx->Instance->CNDTR; + ws_esp8266_incoming_data_chunk(); + } + HAL_UART_IRQHandler(&huart1); } -void ws_esp8266_StartEsp(){ - - uint8_t Tx_AT[]="AT\r\n"; - uint8_t Rx_buffer[10]={0}; - for(int i=0;i<3;i++){ - // HAL_UART_Transmit(&huart2, hier,sizeof(hier),100); - HAL_UART_Transmit_IT(&huart1, Tx_AT,strlen((char*)Tx_AT)); - HAL_UART_Receive_IT(&huart1, Rx_buffer, 10); - - - HAL_UART_Transmit(&huart2, Rx_buffer,10,100); - HAL_Delay(5000); - //memset(Rx_buffer,0,sizeof(Rx_buffer)); +void ws_esp8266_incoming_data_chunk() { + if (g_ws_esp8266_dma_rx_head == g_ws_esp8266_dma_rx_tail) return; // no new data + if (g_ws_esp8266_dma_rx_head > g_ws_esp8266_dma_rx_tail) { + // read from tail until head + ws_server_req_incoming(&g_ws_esp8266_dma_rx_buffer[g_ws_esp8266_dma_rx_tail], + g_ws_esp8266_dma_rx_head - g_ws_esp8266_dma_rx_tail); + } else /* if (g_ws_esp8266_dma_rx_head < g_ws_esp8266_dma_rx_tail) */ { + // read from tail until end of buffer + ws_server_req_incoming(&g_ws_esp8266_dma_rx_buffer[g_ws_esp8266_dma_rx_tail], + WS_DMA_RX_BUFFER_SIZE - g_ws_esp8266_dma_rx_tail); + // read from buffer begin until head + ws_server_req_incoming(&g_ws_esp8266_dma_rx_buffer[0], // yes i know this looks dumb + g_ws_esp8266_dma_rx_head); } - + // finish read by shifting tail forward + g_ws_esp8266_dma_rx_tail = g_ws_esp8266_dma_rx_head; } -void ws_esp8266_disconnect(){ - int ret; - uint8_t Tx_disconnect[]="AT+CWQAP\r\n";uint8_t buffer[17]={0}; - while(ret!=1){ - - HAL_UART_Transmit_IT(&huart1, Tx_disconnect,strlen((char*)Tx_disconnect)); - HAL_UART_Receive_IT(&huart1, buffer, 17); - HAL_Delay(2000); - if(ws_esp8266_checkOK(buffer,17)==1){ - ret=1; - } +void ws_esp8266_send(uint8_t* data, size_t size) { + size_t limited_size = WS_MIN(size, WS_DMA_TX_BUFFER_SIZE - 1); + memcpy(g_ws_esp8266_dma_tx_buffer, data, limited_size); + g_ws_esp8266_dma_tx_buffer[limited_size] = 0x00; - } +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX); + HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer), 100); +#endif - HAL_Delay(5000); + HAL_UART_Transmit_DMA(&huart1, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer)); + __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); } -void ws_esp8266_mode(){ - int ret; - uint8_t buffer1[20]={0}; uint8_t Tx_mode[]="AT+CWMODE=1\r\n"; - - while(ret!=1){ - - HAL_UART_Transmit_IT(&huart1, Tx_mode,strlen((char*)Tx_mode)); - HAL_UART_Receive_IT(&huart1, buffer1, 20); - HAL_Delay(1000); - - if(ws_esp8266_checkOK(buffer1,20)==1){ - ret=1; - - } - } - - HAL_Delay(1000); +void ws_esp8266_connect() { + ws_esp8266_send_seq("AT+CWJAP=\"" WS_ESP8266_WLAN_SSID "\",\"" WS_ESP8266_WLAN_PASSWD "\"\r\n"); } -void ws_esp8266_connect(){ - uint8_t Tx_network[]="AT+CWJAP=\"Test\",\"12345678\"\r\n"; - - - HAL_UART_Transmit(&huart1, Tx_network,strlen((char*)Tx_network),1000); - HAL_Delay(10000); -// HAL_UART_Transmit(&huart1, Tx_network,sizeof(Tx_network),1000); -// HAL_Delay(10000); - - - - +void ws_esp8266_ap_client_mode() { + ws_esp8266_send_seq("AT+CWMODE=1\r\n"); } -void ws_esp8266_serveraan(){ - int ret; - uint8_t buffer1[30]={0}; uint8_t Tx_server[]="AT+CIPSERVER=1,80\r\n"; - - while(ret!=1){ - - HAL_UART_Transmit_IT(&huart1, Tx_server,strlen((char*)Tx_server)); - HAL_UART_Receive_IT(&huart1, buffer1, 30); - HAL_Delay(2000); - - if(ws_esp8266_checkOK(buffer1,30)==1){ - ret=1; - - } - } - - HAL_Delay(1000); +void ws_esp8266_start_tcp_server() { + ws_esp8266_send_seq("AT+CIPSERVER=0\r\n"); // stop tcp server (if running) + ws_esp8266_send_seq("AT+CIPMUX=1\r\n"); // enable multiplexing (allow multiple connections) + ws_esp8266_send_seq("AT+CIPSERVER=1," WS_SERVER_PORT "\r\n"); // start tcp server } -void ws_esp8266_serveruit(){ - int ret; - uint8_t buffer1[27]={0}; uint8_t Tx_server[]="AT+CIPSERVER=0\r\n"; -// -// while(ret!=1){ - - HAL_UART_Transmit_IT(&huart1, Tx_server,strlen((char*)Tx_server)); -// HAL_UART_Receive_IT(&huart1, buffer1, 27); - HAL_Delay(3000); - -// if(unlink(buffer1,27)==1){ -// ret=1; -// -// } -// -// } - HAL_Delay(1000); +void ws_esp8266_set_mac() { + ws_esp8266_send_seq("AT+CIPSTAMAC=\"" WS_ESP8266_WLAN_MAC "\"\r\n"); } -void ws_esp8266_mux(){ - int ret; - uint8_t buffer2[20]={0}; uint8_t Tx_mux[]="AT+CIPMUX=1\r\n"; - - while(ret!=1){ - - HAL_UART_Transmit_IT(&huart1, Tx_mux,strlen((char*)Tx_mux)); - HAL_UART_Receive_IT(&huart1, buffer2, 20); - HAL_Delay(2000); - - if(ws_esp8266_checkOK(buffer2,20)==1){ - ret=1; - - } - - } - - HAL_Delay(5000); -} -void ws_esp8266_close(){ - - uint8_t Tx_close[]="AT+CIPCLOSE=0\r\n"; - - - HAL_UART_Transmit_IT(&huart1, Tx_close,strlen((char*)Tx_close)); - - HAL_Delay(3000); +void ws_esp8266_set_ip() { + ws_esp8266_send_seq("AT+CIPSTA=\"" WS_ESP8266_WLAN_IP "\"\r\n"); } - diff --git a/stm32f091/esp8266.h b/stm32f091/esp8266.h index c09a557..94a7356 100644 --- a/stm32f091/esp8266.h +++ b/stm32f091/esp8266.h @@ -1,16 +1,38 @@ #pragma once +#include <stm32f0xx_hal.h> +#include <stdlib.h> #include <stdint.h> +#include <stdbool.h> -void ws_esp8266_ATsendCommand(uint8_t* data); -int ws_esp8266_checkOK(uint8_t *receiveData,int length); -int ws_esp8266_receivingMsg(uint8_t *receiveData,int length); -int ws_esp8266_unlink(uint8_t *receiveData,int length); -void ws_esp8266_StartEsp(); -void ws_esp8266_disconnect(); -void ws_esp8266_mode(); +#include "consts.h" + +/** @brief DMA rx buffer */ +extern uint8_t g_ws_esp8266_dma_rx_buffer[WS_DMA_RX_BUFFER_SIZE]; +/** @brief null-terminated tx buffer string */ +extern uint8_t g_ws_esp8266_dma_tx_buffer[WS_DMA_TX_BUFFER_SIZE]; + +/** @brief DMA1 channel 2-3 & DMA2 channel 1-2 interrupt handler */ +void DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler(void); +/** @brief DMA1 channel 1 interrupt handler */ +void DMA1_Ch1_IRQHandler(void); +/** @brief USART1 interrupt handler */ +void USART1_IRQHandler(void); + +/** @brief send data to esp over uart with dma */ +void ws_esp8266_send(uint8_t* data, size_t size); + +/** @brief line idle, handle new data on dma buffer */ +void ws_esp8266_incoming_data_chunk(); + +/** @brief connect to access point using wifi.h credentials */ void ws_esp8266_connect(); -void ws_esp8266_serveraan(); -void ws_esp8266_serveruit(); -void ws_esp8266_mux(); -void ws_esp8266_close(); +/** @brief set esp to access point client mode (connect to AP, not become one) */ +void ws_esp8266_ap_client_mode(); +/** @brief initialize and configure the tcp server */ +void ws_esp8266_start_tcp_server(); + +/** @brief set mac address of the esp client */ +void ws_esp8266_set_mac(); +/** @brief set static ip address of the esp client */ +void ws_esp8266_set_ip(); diff --git a/stm32f091/main.c b/stm32f091/main.c index 9235f1b..67c0a8d 100644 --- a/stm32f091/main.c +++ b/stm32f091/main.c @@ -5,19 +5,9 @@ #include "main.h" #include "setup.h" #include "sensor.h" -#include "backlog.h" int main() { ws_io_setup(); - HAL_GPIO_Init(GPIOA, &(GPIO_InitTypeDef) { - .Pin = GPIO_PIN_5, - .Mode = GPIO_MODE_OUTPUT_PP, - .Pull = GPIO_NOPULL - }); - - ws_backlog_alloc(24 * 60); - ws_sensor_read(); - - xTaskCreate(ws_sensor_read_task, "sensor", 128, NULL, 1, NULL); + xTaskCreate(ws_sensor_read_task, "sensor", 64, NULL, 1, NULL); vTaskStartScheduler(); } diff --git a/stm32f091/makefile b/stm32f091/makefile index 5a185de..dd03761 100644 --- a/stm32f091/makefile +++ b/stm32f091/makefile @@ -4,6 +4,9 @@ OC = arm-none-eabi-objcopy RM = rm -f TARGET = main +HOST=$(strip $(shell uname -o)) + +include ../shared/shared.mk SHARED_FLAGS += -g SHARED_FLAGS += -DSTM32F091xC @@ -11,7 +14,6 @@ SHARED_FLAGS += -Wall SHARED_FLAGS += -Wextra # SHARED_FLAGS += -Wno-register SHARED_FLAGS += -Wa,--defsym,CALL_ARM_SYSTEM_INIT=1 -# SHARED_FLAGS += -I/usr/arm-none-eabi/include/ SHARED_FLAGS += -I./lib/STM32-base-STM32Cube/HAL/STM32F0xx/inc SHARED_FLAGS += -I./lib/STM32-base-STM32Cube/HAL/STM32F0xx/inc/Legacy SHARED_FLAGS += -I./lib/STM32-base-STM32Cube/CMSIS/ARM/inc @@ -20,7 +22,10 @@ SHARED_FLAGS += -I./lib/STM32-base/startup SHARED_FLAGS += -I./lib/FreeRTOS-Kernel/include SHARED_FLAGS += -I./lib/FreeRTOS-Kernel/portable/GCC/ARM_CM0/ SHARED_FLAGS += -I. -SHARED_FLAGS += -O1 +ifeq ($(HOST),GNU/Linux) +SHARED_FLAGS += -I/usr/arm-none-eabi/include/ +endif +# SHARED_FLAGS += -O1 SHARED_FLAGS += -ffunction-sections SHARED_FLAGS += -fdata-sections SHARED_FLAGS += -Wl,--gc-sections @@ -74,14 +79,20 @@ $(TARGET).bin: $(TARGET).elf %.o: %.s $(CC) -c $(AFLAGS) $< -o $@ +lib/%.o: lib/%.c + $(CC) -c $(CFLAGS) -w $< -o $@ + %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ +%-stm.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + $(TARGET).elf: $(OBJS) $(LD) $(LFLAGS) $^ -o $@ flash: $(TARGET).bin - st-flash write $(TARGET).bin 0x08000000 + st-flash --reset write $(TARGET).bin 0x08000000 compile_commands: clean compiledb make -n diff --git a/stm32f091/protocol.c b/stm32f091/protocol.c new file mode 100644 index 0000000..f4be08f --- /dev/null +++ b/stm32f091/protocol.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +#include "../shared/protocol.h" +#include "backlog.h" +#include "util.h" +#include "server.h" +#include "esp8266.h" + +void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response, bool send) { + static int record_amount = 0; + static unsigned int record_offset = 0; + const char* response_header = "id,temperature,humidity,atmospheric_pressure\n"; + const unsigned int response_line_len = strlen("xxxx,xx,xx,xx\n"); + + if (!send) { + response->success = WS_PROTOCOL_CMD_RETURN_OK; + response->csh = true; + response->msg = ws_bin_s_alloc(0); + response->msg->bytes = 0; + if (sscanf(parsed_cmd->argv[1], "%x", &record_amount) < 1) response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + if (sscanf(parsed_cmd->argv[2], "%x", &record_offset) < 1) response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + else { + record_amount = WS_MIN(record_amount + record_offset, ws_backlog_get_record_count()); + record_amount = WS_MAX(0, record_amount - record_offset); + response->msg->bytes = strlen(response_header) + response_line_len * record_amount; + } + } else { + if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) return; + ws_protocol_send_data(response_header, strlen(response_header)); + char line[response_line_len + 1]; // + 1 for string terminator + for (unsigned int i = 0; i < record_amount; i++) { + ws_s_backlog_record* record = ws_backlog_get_last_record(i + record_offset); + sprintf(line, "%04x,%02x,%02x,%02x\n", record->id, record->sens_temperature, record->sens_humidity, record->sens_atm_pressure); + ws_protocol_send_data(line, response_line_len); + } + } +} + +void ws_protocol_send_data(const char* data, unsigned int length) { + ws_server_buffer_send_append((uint8_t*) data, length); +} diff --git a/stm32f091/readme.md b/stm32f091/readme.md new file mode 100644 index 0000000..d2758b5 --- /dev/null +++ b/stm32f091/readme.md @@ -0,0 +1,11 @@ +# stm32 firmware subdirectory + +- uses make +- make sure to initialize the git submodules +- all warnings from source files in the lib/ subfolder are hidden +- copy wifi.def.h to wifi.h and edit the network credentials +- the initialization code is broken in some way which means that a soft reset + is required for the uart dma to work, either (a) press the reset button on + the development board after plugging in, or (b) run `st-flash reset` after + plugging in. + diff --git a/stm32f091/sensor.c b/stm32f091/sensor.c index bc3cfd3..1c94e2a 100644 --- a/stm32f091/sensor.c +++ b/stm32f091/sensor.c @@ -58,6 +58,12 @@ void ws_sensor_read() { .sens_humidity = ws_sensor_humidity() }; ws_backlog_add_record(record); + + // < DEBUG PROTOCOL PARSING CODE > + // ws_s_protocol_req_parser_state* parser = ws_protocol_req_parser_alloc(); + // const char* request = "last-records 5\n"; + // ws_protocol_parse_req_bytes(parser, (char*) request, strlen(request)); + // ws_protocol_req_parser_free(parser); } void ws_sensor_read_task() { diff --git a/stm32f091/server.c b/stm32f091/server.c index e289245..d69ef1e 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -3,55 +3,222 @@ #include <stdlib.h> #include <string.h> -#include "setup.h" -#include "server.h" +#include "../shared/protocol.h" #include "esp8266.h" +#include "server.h" +#include "setup.h" +#include "consts.h" +#include "util.h" + +ws_s_server_parser g_ws_server_parser = { + .last_response = WS_SERVER_RC_NONE, + .mode = WS_SERVER_LM_IDLE, + + .current_channel = 0, + .channel_data_length = 0, + .channel_data_counter = 0, + .channel_listen_mode = WS_SERVER_CL_CHANNEL_ID, + + .rc = { 0 }, +}; + +static ws_s_protocol_req_parser_state* g_ws_protocol_parsers[WS_SERVER_MAX_CHANNELS] = {0}; +static unsigned int g_ws_esp8266_dma_tx_buffer_head = 0; +static unsigned int g_ws_esp8266_dma_tx_buffer_tail = 0; +static unsigned int g_ws_esp8266_dma_tx_buffer_cs = 0; // chunk size + +void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore) { + if (ignore) return; + if (channel >= WS_SERVER_MAX_CHANNELS) return; + + if (g_ws_protocol_parsers[channel] == NULL) { + g_ws_protocol_parsers[channel] = ws_protocol_req_parser_alloc(); + } -void ws_server_demo() { - uint8_t ok[]= "ok\r\n"; - uint8_t hier[]= "hier\r\n"; - //disconnect();//connect();// - - ws_esp8266_StartEsp(); - HAL_UART_Transmit(&huart2, hier,sizeof(hier),1000); - ws_esp8266_close(); - HAL_UART_Transmit(&huart2, hier,sizeof(hier),1000); - ws_esp8266_serveruit(); - HAL_UART_Transmit(&huart2, hier,sizeof(hier),1000); - ws_esp8266_mux(); - HAL_UART_Transmit(&huart2, hier,sizeof(hier),1000); - ws_esp8266_mode(); - HAL_UART_Transmit(&huart2, hier,sizeof(hier),1000); - - ws_esp8266_serveraan(); - HAL_UART_Transmit(&huart2, ok,sizeof(ok),1000); - uint8_t receive[24]={0}; - uint8_t sendToQTData[]="gelukt"; - uint8_t test[]="test"; - int ret; - //ATsendCommand(sendToQTData); - while (1) - { - - if(receive[0]=='\0') - { - HAL_UART_Receive_IT(&huart1, receive, 24); + ws_protocol_parse_req_byte(g_ws_protocol_parsers[channel], byte); +} + +void ws_server_req_finish(unsigned int channel, bool ignore) { + if (ignore) return; + if (channel >= WS_SERVER_MAX_CHANNELS) return; + + if (g_ws_protocol_parsers[channel] != NULL) { + ws_protocol_req_parser_free(g_ws_protocol_parsers[channel]); + g_ws_protocol_parsers[channel] = NULL; + } +} + +static bool ws_server_is_response(char data, uint8_t* counter, const char* cmd, unsigned short cmd_len) { + if (data == cmd[*counter]) *counter += 1; + else *counter = 0; + if (*counter == cmd_len) return true; + return false; +} + +void ws_server_req_incoming(uint8_t* data, size_t size) { +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_RX); + HAL_UART_Transmit(&huart2, data, size, 100); +#endif + + for (unsigned int i = 0; i < size; i++) { + uint8_t byte = data[i]; + + switch (g_ws_server_parser.mode) { + case WS_SERVER_LM_CMD_ECHO: { + if (byte == '\n') g_ws_server_parser.mode = WS_SERVER_LM_STATUS_CODE; + break; + } + case WS_SERVER_LM_STATUS_CODE: { + bool code_got = false; + if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_ok, "OK", 2)) { + code_got = true; + g_ws_server_parser.last_response = WS_SERVER_RC_OK; + } else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_error, "ERROR", 5)) { + code_got = true; + g_ws_server_parser.last_response = WS_SERVER_RC_ERR; + } else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_fail, "FAIL", 4)) { + code_got = true; + g_ws_server_parser.last_response = WS_SERVER_RC_ERR; + } else if (ws_server_is_response(byte, &g_ws_server_parser.rc.s_busy, "busy p...", 9)) { + code_got = true; + g_ws_server_parser.last_response = WS_SERVER_RC_BUSY; + } + if (code_got) g_ws_server_parser.mode = WS_SERVER_LM_IDLE; + break; } - else - { - HAL_UART_Transmit(&huart2, test,strlen((char*)test),1000); - HAL_Delay(5000); - - // if(receivingMsg(receive, 24)==1) - // { - // ret=1; - ws_esp8266_ATsendCommand(sendToQTData); - ws_esp8266_close(); - memset(receive,0,24); - //} + case WS_SERVER_LM_IDLE: { + if (ws_server_is_response(byte, &g_ws_server_parser.rc.i_ipd, "+IPD,", 5)) { + g_ws_server_parser.mode = WS_SERVER_LM_IPD_LISTENING; + } else if (ws_server_is_response(byte, &g_ws_server_parser.rc.i_prompt, ">", 1)) { + // ^^^ this is ">" on official espressif firmware, "> " on ai-thinker firmware + g_ws_server_parser.mode = WS_SERVER_LM_CIPSEND_LISTENING; + ws_server_buffer_send_chunk(); + } + break; } + case WS_SERVER_LM_IPD_LISTENING: { + switch (g_ws_server_parser.channel_listen_mode) { + case WS_SERVER_CL_CHANNEL_ID: { + if (byte == ',') { + g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_DATA_LENGTH; + break; + } + g_ws_server_parser.current_channel *= 10; + g_ws_server_parser.current_channel += byte - '0'; // ascii to int + break; + } + case WS_SERVER_CL_DATA_LENGTH: { + if (byte == ':') { + g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_DATA_READ; + if (g_ws_server_parser.channel_data_length > WS_PROTOCOL_CMD_BUFFER_LEN) + g_ws_server_parser.channel_data_ignore = true; + break; + } + g_ws_server_parser.channel_data_length *= 10; + g_ws_server_parser.channel_data_length += byte - '0'; // ascii to int + break; + } + case WS_SERVER_CL_DATA_READ: { + ws_server_req_parse_byte(g_ws_server_parser.current_channel, byte, g_ws_server_parser.channel_data_ignore); + g_ws_server_parser.channel_data_counter++; + if (g_ws_server_parser.channel_data_counter == g_ws_server_parser.channel_data_length) { + g_ws_server_parser.current_channel = 0; + g_ws_server_parser.channel_data_counter = 0; + g_ws_server_parser.channel_data_length = 0; + g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_CHANNEL_ID; + ws_server_req_finish(g_ws_server_parser.current_channel, g_ws_server_parser.channel_data_ignore); + g_ws_server_parser.mode = WS_SERVER_LM_IDLE; + ws_server_buffer_request_chunk_send(); + } + break; + } + default: {} + } + break; + } + case WS_SERVER_LM_CIPSEND_LISTENING: { + if (ws_server_is_response(byte, &g_ws_server_parser.rc.l_send_ok, "SEND OK", 7) || ws_server_is_response(byte, &g_ws_server_parser.rc.l_error, "ERROR", 5)) { + ws_server_buffer_request_chunk_send(); + } + break; + } + default: {} + } + } +} + +/** @brief get amount of bytes in g_ws_esp8266_dma_tx_buffer until \n */ +static unsigned int ws_server_next_line_length() { + for (unsigned int i = g_ws_esp8266_dma_tx_buffer_tail; i <= g_ws_esp8266_dma_tx_buffer_head; i++) + if (g_ws_esp8266_dma_tx_buffer[i] == '\n') return i - g_ws_esp8266_dma_tx_buffer_tail + 1; + return g_ws_esp8266_dma_tx_buffer_head - g_ws_esp8266_dma_tx_buffer_tail; +} +void ws_server_send(uint8_t* data, size_t size) { + g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO; + ws_esp8266_send(data, size); + while (g_ws_server_parser.mode != WS_SERVER_LM_IDLE) {}; +} +void ws_server_buffer_send_append(uint8_t* data, size_t size) { + // TODO: buffer overrun protection + // while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); // make sure buffer isn't used + strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_head], (char*) data, size); // append string + g_ws_esp8266_dma_tx_buffer_head += size; // shift head +} - } +void ws_server_buffer_request_chunk_send() { + g_ws_esp8266_dma_tx_buffer_cs = ws_server_next_line_length(); + + char* cmd = NULL; + size_t len; + + if (g_ws_esp8266_dma_tx_buffer_cs > 0) { + len = asiprintf(&cmd, "AT+CIPSEND=%d,%d\r\n", g_ws_server_parser.current_channel, g_ws_esp8266_dma_tx_buffer_cs); + } else { + len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", g_ws_server_parser.current_channel); + } + free(cmd); + + g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO; + +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX); + HAL_UART_Transmit(&huart2, (uint8_t*) cmd, len, 100); +#endif + HAL_UART_Transmit(&huart1, (uint8_t*) cmd, len, 100); +} + +void ws_server_buffer_send_chunk() { +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX); + HAL_UART_Transmit(&huart2, &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_tail], g_ws_esp8266_dma_tx_buffer_cs, 100); +#endif + HAL_UART_Transmit(&huart1, &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_tail], g_ws_esp8266_dma_tx_buffer_cs, 100); + g_ws_esp8266_dma_tx_buffer_tail += g_ws_esp8266_dma_tx_buffer_cs; + + if (g_ws_esp8266_dma_tx_buffer_head == g_ws_esp8266_dma_tx_buffer_tail) { + g_ws_esp8266_dma_tx_buffer_head = g_ws_esp8266_dma_tx_buffer_tail = 0; + } + +// #ifdef WS_DBG_PRINT_ESP_OVER_USART2 +// ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_TX); +// HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, g_ws_esp8266_dma_tx_buffer_head, 100); +// #endif +// +// HAL_UART_Transmit(&huart1, g_ws_esp8266_dma_tx_buffer, g_ws_esp8266_dma_tx_buffer_head, 100); +// g_ws_esp8266_dma_tx_buffer_head = 0; +// +// HAL_UART_Transmit(&huart1, (uint8_t*) "+++", 3, 100); +} + +// TODO: refactor this +void ws_server_req_respond_end(unsigned int channel) { + char* cmd = NULL; + size_t len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", channel); + g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO; + ws_esp8266_send((uint8_t*) cmd, len); + while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); + free(cmd); } diff --git a/stm32f091/server.h b/stm32f091/server.h index 6a3501d..07c49d9 100644 --- a/stm32f091/server.h +++ b/stm32f091/server.h @@ -1,6 +1,99 @@ #pragma once -void ws_server_demo(); +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> -/** FreeRTOS task that listens for incoming requests from the esp */ -void ws_server_listen_task(); +typedef enum { + WS_SERVER_LM_CMD_ECHO, /** @brief listen for echo of sent command */ + WS_SERVER_LM_STATUS_CODE, /** @brief listen for busy, ERROR or OK */ + WS_SERVER_LM_IDLE, /** @brief listen for incoming +IPD commands */ + WS_SERVER_LM_IPD_LISTENING, /** @brief +IPD received, now reading data */ + WS_SERVER_LM_CIPSEND_LISTENING, /** @brief AT+CIPSEND sent, now reading data */ +} ws_e_server_listen_mode; + +typedef enum { + WS_SERVER_CL_CHANNEL_ID, /** @brief listen channel id */ + WS_SERVER_CL_DATA_LENGTH, /** @brief listen for data byte length */ + WS_SERVER_CL_DATA_READ, /** @brief listen for data and pipe to ws_protocol_parse_req_byte */ +} ws_e_channel_listen_mode; + +typedef enum { + WS_SERVER_RC_NONE = -1, + WS_SERVER_RC_BUSY, + WS_SERVER_RC_ERR, + WS_SERVER_RC_OK, +} ws_e_server_response_code; + +typedef struct { + uint8_t s_ok; /** @brief status code OK */ + uint8_t s_error; /** @brief status code OK */ + uint8_t s_fail; /** @brief status code OK */ + uint8_t s_busy; /** @brief status code OK */ + uint8_t i_ipd; /** @brief idle +IPD, */ + uint8_t i_prompt; /** @brief idle > */ + uint8_t l_send_ok; /** @brief ipd listen SEND OK */ + uint8_t l_error; /** @brief ipd listen ERROR */ +} ws_s_server_parser_response_counter; + +typedef struct { + ws_e_server_listen_mode mode; + ws_e_server_response_code last_response; + unsigned int current_channel; + unsigned int channel_data_length; + unsigned int channel_data_counter; + ws_e_channel_listen_mode channel_listen_mode; + bool channel_data_ignore; + ws_s_server_parser_response_counter rc; +} ws_s_server_parser; + +/** @brief global server parser struct */ +extern ws_s_server_parser g_ws_server_parser; + +/** + * @brief +IPD incoming request handler + * + * this function takes chunks of data from the esp8266 and parses +IPD + * commands. when a valid +IPD command is detected, it gets forwarded to + * ws_protocol_parse_req_byte. + * + * @param data pointer to data array + * @param size amount of bytes allowed to be read from `data` + */ +void ws_server_req_incoming(uint8_t* data, size_t size); + +// /** @brief send AT response header for incoming request on specific channel */ +// void ws_server_req_respond_start(unsigned int channel); +// /** @brief send AT tcp close on specific channel */ +// void ws_server_req_respond_end(unsigned int channel); + +/** @brief send data to esp, waiting until server returns to idle mode */ +void ws_server_send(uint8_t* data, size_t size); + +/** + * @brief parse byte from channel + * + * automatically creates parser struct and passes data onto protocol parser + * functions + * + * @param channel request channel + * @param byte data byte + * @param ignore ignore mode + */ +void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore); + +/** + * @brief close connection + * + * deallocates any parser struct that were automatically created in + * ws_server_req_parse_byte + * + * @param channel request channel + * @param ignore ignore mode + */ +void ws_server_req_finish(unsigned int channel, bool ignore); + +void ws_server_buffer_send_append(uint8_t* data, size_t size); + +void ws_server_buffer_request_chunk_send(); +void ws_server_buffer_send_chunk(); diff --git a/stm32f091/setup.c b/stm32f091/setup.c index fec2b7c..ef00a29 100644 --- a/stm32f091/setup.c +++ b/stm32f091/setup.c @@ -5,7 +5,11 @@ #include <FreeRTOS.h> #include <task.h> +#include "esp8266.h" #include "setup.h" +#include "backlog.h" +#include "server.h" +#include "util.h" I2C_HandleTypeDef hi2c1 = { .Instance = I2C1, @@ -20,16 +24,14 @@ I2C_HandleTypeDef hi2c1 = { }; UART_HandleTypeDef huart1 = { - .Instance = USART1, - .Init.BaudRate = 115200, - .Init.WordLength = UART_WORDLENGTH_8B, - .Init.StopBits = UART_STOPBITS_1, - .Init.Parity = UART_PARITY_NONE, - .Init.Mode = UART_MODE_TX_RX, - .Init.HwFlowCtl = UART_HWCONTROL_NONE, - .Init.OverSampling = UART_OVERSAMPLING_16, - .Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE, - .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT, + .Instance = USART1, + .Init.BaudRate = 115200, + .Init.WordLength = UART_WORDLENGTH_8B, + .Init.StopBits = UART_STOPBITS_1, + .Init.Parity = UART_PARITY_NONE, + .Init.Mode = UART_MODE_TX_RX, + .Init.HwFlowCtl = UART_HWCONTROL_NONE, + .Init.OverSampling = UART_OVERSAMPLING_16, }; UART_HandleTypeDef huart2 = { @@ -45,10 +47,33 @@ UART_HandleTypeDef huart2 = { .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT, }; +DMA_HandleTypeDef hdma_usart1_rx = { + .Instance = DMA1_Channel1, + .Init.Direction = DMA_PERIPH_TO_MEMORY, + .Init.PeriphInc = DMA_PINC_DISABLE, + .Init.MemInc = DMA_MINC_ENABLE, + .Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .Init.MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Init.Mode = DMA_CIRCULAR, + .Init.Priority = DMA_PRIORITY_LOW, +}; + +DMA_HandleTypeDef hdma_usart1_tx = { + .Instance = DMA1_Channel2, + .Init.Direction = DMA_MEMORY_TO_PERIPH, + .Init.PeriphInc = DMA_PINC_DISABLE, + .Init.MemInc = DMA_MINC_ENABLE, + .Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .Init.MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Init.Mode = DMA_NORMAL, + .Init.Priority = DMA_PRIORITY_LOW, +}; + static void ws_io_clock_setup(); static void ws_io_i2c_setup(); static void ws_io_usart1_setup(); static void ws_io_usart2_setup(); +static void ws_io_dma_setup(); static void ws_setup_error_handler(); void ws_io_setup() { @@ -56,8 +81,36 @@ void ws_io_setup() { ws_io_clock_setup(); ws_io_i2c_setup(); + ws_io_dma_setup(); ws_io_usart1_setup(); ws_io_usart2_setup(); + ws_io_dma_setup(); + + HAL_GPIO_Init(GPIOA, &(GPIO_InitTypeDef) { + .Pin = GPIO_PIN_5, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL + }); + + // TODO: remove debug size + ws_backlog_alloc(24 * 60); + // ws_backlog_alloc(10); + +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(WS_DBG_TTY_COLOR_DBGMSG); + const char restart_str[] = "\r\n--- stm restart ---\r\n"; + HAL_UART_Transmit(&huart2, (uint8_t*) restart_str, strlen(restart_str), 100); +#endif + + ws_esp8266_ap_client_mode(); +#ifdef WS_ESP8266_WLAN_MAC + ws_esp8266_set_mac(); +#endif +#ifdef WS_ESP8266_WLAN_IP + ws_esp8266_set_ip(); +#endif + do ws_esp8266_connect(); while (g_ws_server_parser.last_response == WS_SERVER_RC_ERR); + ws_esp8266_start_tcp_server(); } static void ws_io_clock_setup() { @@ -97,11 +150,27 @@ static void ws_io_i2c_setup() { static void ws_io_usart1_setup() { if (HAL_UART_Init(&huart1) != HAL_OK) return ws_setup_error_handler(); + + HAL_UART_Receive_DMA(&huart1, g_ws_esp8266_dma_rx_buffer, WS_DMA_RX_BUFFER_SIZE); + __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); + + __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // enable receive intterupts + __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // enable idle line detection } static void ws_io_usart2_setup() { if (HAL_UART_Init(&huart2) != HAL_OK) return ws_setup_error_handler(); +} + +static void ws_io_dma_setup() { + __HAL_RCC_DMA1_CLK_ENABLE(); + + // interrupt priorities + HAL_NVIC_SetPriority(DMA1_Ch1_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DMA1_Ch1_IRQn); + HAL_NVIC_SetPriority(DMA1_Ch2_3_DMA2_Ch1_2_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DMA1_Ch2_3_DMA2_Ch1_2_IRQn); } void HAL_MspInit() { @@ -136,6 +205,14 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { .Alternate = GPIO_AF1_USART1, }); + // DMA setup + if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) return ws_setup_error_handler(); + __HAL_DMA1_REMAP(HAL_DMA1_CH1_USART1_RX); + __HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx); + if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) return ws_setup_error_handler(); + __HAL_DMA1_REMAP(HAL_DMA1_CH2_USART1_TX); + __HAL_LINKDMA(huart, hdmatx, hdma_usart1_tx); + // USART1 interrupt Init HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); diff --git a/stm32f091/setup.h b/stm32f091/setup.h index 8ca3720..d459635 100644 --- a/stm32f091/setup.h +++ b/stm32f091/setup.h @@ -4,24 +4,13 @@ #include <stm32f0xx_hal_i2c.h> #include <stm32f0xx_hal_uart.h> -#define WS_PINOUT_I2C_SDA_PIN GPIO_PIN_9 -#define WS_PINOUT_I2C_SDA_PORT GPIOB -#define WS_PINOUT_I2C_SCL_PIN GPIO_PIN_8 -#define WS_PINOUT_I2C_SCL_PORT GPIOB - -#define WS_PINOUT_USART1_RX_PIN GPIO_PIN_10 -#define WS_PINOUT_USART1_RX_PORT GPIOA -#define WS_PINOUT_USART1_TX_PIN GPIO_PIN_9 -#define WS_PINOUT_USART1_TX_PORT GPIOA - -#define WS_PINOUT_USART2_RX_PIN GPIO_PIN_3 -#define WS_PINOUT_USART2_RX_PORT GPIOA -#define WS_PINOUT_USART2_TX_PIN GPIO_PIN_2 -#define WS_PINOUT_USART2_TX_PORT GPIOA +#include "consts.h" extern I2C_HandleTypeDef hi2c1; extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; +extern DMA_HandleTypeDef hdma_usart1_rx; +extern DMA_HandleTypeDef hdma_usart1_tx; void ws_io_setup(); diff --git a/stm32f091/util.h b/stm32f091/util.h new file mode 100644 index 0000000..11bee6f --- /dev/null +++ b/stm32f091/util.h @@ -0,0 +1,51 @@ +#pragma once + +#include <stdlib.h> +#include <stdio.h> +#include <stm32f0xx_hal.h> +#include <string.h> + +#include "setup.h" +#include "../shared/util.h" + +#define WS_DBG_TTY_COLOR_BLK 0x0 +#define WS_DBG_TTY_COLOR_RED 0x1 +#define WS_DBG_TTY_COLOR_GRN 0x2 +#define WS_DBG_TTY_COLOR_YLW 0x3 +#define WS_DBG_TTY_COLOR_BLU 0x4 +#define WS_DBG_TTY_COLOR_VLT 0x5 +#define WS_DBG_TTY_COLOR_CYN 0x6 +#define WS_DBG_TTY_COLOR_WHI 0x7 +#define WS_DBG_TTY_COLOR_BR_BLK 0x8 +#define WS_DBG_TTY_COLOR_BR_RED 0x9 +#define WS_DBG_TTY_COLOR_BR_GRN 0xa +#define WS_DBG_TTY_COLOR_BR_YLW 0xb +#define WS_DBG_TTY_COLOR_BR_BLU 0xc +#define WS_DBG_TTY_COLOR_BR_VLT 0xd +#define WS_DBG_TTY_COLOR_BR_CYN 0xe +#define WS_DBG_TTY_COLOR_BR_WHI 0xf + +// serial debug color scheme +#define WS_DBG_TTY_COLOR_DBGMSG WS_DBG_TTY_COLOR_BR_BLK +#define WS_DBG_TTY_COLOR_TX WS_DBG_TTY_COLOR_GRN +#define WS_DBG_TTY_COLOR_RX WS_DBG_TTY_COLOR_RED + +#define debugger asm("nop") + +// unused +// #define WS_DBG_TTY_COLOR_CMD_ECHO WS_DBG_TTY_COLOR_BLK +// #define WS_DBG_TTY_COLOR_STATUS_CODE WS_DBG_TTY_COLOR_YLW +// #define WS_DBG_TTY_COLOR_IDLE WS_DBG_TTY_COLOR_VLT +// #define WS_DBG_TTY_COLOR_IPD_LISTENING WS_DBG_TTY_COLOR_GRN +// #define WS_DBG_TTY_COLOR_CIPSEND_LISTENING WS_DBG_TTY_COLOR_RED + +#define ws_usb_printf(fmt, ...) { \ + char temp[255]; \ + snprintf(temp, 255, fmt, ##__VA_ARGS__); \ + HAL_UART_Transmit(&huart2, (uint8_t*) temp, sizeof(char) * strlen(temp), HAL_MAX_DELAY); \ +} + +#define ws_dbg_set_usart2_tty_color(color) { \ + uint8_t sgr[] = { 0x1b, 0x5b, 0x33 + (color > 7 ? 6 : 0), 0x30 + (color & 0b111), 0x6d }; \ + HAL_UART_Transmit(&huart2, sgr, sizeof(sgr), 100); \ +} diff --git a/stm32f091/wifi.def.h b/stm32f091/wifi.def.h new file mode 100644 index 0000000..61e1706 --- /dev/null +++ b/stm32f091/wifi.def.h @@ -0,0 +1,7 @@ +#pragma once + +#define WS_ESP8266_WLAN_SSID "Test" +#define WS_ESP8266_WLAN_PASSWD "12345678" +// #define WS_ESP8266_WLAN_MAC "f2:9b:89:47:c4:f3" +// #define WS_ESP8266_WLAN_IP "192.168.2.69" + @@ -0,0 +1,28 @@ +# things that have to get fixed before monday + +- [ ] more documentation in header files (for both client and stm code) +- [ ] design/architecture document +- [x] more tests in the test document +- [x] handle errors from `AT+CIPSEND`, these look like this: + ``` + > AT0,CONNECT + + > +IPD,0,15:last-records 5<0a> + < AT+CIPSEND=0,125 + > AT+CIPSEND=0,125 + + > ERROR + ``` + +## `// TODO:`'s + +- [ ] `sensor.c:24: return (uint8_t) temp_c; //TODO: convert with range -> util.h` +- [ ] `sensor.c:36: return (uint8_t) humidity; //TODO: convert with range -> util.h` +- [ ] `sensor.c:51: return (uint8_t) val; // TODO: convert with range` +- [x] `server.c:47:// TODO: next_few_bytes_are assumes that the complete search string is in the` +- [ ] `server.c:146: // TODO: buffer overrun protection` +- [x] `server.c:152:// TODO: refactor this` +- [x] `server.c:165:// TODO: refactor this` +- [x] `server.c:174:// TODO: refactor this` +- [ ] `setup.c:95: // TODO: remove debug size` +- [ ] `setup.c:187: .Pin = GPIO_PIN_8|GPIO_PIN_9, //TODO: use #defines in setup.h` |