basic function OK

This commit is contained in:
Villivateur Von 2021-09-20 22:48:41 +08:00
parent 32e1eb8958
commit 97d17ada7c
18 changed files with 489 additions and 62 deletions

24
doc/province_bit_map.md Normal file
View File

@ -0,0 +1,24 @@
# 各省对应的 LED 位
此表为 Mapuino 上实际闪烁的 LED 所在省级行政区与 HTTP 报文中 `data0`、`data1` 字段的对应关系。
| 省 | 字段 | 位 | 省 | 字段 | 位 |
|----|-----|----|----|------|---|
| 新疆 | data0 | 0 | 内蒙古 | data0 | 1 |
| 黑龙江 | data0 | 2 | 吉林 | data0 | 3 |
| 辽宁 | data0 | 4 | 北京 | data0 | 5 |
| 天津 | data0 | 6 | 青海 | data0 | 7 |
| 甘肃 | data0 | 8 | 宁夏 | data0 | 9 |
| 陕西 | data0 | 10 | 山西 | data0 | 11 |
| 河北 | data0 | 12 | 山东 | data0 | 13 |
| 河南 | data0 | 14 | 西藏 | data0 | 15 |
| 四川 | data0 | 16 | 重庆 | data0 | 17 |
| 湖北 | data0 | 18 | 安徽 | data0 | 19 |
| 江苏 | data0 | 20 | 云南 | data0 | 21 |
| 贵州 | data0 | 22 | 湖南 | data0 | 23 |
| 江西 | data0 | 24 | 浙江 | data0 | 25 |
| 上海 | data0 | 26 | 广西 | data0 | 27 |
| 广东 | data0 | 28 | 福建 | data0 | 29 |
| 海南 | data0 | 30 | 澳门 | data0 | 31 |
| 香港 | data1 | 0 | 台湾 | data1 | 1 |
| World | data1 | 2 |

20
include/client_network.h Normal file
View File

@ -0,0 +1,20 @@
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
class ClientNetwork
{
private:
String url;
StaticJsonDocument<512> receivedData;
HTTPClient* http;
STATUS status;
public:
ClientNetwork();
STATUS FetchNewData();
uint32_t GetData0();
uint32_t GetData1();
};

15
include/config_manager.h Normal file
View File

@ -0,0 +1,15 @@
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
class ConfigManager
{
private:
IPAddress localIp;
IPAddress gateway;
IPAddress subnet;
public:
ESP8266WebServer httpServer;
ConfigManager();
void ProcessConfig();
};

12
include/display.h Normal file
View File

@ -0,0 +1,12 @@
#include <Arduino.h>
#include <TM1638plus.h>
class DisplayPanel
{
private:
TM1638plus* ledMap;
public:
DisplayPanel();
void DisplayLedMap(uint32_t data0, uint32_t data1);
};

11
include/func_button.h Normal file
View File

@ -0,0 +1,11 @@
#include <Arduino.h>
class FuncButton
{
private:
uint8_t pressedTime;
public:
FuncButton();
void Scan();
};

10
include/monitor_items.h Normal file
View File

@ -0,0 +1,10 @@
// Topuino and Topuino_Server must share this header file
#define CPU_PERCENT "CPU_PERCENT"
#define MEM_PERCENT "MEM_PERCENT"
#define DISK0_PERCENT "DISK_PERCENT"
#define DISK1_PERCENT "DISK1_PERCENT"
#define DISK_READ_RATE "DISK_READ_RATE"
#define DISK_WRITE_RATE "DISK_WRITE_RATE"
#define NET_SENT_RATE "NET_SENT_RATE"
#define NET_RECV_RATE "NET_RECV_RATE"

21
include/status_blink.h Normal file
View File

@ -0,0 +1,21 @@
#include <Arduino.h>
#include <Ticker.h>
#define STATUS_LED_PIN 2
class StatusBlink
{
private:
Ticker flipper;
public:
enum BlinkRate {
RateAlwaysOn,
Rate5Hz,
Rate2Hz,
Rate0_5Hz,
RateAlwaysOff,
};
StatusBlink();
void SetBlinkRate(BlinkRate rate);
};

19
include/user_data.h Normal file
View File

@ -0,0 +1,19 @@
#include <Arduino.h>
class UserData
{
private:
String ReadEepromString(uint32_t offset);
void WriteEepromString(String data, uint32_t offset);
public:
UserData();
bool UserDataValid();
void ConfirmData();
void EraseData();
String GetWifiSsid();
void SetWifiSsid(String ssid);
String GetWifiPasswd();
void SetWifiPasswd(String password);
String GetDeviceUuid();
void SetDeviceUuid(String uuid);
};

View File

@ -1,46 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -12,3 +12,6 @@
platform = espressif8266
board = esp12e
framework = arduino
lib_deps =
gavinlyonsrepo/TM1638plus@^1.7.0
bblanchon/ArduinoJson@^6.18.3

61
src/client_network.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "client_network.h"
#include "status_blink.h"
#include "user_data.h"
#include "func_button.h"
extern StatusBlink* statusLed;
extern UserData* userdataManager;
extern FuncButton* funcButton;
ClientNetwork::ClientNetwork()
{
WiFi.begin(userdataManager->GetWifiSsid(), userdataManager->GetWifiPasswd());
statusLed->SetBlinkRate(StatusBlink::BlinkRate::Rate2Hz);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
funcButton->Scan();
}
statusLed->SetBlinkRate(StatusBlink::BlinkRate::RateAlwaysOff);
url = "http://iot.vvzero.com/mapuino/hardwareAPI?UUID=";
url += userdataManager->GetDeviceUuid();
status = FAIL;
}
STATUS ClientNetwork::FetchNewData()
{
status = FAIL;
if (WiFi.status() == WL_CONNECTED) {
WiFiClient client;
http = new HTTPClient();
if (http->begin(client, url)) {
if (http->GET() == HTTP_CODE_OK) {
if (deserializeJson(receivedData, http->getString().c_str()) == DeserializationError::Code::Ok) {
status = OK;
}
}
http->end();
}
delete http;
}
return status;
}
uint32_t ClientNetwork::GetData0()
{
if (status != OK) {
return 0;
} else {
return (uint32_t)receivedData["DATA0"];
}
}
uint32_t ClientNetwork::GetData1()
{
if (status != OK) {
return 0;
} else {
return (uint32_t)receivedData["DATA1"];
}
}

88
src/config_manager.cpp Normal file
View File

@ -0,0 +1,88 @@
#include "config_manager.h"
#include "status_blink.h"
#include "user_data.h"
#define SSID "Topuino"
#define PASSWORD "vvzero.com"
extern StatusBlink* statusLed;
extern ConfigManager* configManager;
extern UserData* userdataManager;
static String configPage("\
<!DOCTYPE html>\
<html>\
<head>\
<title>Topuino</title>\
<meta name='viewport' content='width=device-width, initial-scale=1, user-scalable=no' />\
<link rel='shortcut icon' href='data:,'>\
</head>\
<body>\
<h1 style='text-align: center; font-size: 40px'>Topuino Config Page</h1>\
<form action='/setup' method='POST'>\
<div style='text-align: center'>\
<div style='font-size: 20px; margin-bottom: 15px'>\
<label for='ssid'><b>Wi-Fi SSID</b></label>\
<input type='text' name='ssid' required>\
</div>\
<div style='font-size: 20px; margin-bottom: 15px'>\
<label for='psw'><b>Wi-Fi Password</b></label>\
<input type='password' name='psw' required>\
</div>\
<div style='font-size: 20px; margin-bottom: 15px'>\
<label for='uuid'><b>Device ID</b></label>\
<input type='text' name='uuid' required>\
</div>\
<div style='font-size: 20px'>\
<button type='submit'>Commit</button>\
</div>\
</div>\
</form>\
</body>\
</html>\
");
static void handleOnConnect()
{
configManager->httpServer.send(200, "text/html", configPage);
}
static void handleOnCommit()
{
if (configManager->httpServer.hasArg("ssid") && configManager->httpServer.hasArg("psw") && configManager->httpServer.hasArg("uuid")) {
userdataManager->SetWifiSsid(configManager->httpServer.arg("ssid"));
userdataManager->SetWifiPasswd(configManager->httpServer.arg("psw"));
userdataManager->SetDeviceUuid(configManager->httpServer.arg("uuid"));
userdataManager->ConfirmData();
configManager->httpServer.send(200, "text/html", "OK");
delay(200);
ESP.restart();
} else {
configManager->httpServer.send(200, "text/html", "ERROR");
}
}
ConfigManager::ConfigManager() :
localIp(192,168,1,1),
gateway(192,168,1,1),
subnet(255,255,255,0),
httpServer(80)
{
statusLed->SetBlinkRate(StatusBlink::BlinkRate::Rate0_5Hz);
WiFi.softAPConfig(localIp, gateway, subnet);
WiFi.softAP(SSID, PASSWORD);
delay(100);
httpServer.on("/", handleOnConnect);
httpServer.on("/setup", handleOnCommit);
httpServer.begin();
}
void ConfigManager::ProcessConfig()
{
while (1) {
httpServer.handleClient();
}
}

22
src/display.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "display.h"
#define STROBE_TM1 13
#define CLOCK_TM 4 // clock = GPIO connected to clock line of module
#define DIO_TM 5 // data = GPIO connected to data line of module
#define HIGH_FREQ false //default false, If using a high freq CPU > ~100 MHZ set to true.
DisplayPanel::DisplayPanel()
{
// Constructor object (GPIO STB , GPIO CLOCK , GPIO DIO, use high freq MCU)
ledMap = new TM1638plus(STROBE_TM1, CLOCK_TM, DIO_TM, HIGH_FREQ);
ledMap->displayBegin();
}
void DisplayPanel::DisplayLedMap(uint32_t data0, uint32_t data1)
{
ledMap->display7Seg(0, data0 % 0x100);
ledMap->display7Seg(1, data0 / 0x100 % 0x100);
ledMap->display7Seg(2, data0 / 0x10000 % 0x100);
ledMap->display7Seg(3, data0 / 0x1000000);
ledMap->display7Seg(4, data1 % 0x100);
}

26
src/func_button.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "func_button.h"
#include "user_data.h"
#define FUNC_BTN 0
#define PRESSED_STATUS LOW
extern UserData* userdataManager;
FuncButton::FuncButton()
{
pinMode(FUNC_BTN, INPUT);
pressedTime = 0;
}
void FuncButton::Scan()
{
if (digitalRead(FUNC_BTN) == PRESSED_STATUS) {
pressedTime++;
} else {
pressedTime = 0;
}
if (pressedTime > 5) {
userdataManager->EraseData();
ESP.restart();
}
}

View File

@ -1,9 +1,40 @@
#include <Arduino.h>
#include "display.h"
#include "client_network.h"
#include "monitor_items.h"
#include "status_blink.h"
#include "config_manager.h"
#include "user_data.h"
#include "func_button.h"
void setup() {
// put your setup code here, to run once:
DisplayPanel* displayPanel;
ClientNetwork* netClient;
StatusBlink* statusLed;
UserData* userdataManager;
ConfigManager* configManager;
FuncButton* funcButton;
void setup()
{
statusLed = new StatusBlink();
userdataManager = new UserData();
displayPanel = new DisplayPanel();
funcButton = new FuncButton();
if (!userdataManager->UserDataValid()) {
configManager = new ConfigManager();
configManager->ProcessConfig();
} else {
netClient = new ClientNetwork();
}
}
void loop() {
// put your main code here, to run repeatedly:
}
void loop()
{
delay(1000);
funcButton->Scan();
if (netClient->FetchNewData() != OK) {
return;
}
displayPanel->DisplayLedMap(netClient->GetData0(), netClient->GetData1());
}

36
src/status_blink.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "status_blink.h"
StatusBlink::StatusBlink()
{
pinMode(STATUS_LED_PIN, OUTPUT);
digitalWrite(STATUS_LED_PIN, HIGH);
}
static void BlinkTask()
{
digitalWrite(STATUS_LED_PIN, !digitalRead(STATUS_LED_PIN)); // set pin to the opposite state
}
void StatusBlink::SetBlinkRate(BlinkRate rate)
{
switch (rate)
{
case BlinkRate::RateAlwaysOn:
flipper.detach();
digitalWrite(STATUS_LED_PIN, LOW);
break;
case BlinkRate::RateAlwaysOff:
flipper.detach();
digitalWrite(STATUS_LED_PIN, HIGH);
break;
case BlinkRate::Rate5Hz:
flipper.attach(0.1, BlinkTask);
break;
case BlinkRate::Rate2Hz:
flipper.attach(0.25, BlinkTask);
break;
case BlinkRate::Rate0_5Hz:
flipper.attach(1.0, BlinkTask);
break;
}
}

85
src/user_data.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "user_data.h"
#include <EEPROM.h>
#define MAX_USER_DATA_SIZE 0x200
#define VALIDATION_MAGIC 0xaa
#define GENERAL_FEILD_SIZE 0x20
#define VALIDATION_OFFSET 0x00
#define SSID_OFFSET 0x20
#define PASSWORD_OFFSET 0x40
#define UUID_OFFSET 0x60
UserData::UserData()
{
EEPROM.begin(MAX_USER_DATA_SIZE);
}
String UserData::ReadEepromString(uint32_t offset)
{
String result;
char readByte;
for (uint32_t addr = offset; (readByte = EEPROM.read(addr)) != '\0'; addr++) {
result += readByte;
}
return result;
}
void UserData::WriteEepromString(String data, uint32_t offset)
{
for (uint32_t i = 0; i < data.length(); i++) {
EEPROM.write(i + offset, data[i]);
}
EEPROM.write(data.length() + offset, 0x00);
}
bool UserData::UserDataValid()
{
byte validation = EEPROM.read(VALIDATION_OFFSET);
return validation == VALIDATION_MAGIC;
}
void UserData::ConfirmData()
{
EEPROM.write(VALIDATION_OFFSET, VALIDATION_MAGIC);
EEPROM.commit();
}
void UserData::EraseData()
{
EEPROM.write(VALIDATION_OFFSET, 0x00);
EEPROM.commit();
}
String UserData::GetWifiSsid()
{
return ReadEepromString(SSID_OFFSET);
}
void UserData::SetWifiSsid(String ssid)
{
return WriteEepromString(ssid, SSID_OFFSET);
}
String UserData::GetWifiPasswd()
{
return ReadEepromString(PASSWORD_OFFSET);
}
void UserData::SetWifiPasswd(String password)
{
return WriteEepromString(password, PASSWORD_OFFSET);
}
String UserData::GetDeviceUuid()
{
return ReadEepromString(UUID_OFFSET);
}
void UserData::SetDeviceUuid(String uuid)
{
return WriteEepromString(uuid, UUID_OFFSET);
}

View File

@ -1,11 +0,0 @@
This directory is intended for PlatformIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html