ESP32でUDP通信

単純にデータを送信するのと受信するののみを実装してみた。
本来ならUDPなのでパケットロスや受信時は別スレッドでキューに渡してやるとかで実装するべきだが、わかりやすくするためにその辺は省いている。
※arduinoIDEを使う場合は必ずc++ファイルにすること。cとcppファイルで扱いが異なるため。platformioは知らん
```php:simpleUDP.hpp
#ifndef _H_simpleUDP_
#define _H_simpleUDP_

//WIFI関係
#include "WiFi.h"
#include <WiFiUdp.h>

void initUDP();
void openUDP();
void SendUDP(char *str);
void RecvUDP(unsigned long timeout);

#endif
```
```php:simpleUDP.cpp
#include "simpleUDP.hpp"
#include <Arduino.h>
#include "myUtilJson.h"
#include "FS.h"
#include "SD.h"

#define WIFISETTINGFILE "/wifi_setting.json"  //WIFI関係の設定ファイル

// IPAddress ip(192, 168, 1, 30);              //送信元IPアドレス(固定IPアドレス)
// IPAddress gateway(192,168, 1, 1);           //ゲートウェイアドレス
// IPAddress subnet(255, 255, 255, 0);         //サブネットマスク
// IPAddress cl01_ip(192, 168, 1, 70);         //送信先IPアドレス

WiFiUDP UDP;  //UDP

//wifiの初期化
void initWiFi(const char * path)
{
  IPAddress ip;              //送信元IPアドレス(固定IPアドレス)
  IPAddress gateway;         //ゲートウェイアドレス
  IPAddress subnet;         //サブネットマスク
  
  MyUtilJson utiljson;  //json操作クラス
  DynamicJsonDocument doc(1000);

  utiljson.readJson(SD,path,doc);  //送信コマンドjsonファイル読み込み

  const char* clip=doc["cliant"]["ip"]; //送信元IPアドレス
  const char* clsubnet=doc["cliant"]["subnet"]; //サブネットマスク
  const char* clgateway=doc["cliant"]["gateway"]; //ゲートウェイアドレス
  const char* wifi_ssid=doc["wifi"]["ssid"]; //wifi接続先
  const char* wifi_password=doc["wifi"]["password"]; //wifi接続先パスワード

  if(strcmp("no",doc["cliant"]["dhcp"]) == 0)
  {
    //固定IPアドレスの場合
    ip.fromString(clip);
    gateway.fromString(clsubnet);
    subnet.fromString(clgateway);
  }else
  {
    //DHCP使用時
    Serial.println("dhcp+++++++++++++++++");
    //未実装
  }

  WiFi.mode(WIFI_STA);  //無線モード(ルーターを介するやつ)
  WiFi.config(ip, gateway, subnet); //IP等の設定
  WiFi.begin(wifi_ssid, wifi_password); //無線の初期化
}

//UDP初期化
void initUDP()
{
  initWiFi(WIFISETTINGFILE);
  //initWiFi("/display_setting.json");
//  Serial.println(WiFi.localIP());
}

//UDP接続
void openUDP()
{
  //ルーターへの接続
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }

  MyUtilJson utiljson;  //json操作クラス
  DynamicJsonDocument doc(1000);
  
  utiljson.readJson(SD,WIFISETTINGFILE,doc);  //送信コマンドjsonファイル読み込み
//  const int clport=(int)doc["cliant"]["port"]; //送信元IPアドレス

  //UDP.begin(Org_Port);  //UDP通信の開始
  UDP.begin((int)doc["cliant"]["port"]);  //UDP通信の開始
}

//UDP送信
void SendUDP(char *str)
{
  IPAddress server_ip(192, 168, 1, 70);         //送信先IPアドレス

  MyUtilJson utiljson;  //json操作クラス
  DynamicJsonDocument doc(1000);
  
  utiljson.readJson(SD,WIFISETTINGFILE,doc);  //送信コマンドjsonファイル読み込み
  const char* svip=doc["server"]["ip"]; //サーバIP
 // const int svport=doc["server"]["port"]; //サーバポート番号

  server_ip.fromString(svip);

  UDP.beginPacket(server_ip, (int)doc["server"]["port"]);  //パケットの開始
  UDP.print(str); //送信データ書き込み
  UDP.endPacket();  //パケットの終了
}

//UDP受信

void RecvUDP(unsigned long timeout)
{
  char rv_data[50]; //受信バッファ
  int datasize = 0; //受信データサイズ

  unsigned long timestart,timenow = timestart = millis(); //経過時間用
  while( (timenow - timestart) < timeout){
    datasize = UDP.parsePacket();
    if (datasize > 0)  //受信バイト数
    {
      UDP.read(rv_data , datasize);  //UDPデータの取得
      rv_data[datasize] = '\0';
      Serial.print("Recieve : ");
      Serial.println(rv_data);
      UDP.flush();
      break;
    }
    
    timenow = millis();
  }
}
```
json操作はarduinojsonライブラリを使用してます。ライブラリはインストールしておくこと
```php:MyUtilJson.h
#ifndef _H_my_util_json_
#define _H_my_util_json_

#include <Arduino.h>
#include "FS.h"
#include<ArduinoJson.h>

//クラスの定義
class MyUtilJson
{
public:
    void readJson(fs::FS &fs, const char* path,JsonDocument &doc);
private:
    //  void readFile(fs::FS &fs, const char * path,char *buf);
};

#endif
```
```php:MyUtilJson.cpp
#include "myUtilJson.h"

//Jsonファイルの読み込み
void MyUtilJson::readJson(fs::FS &fs,const char *path,JsonDocument &doc)
{  
  /*
   static char json_buf[1000];
   readFile(fs, path,json_buf); //jsonファイル読み込み
Serial.println(path);
Serial.print(json_buf);
*/
  File file = fs.open(path);  //jsonファイルオープン

  //json解析
  // DeserializationError error = deserializeJson(doc, json_buf);  //文字列からデシリアライズ
  DeserializationError error = deserializeJson(doc, file);  //ファイル(Stream)からデシリアライズ
  file.close();
}

//ファイル読み込み
/*
void MyUtilJson::readFile(fs::FS &fs, const char * path,char *buf){
  File file = fs.open(path);
  if(!file || file.isDirectory()){
      Serial.println("- failed to open file for reading");
      return;
  }

  //ファイルの中見をコピー
  int i=0;
  while(file.available())
  {
    *(buf+i) = file.read();
    i++;
  }
  *(buf+i) = '\0';  //終端文字
Serial.println(buf);
  file.close();

  //終端文字書き込まずに読み込みサイズを返すべきな気がする！！！！
}
*/
```
IPとかポートの設定などは外部ファイルからJSON形式で読み込むようにしている。
```php:wifi_setting.json
{
	"cliant": {
		"dhcp": "no",
		"ip": "192.168.1.30",
		"subnet": "255.255.255.0",
		"gateway": "192.168.1.1",
		"port": 50001
	},
	"server": {
		"ip": "192.168.1.70",
		"port": 50007
	},
	"wifi": {
		"ssid": "hogehoge",
		"password": "fugafuga"
	}
}
```