Arduino - 将高分写入 SD 卡上的 SQLite 数据库

Posted

技术标签:

【中文标题】Arduino - 将高分写入 SD 卡上的 SQLite 数据库【英文标题】:Arduino - write highscores to SQLite database on SD card 【发布时间】:2021-12-30 03:10:04 【问题描述】:

编辑 因为我找到的解决方案采用了不同的路径,所以我更新了标题以反映最终解决方案。最终解决方案允许通过简单的查询轻松添加和删除条目或检索您想要的条目数。最初的问题(下)是关于用 txt 文件解决问题的。

我有一个 ESP32,目前将高分写入 EEPROM。

每个条目都包含一个名称和分数。

我想用 SD 卡替换此工作解决方案。 我会在 SD 卡上有一个包含前 100 名分数的 txt 文件。一个文件会是这样的:

Player1          97.3     ROWCHECKSUM
Some player name 92.3     ROWCHECKSUM
Player1          91.2     ROWCHECKSUM
Player1          90.3     ROWCHECKSUM
Player2          87.1     ROWCHECKSUM
Player4 guy      77.3     ROWCHECKSUM
Player2          64.3     ROWCHECKSUM
Player1          61.1     ROWCHECKSUM
Player7          51.1     ROWCHECKSUM
.
.
.
Player9          21.1     ROWCHECKSUM

rowchecksum 将确保没有人手动更改文件。 每次有新的高分时,我都必须更新 txt 文件。什么是一个好的方法呢?每次都删除文件并重新生成?似乎要写入很多数据只是为了删除最后一行并将新行插入到适当的位置。

【问题讨论】:

【参考方案1】:

我通过将数据写入 SD 卡上的 sqlite 数据库解决了这个问题。这样我可以简单地添加行,然后使用查询返回前 10 名玩家。

根据评论中的要求进行更新。

我的表叫做 highscores,它的结构是:

名称:字符串 分数:字符串 哈希:字符串

has 是sha256(name + score + salt) 并确保没有人修改名称或分数。

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <sqlite3.h>
#include <SPI.h>
#include <FS.h>
#include "SD.h"
#include "mbedtls/md.h"

#include "highscores.h"

[...]
WebServer server(80);
int rc;
sqlite3_stmt *res;
int rec_count = 0;
const char *tail;
sqlite3 *db1;
char *zErrMsg = 0;
File myFile;
[...]

void setup(void) 

 [...]
  server.on("/highscores", handleHighscores);
  server.on("/gethighscores", handleGetHighscores);

  sqlite3_initialize();
  if (openDb("/sd/mydb.db3", &db1))
    return;
 [...]


void loop(void) 
  server.handleClient();

 if (progStep == SAVEHIGHSCORE)
    


      String tmp = shooter + rankingAvgScore + "fajlo5a5%9k";
      const char *payload = tmp.c_str();

      byte shaResult[32];

      mbedtls_md_context_t ctx;
      mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
      const size_t payloadLength = strlen(payload);

      mbedtls_md_init(&ctx);
      mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
      mbedtls_md_starts(&ctx);
      mbedtls_md_update(&ctx, (const unsigned char *) payload, payloadLength);
      mbedtls_md_finish(&ctx, shaResult);
      mbedtls_md_free(&ctx);

      String shastr;
      for (int i = 0; i < sizeof(shaResult); i++) 
        char str[3];
        sprintf(str, "%02x", (int)shaResult[i]);
        shastr = shastr + str;
      

      String sql = "insert into highscores ('name','score','hash') values ('";
      sql += shooter;
      sql += "','";
      sql += rankingAvgScore;
      sql += "','";
      sql += shastr;
      sql += "')";
      
      rc = db_exec(db1, sql.c_str());

      sql = "Select * from highscores order by score desc limit 10";

      rc = sqlite3_prepare_v2(db1, sql.c_str(), 1000, &res, &tail);
      if (rc != SQLITE_OK) 
        String resp = "Failed to fetch data: ";
        resp += sqlite3_errmsg(db1);
        Serial.println(resp.c_str());
        return;
      
      rec_count = 0;
      while (sqlite3_step(res) == SQLITE_ROW) 
        highscoreNames[rec_count] = (const char *) sqlite3_column_text(res, 1);
        highscoreScores[rec_count] = sqlite3_column_double(res, 2);
        highscoreHash[rec_count] = (const char *) sqlite3_column_text(res, 3);
        rec_count++;
      
      sqlite3_finalize(res);
     
      progStep = END;

    

这会根据请求发送网页。

void handleHighscores() 
  Serial.println("GET /");
  server.send(200, "text/html", htmlhighscores);

这会在网页请求时从数据库中读取值..

void handleGetHighscores()


  /* read highscores from sqlite db*/

  String sql = "Select * from highscores order by score desc limit 10";

  rc = sqlite3_prepare_v2(db1, sql.c_str(), 1000, &res, &tail);
  if (rc != SQLITE_OK) 
    String resp = "Failed to fetch data: ";
    resp += sqlite3_errmsg(db1);
    Serial.println(resp.c_str());
    return;
  
  rec_count = 0;
  while (sqlite3_step(res) == SQLITE_ROW) 
    highscoreNames[rec_count] = (const char *) sqlite3_column_text(res, 1);
    highscoreScores[rec_count] = sqlite3_column_double(res, 2);
    highscoreHash[rec_count] = (const char *) sqlite3_column_text(res, 3);    
    rec_count++;
  
  sqlite3_finalize(res);

  /* end read highschores from sqlite db*/

  StaticJsonDocument<2000> doc;
  JsonObject root = doc.to<JsonObject>();
  JsonObject values = root["highscores"].to<JsonObject>();

  //String highscoreNames[10];
  //double highscoreScores[10];

  for (int i = 0; i <= 9; i++) 
     String tmp = highscoreNames[i] + highscoreScores[i] + "fajlo5a5%9k";
      const char *payload = tmp.c_str();
      Serial.println(tmp);
      byte shaResult[32];

      mbedtls_md_context_t ctx;
      mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
      const size_t payloadLength = strlen(payload);

      mbedtls_md_init(&ctx);
      mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
      mbedtls_md_starts(&ctx);
      mbedtls_md_update(&ctx, (const unsigned char *) payload, payloadLength);
      mbedtls_md_finish(&ctx, shaResult);
      mbedtls_md_free(&ctx);

      String shastr;
      for (int i = 0; i < sizeof(shaResult); i++) 
        char str[3];
        sprintf(str, "%02x", (int)shaResult[i]);
        shastr = shastr + str;
      
    String tmp2 = "name" + (String)(i+1);
    values[tmp2] = highscoreNames[i];
    tmp2 = "score" + (String)(i+1);
    values[tmp2] = highscoreScores[i];
    Serial.println(highscoreHash[i]);
    Serial.println(shastr);
    
    if ((highscoreHash[i] != shastr) && (highscoreScores[i] > 0))
    
      values[tmp2] = (String)highscoreScores[i] + (String)" Hacked.. :D";
    
      
  
 
 
  Serial.println("Json SENT");
  Serial.println(highscoreScores[0]);
  String json;
  serializeJsonPretty(doc, json);
  //Serial.println(json);
  server.send(200, "text/plane", json);

highschores.h 文件

const char htmlhighscores[] PROGMEM = R"=====(
<html>
<style>
div.divshooter
  text-align: center;
  font-size: 18px;
  font-weight: bold;  

div.minimalistBlack 
  border: 0px solid #000000;
  width: 100%;
  text-align: left;
  border-collapse: collapse;

.divTable.minimalistBlack .divTableCell, .divTable.minimalistBlack .divTableHead 
  border: 1px solid #000000;
  padding: 5px 4px;

.divTable.minimalistBlack .divTableBody .divTableCell 
  font-size: 13px;

.divTable.minimalistBlack .divTableHeading 
  background: #CFCFCF;
  background: -moz-linear-gradient(top, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
  background: -webkit-linear-gradient(top, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
  background: linear-gradient(to bottom, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%);
  border-bottom: 3px solid #000000;

.divTable.minimalistBlack .divTableHeading .divTableHead 
  font-size: 15px;
  font-weight: bold;
  color: #000000;
  text-align: left;

.minimalistBlack .tableFootStyle 
  font-size: 14px;
  font-weight: bold;
  color: #000000;
  border-top: 3px solid #000000;

.minimalistBlack .tableFootStyle 
  font-size: 14px;

/* DivTable.com */
.divTable display: table; 
.divTableRow  display: table-row; 
.divTableHeading  display: table-header-group;
.divTableCell, .divTableHead  display: table-cell;
.divTableHeading  display: table-header-group;
.divTableFoot  display: table-footer-group;
.divTableBody  display: table-row-group;
</style>
<script>
function getData() 
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() 
    if (this.readyState == 4 && this.status == 200) 
      var jsonval = JSON.parse( this.responseText );
      
  
      document.getElementById("name1").innerHTML = jsonval.highscores["name1"];
      document.getElementById("score1").innerHTML = jsonval.highscores["score1"];
      document.getElementById("name2").innerHTML = jsonval.highscores["name2"];
      document.getElementById("score2").innerHTML = jsonval.highscores["score2"];
      document.getElementById("name3").innerHTML = jsonval.highscores["name3"];
      document.getElementById("score3").innerHTML = jsonval.highscores["score3"];
      document.getElementById("name4").innerHTML = jsonval.highscores["name4"];
      document.getElementById("score4").innerHTML = jsonval.highscores["score4"];
      document.getElementById("name5").innerHTML = jsonval.highscores["name5"];
      document.getElementById("score5").innerHTML = jsonval.highscores["score5"];
      document.getElementById("name6").innerHTML = jsonval.highscores["name6"];
      document.getElementById("score6").innerHTML = jsonval.highscores["score6"];
      document.getElementById("name7").innerHTML = jsonval.highscores["name7"];
      document.getElementById("score7").innerHTML = jsonval.highscores["score7"];
      document.getElementById("name8").innerHTML = jsonval.highscores["name8"];
      document.getElementById("score8").innerHTML = jsonval.highscores["score8"];
      document.getElementById("name9").innerHTML = jsonval.highscores["name9"];
      document.getElementById("score9").innerHTML = jsonval.highscores["score9"];
      document.getElementById("name10").innerHTML = jsonval.highscores["name10"];
      document.getElementById("score10").innerHTML = jsonval.highscores["score10"];

      console.log(this.responseText);
      
    
  ;
  xhttp.open("GET", "gethighscores", true);
  xhttp.send();



</script>
<body onload="getData();">
<h2>Highscores</h2>

<div class="divTable minimalistBlack">
<div class="divTableHeading">
<div class="divTableRow">
<div class="divTableHead">Rank</div>
<div class="divTableHead">Name</div>
<div class="divTableHead">Score</div>
</div>
</div>
<div class="divTableBody">

<div class = "divTableRow">
<div class = "divTableCell"><b><u>1</u></b></div>
<div class = "divTableCell" id="name1"></div>
<div class = "divTableCell" id="score1"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell"><b>2</b></div>
<div class = "divTableCell" id="name2"></div>
<div class = "divTableCell" id="score2"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell"><b>3</b></div>
<div class = "divTableCell" id="name3"></div>
<div class = "divTableCell" id="score3"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">4</div>
<div class = "divTableCell" id="name4"></div>
<div class = "divTableCell" id="score4"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">5</div>
<div class = "divTableCell" id="name5"></div>
<div class = "divTableCell" id="score5"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">6</div>
<div class = "divTableCell" id="name6"></div>
<div class = "divTableCell" id="score6"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">7</div>
<div class = "divTableCell" id="name7"></div>
<div class = "divTableCell" id="score7"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">8</div>
<div class = "divTableCell" id="name8"></div>
<div class = "divTableCell" id="score8"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">9</div>
<div class = "divTableCell" id="name9"></div>
<div class = "divTableCell" id="score9"></div>
</div>
<div class = "divTableRow">
<div class = "divTableCell">10</div>
<div class = "divTableCell" id="name10"></div>
<div class = "divTableCell" id="score10"></div>
</div>
</div>
</div>
</div>

</br></br>

<form action="/">
   <center> <input type="submit" value="Back to start" /></center>
</form>

</body>
</html>)=====";

【讨论】:

你能分享一下选择和打印前 10 名球员的代码吗?我正在做类似的事情 @VAAA 当然可以,但是因为我现在不在家,所以只能在大约 10 小时内完成。你已经完成了对数据库的写入?你到底需要什么零件? 非常感谢。我开始添加sqlite。所以真的什么都没有。 @VAAA 完成。希望它有所帮助,我不得不删除代码,因为它包含大量不相关的代码,我无法发布。

以上是关于Arduino - 将高分写入 SD 卡上的 SQLite 数据库的主要内容,如果未能解决你的问题,请参考以下文章

esp32 Arduino SD卡写入文件的问题

如何从 Android API 24+ 在 SD 卡上写入文件

以太网屏蔽arduino上的FTP客户端

如何将 SQLiteOpenHelper 与 sd 卡上的数据库一起使用?

如何将 SD 卡上的 3gp 文件上传到服务器?

Android Dev:从存储在 SD 卡上的临时文件创建位图,设置 ImageView,然后将其存储在本地