2019年3月27日水曜日

ESP32/arduino : WEBから制御可能なNゲージ用 PWM制御パワーパック_改2

目的:
Nゲージ用 PWM制御パワーパックの改良/機能追加として、以下を行う。
(1) softAP による WiFi設定の対応
(2) 自動走行対応

追加機能:
パワーパック改からの追加機能は、以下の通り。
  1. softAP による WiFi設定の対応
    "softAPでWiFi設定" と同様。
    上記内容に、"戻る"ボタンを追加。
  2. 自動走行対応
    発車ボタン押下で、自動運行設定に従って自動走行を行う。設定項目は、
    加速度
    目標速度
    走行時間
    で、5種類設定可能で、繰り返し実行できる様にする。
    また、設定間は、スイッチ押下で遷移させる事も可能。
    設定は SPIFFS に保存。

パワーパック ハードウェア:
ハードウェア(回路) はパワーパック改と同じ。

WEB画面:
WiFi設定画面 ( WiFi接続先, ESP32 の IPアドレス等を設定する )
 PWPK設定画面 ( 自動運行の設定を行う )
 PWPKメイン画面 ( PWPK の操作画面 )

スケッチ、HTML等 ファイル構成:
HTML, スケッチ共に、だいぶ大きくなってきた為、各ファイルは以下の様に分割。
( ファイルの分割は、まだうまく整理できていない。今後見直し要。
まだ、バグ等があると思われるため、参考にする場合は十分確認願います。)
スケッチの拡張子は全て .ino

HTML     :    MAIN HTML (pwpk.html)
WiFi設定 HTML (wifi_conf.html)
PWPK設定 HTML (pwpk_conf.html)
XHR 応答 HTML (pwpk_resp.html)

スケッチ :    MAIN (変数定義, setup, loop 関数)
WIFI設定 (主に WiFI 設定用 の関数)
PWPK処理 (主に PWPK処理、PWPK 設定用 の関数)

MAIN HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>
       #base          {font-size:16pt; text-align:center; width:600px; border:solid 4px #000000; background-color:#c0c0c0; }
       #radio_box     {font-size:12pt; float:left ;text-align:left; width:30%; margin: 0px 5%  20px 15% ; }
       #dir_box       {font-size:12pt; float:right;text-align:left; width:30%; margin: 0px 15% 20px  5% ; }
       #disp_box      {font-size:12pt; clear:both; text-align:left; margin: 0px 0px 20px  100px ; }
       #pwr_box       {font-size:12pt; text-align:left; margin: 0px 0px 0px 100px ; }
       #slid_box      {font-size:12pt; text-align:left; margin: 10px 0px 10px 50px ; }
       #sw_box        {font-size:12pt; text-align:center; margin: 10px 0% 10px 0% ; }
       #cnfgbtn1      {font-size:12pt; text-align:right ; margin: 0px 5%;width 100%}
       #cnfgbtn2      {font-size:12pt; text-align:right ; margin: 0px 5%;width 100%}
       #footer        {font-size:12pt; clear:both;}
       output.disp    {margin-left:200px; font-size:14pt; }
       input.radio    {margin-left:8px; width:30px;}
       input.dir      {margin-left:8px; width:30px;}
       input.value    {margin-left:100px; width:40px; font-size:12pt; }
       input.setbutton{margin-left:8px; width:40px;}
       input.slider   {margin-left:50px; width:400px;}
       input.button   {margin:0px 13%; width:20%;}
       </style>
 
<title>Power PWN Controller</title></head>
 
<body>
<div id="base">
  <p>運 行 管 理</p>
  <div id="radio_box">
    <form method="get">
      <input class="radio" type="radio" name="remote" id="rad_lo" value="local" $checked_lo onclick="disp_ctrl(this.value); submit(this.value)">制御盤<br>
      <input class="radio" type="radio" name="remote" id="rad_rm" value="remote" $checked_rm onclick="disp_ctrl(this.value); submit(this.value)">遠隔<br>
    </form>
  </div>
  <div id="dir_box">
    <form method="get">
      <input class="dir" type="radio" name="dir" id="dir_fw" value="foward" $checked_fw onclick="submit(this.value)" disabled >前進<br>
      <input class="dir" type="radio" name="dir" id="dir_bw" value="backward" $checked_bw onclick="submit(this.value)" disabled >後退<br>
    </form>
  </div>
  <div id="disp_box">
    <span> 現在出力 </span>
    <output class='disp' id='o1'>
    $pwr
    </output>
  </div>
  <div id="pwr_box">
    <form method="get">
      <span> 出力設定 (0-255)</span>
      <input class='value'  type='text' name='pwr_v' value= $pwr id='pwr_v' disabled>
      <input class='setbutton' type='submit' name='set' id='set' value='SET' disabled>
    </form>
  </div>
  <div id="slid_box">
    <form method='get'>
      <input class='slider' type='range' name='pwr_s' id='pwr_s' value= $pwr min=$pwmin max='255' step='1' disabled
        onchange='setval(this.value);' oninput='setval(this.value)'; onmouseup='submit(this.form)': ontouchend='submit(this.form)'>
    </form>
  </div>
  <div id="sw_box">
    <form method='get'>
        <input class='button' type='submit' name='ready' id='ready' value= '準備/解除'  disabled >
        <input class='button' type='button' name='start' id='start' value= '発車/停車'  onclick='sw_start()' disabled >
    </form>
  </div>
  <div id="cnfgbtn1">
    <form method="get">
      <input type='submit' name='mconf' id='mconf' style="width:100px" value='運行設定画面'>
    </form
  </div>
  <div id="cnfgbtn2">
    <form method="get">
      <input type='submit' name='config' id='config' style="width:100px" value='WiFi設定画面'>
    </form
  </div>
  <div id="footer">
    <br/>
  </div>
</div>
 
 
<script>
var polling = null ;
 
function setval(pwr){
        if (polling == null) clearInterval(polling);
        pollint = null ;
 var xhr = new XMLHttpRequest();
        xhr.open("get", "?slid="+pwr );
        xhr.setRequestHeader('Cache-Control', 'no-cache');
        xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
        xhr.responseType = 'document' ;
 
        xhr.onreadystatechange = function() {
          if( (xhr.readyState == 4) && (xhr.status == 200) ) {
            document.getElementById('pwr_v').value  = parseInt(xhr.response.getElementById("output1").innerHTML) ;
            document.getElementById('o1').innerHTML = xhr.response.getElementById("output1").innerHTML;
          }
        }
 
        ntimeout = function(e) {
          xhr.abort() ;
        }
        xhr.send();
}
 
 
function getval(){
 var xhrget = new XMLHttpRequest();
        xhrget.open("get", "?pol" );
        xhrget.setRequestHeader('Cache-Control', 'no-cache');
        xhrget.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
        xhrget.responseType = 'document' ;
 
        xhrget.onreadystatechange = function() {
          if( (xhrget.readyState == 4) && (xhrget.status == 200) ) {
            document.getElementById('o1').innerHTML = xhrget.response.getElementById("output1").innerHTML;
            document.getElementById('pwr_s').value  = parseInt(xhrget.response.getElementById("output1").innerHTML);
            document.getElementById('pwr_v').value  = parseInt(xhrget.response.getElementById("output1").innerHTML);
          }
        }
 
        ntimeout = function(e) {
          xhrget.abort() ;
        }
        xhrget.send();
}
 
function sw_start() {
        var xhr_start = new XMLHttpRequest();
        xhr_start.open("get", "?start" );
        xhr_start.setRequestHeader('Cache-Control', 'no-cache');
        xhr_start.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
        xhr_start.responseType = 'document' ;
         
        xhr_start.onreadystatechange = function() {
          if( (xhr_start.readyState == 4) && (xhr_start.status == 200) ) {
            if (polling == null) polling = setInterval(getval,100) ;
          }
        }
         
        ntimeout = function(e) {
          xhr_start.abort() ;
        }
        xhr_start.send();
 
}
     
 
function disp_ctrl( radioid ) {
   if(radioid == 'remote') {
      document.getElementById('dir_fw').disabled = false;
      document.getElementById('dir_bw').disabled = false;
      document.getElementById('pwr_v').disabled = false;
      document.getElementById('set').disabled = false;
      document.getElementById('pwr_s').disabled = false;
      document.getElementById('ready').disabled = false;
      document.getElementById('start').disabled = false;
      if (polling == null) clearInterval(polling);
      pollint = null ;
   } else {
      document.getElementById('dir_fw').disabled = true;
      document.getElementById('dir_bw').disabled = true;
      document.getElementById('pwr_v').disabled = true;
      document.getElementById('set').disabled = true;
      document.getElementById('pwr_s').disabled = true;
      document.getElementById('ready').disabled = true;
      if (polling == null) polling = setInterval(getval,100) ;
   }
 
}
 
 
window.onload = function() {
    if(document.getElementById("rad_rm").checked) {
      document.getElementById('dir_fw').disabled = false;
      document.getElementById('dir_bw').disabled = false;
      document.getElementById('pwr_v').disabled = false;
      document.getElementById('set').disabled = false;
      document.getElementById('pwr_s').disabled = false;
      document.getElementById('ready').disabled = false;
      document.getElementById('start').disabled = false;
      if (polling == null) clearInterval(polling);
      pollint = null ;
    } else if(document.getElementById("rad_lo").checked) {
      document.getElementById('dir_fw').disabled = true;
      document.getElementById('dir_bw').disabled = true;
      document.getElementById('pwr_v').disabled = true;
      document.getElementById('set').disabled = true;
      document.getElementById('pwr_s').disabled = true;
      document.getElementById('ready').disabled = true;
      document.getElementById('start').disabled = true;
      polling = setInterval(getval,100) ;
    }
}
 
</script>
 
</body>
</html>

WiFi設定 HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>
    #base         {font-size:16pt; text-align:center; width:600px; border:solid 4px #00000000; background-color:#c0c0c0; }
    #text_box     {height: 25px; font-size:12pt; float:left ; text-align:left; width:45%;}
    #input_box    {height: 25px; font-size:12pt; float:right; text-align:left; width:55%;}
    #ip_box       {height: 25px; font-size:12pt; float:right; text-align:left; width:15%;}
    #radio_box    {font-size:12pt; clear:both; margin : 0% 20% ; width : 60% ;}
    #button       {font-size:12pt; clear:both; width 50%}
    #foot         {font-size:16pt; clear:both;}
    input.val     {width: 90%;}
    input.ip      {width: 20%;}
    input.button  {margin:10px 10% ; width: 25%;}
    input.radio   {margin:10px 0px 0px 15% ; }
</style>
 
<title>設定画面</title></head>
 
<body>
<div id="base">
  <p>設定画面</p>
  <div id="text_box">
    <span> WiFi 接続先 SSID </span>
  </div>
 <form method="get">
  <div id="input_box">
      <input class='val' type='text' name='ssid' id='ssid' value=$ssid>
  </div>
  <div id="text_box">
    <span> WiFi 接続先 PASSWORD </span>
  </div>
  <div id="input_box">
      <input class='val' type='text' name='pass' id='pass' value=$pass>
  </div>
  <div id="text_box">
    <span> WiFi 接続  IP アドレス </span>
  </div>
  <div id="input_box">
      <input class='ip' type='number' name='ip1' id='ip1' min=0 max=255 value=$ip1 >
      <input class='ip' type='number' name='ip2' id='ip2' min=0 max=255 value=$ip2 >
      <input class='ip' type='number' name='ip3' id='ip3' min=0 max=255 value=$ip3 >
      <input class='ip' type='number' name='ip4' id='ip4' min=0 max=255 value=$ip4 >
  </div>
  <div id="text_box">
    <span> WiFi 接続  サブネットマスク</span>
  </div>
  <div id="input_box">
      <input class='ip' type='number' name='sn1' id='sn1' min=0 max=255 value=$sm1 >
      <input class='ip' type='number' name='sn2' id='sn2' min=0 max=255 value=$sm2 >
      <input class='ip' type='number' name='sn3' id='sn3' min=0 max=255 value=$sm3 >
      <input class='ip' type='number' name='sn4' id='sn4' min=0 max=255 value=$sm4 >
  </div>
  <div id="text_box">
    <span> WiFi 接続  デフォルトゲートウェイ</span>
  </div>
  <div id="input_box">
      <input class='ip' type='number' name='gw1' id='gw1' min=0 max=255 value=$gw1 >
      <input class='ip' type='number' name='gw2' id='gw2' min=0 max=255 value=$gw2 >
      <input class='ip' type='number' name='gw3' id='gw3' min=0 max=255 value=$gw3 >
      <input class='ip' type='number' name='gw4' id='gw4' min=0 max=255 value=$gw4 >
  </div>
  <div id="text_box">
    <span> WiFi 接続  DNSアドレス</span>
  </div>
  <div id="input_box">
      <input class='ip' type='number' name='dns1' id='dns1' min=0 max=255 value=$dns1 >
      <input class='ip' type='number' name='dns2' id='dns2' min=0 max=255 value=$dns2 >
      <input class='ip' type='number' name='dns3' id='dns3' min=0 max=255 value=$dns3 >
      <input class='ip' type='number' name='dns4' id='dns4' min=0 max=255 value=$dns4 >
  </div>
  <div id="radio_box">
      <input class='radio' type='radio' name='wifi_stamode' id='rad_sta' value='sta' $checked_sta > STA MODE
      <input class='radio' type='radio' name='wifi_stamode' id='rad_ap' value='ap' $checked_ap > AP MODE
  </div>
  <div id="button">
      <input class='button' type='submit' name='set' id='set' value='設定'>
      <input class='button' type='submit' name='rtn' id='rtn' value='戻る'>
  </div>
 </form>
 <div id="foot">
   <span>$footer</span>
 </div>
</div>
</body>
</html>

PWPK設定 HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>
    #base         {font-size:16pt; text-align:center; width:600px; border:solid 4px #00000000; background-color:#c0c0c0; }
    #item_box     {height:30px; font-size:12pt; text-align:left; }
    #item_0       {font-size:10pt; float:left ; text-align:left; width:20%;  }
    #item_1       {font-size:10pt; float:left ; text-align:center; width:20%;  }
    #item_def     {font-size:10pt; float:left ; text-align:center; width:15.5%; }
    #chec_box     {height:30px; font-size:12pt; cleart:both ;text-align:left;  }
    #conf_box     {height:30px; font-size:12pt; text-align:left;  }
    #button       {font-size:12pt; clear:both; width 50%}
    input.button  {margin:10px 10% ; width: 25%;}
</style>
 
<title>運行設定画面</title></head>
 
<body>
<div id="base">
  <p>設定画面</p>
  <form method="get">
    <div id="chec_box">
      <div id="item_0">
        <span> Loop </span>
        <input type="checkbox" name="loop" id="loop" value="1" $checked_loop autocomplete="off" onclick="disp_ctrl_0(this.checked)" >
      </div>
      <div>
        <span> 回数 </span>
        <input type="number" name="loopnum" id="loopnum" value=$loopnum max="36000"  style="width:80px;" >
      </div>
    </div>
 
    <!-- 項目名の表示 =========================================    -->
    <div id="item_box">
     <div id="item_0"> <span>  </span> </div>
     <div id="item_1"> <span>起点</span> </div>
     <div id="item_def"> <span>加速度</span> </div>
     <div id="item_def"> <span>目標速度</span> </div>
     <div id="item_def"> <span>時間(x0.1秒)</span> </div>
    </div>
 
    <!-- 設定 1 の 入力欄 =====================================    -->
    <div id="conf_box">
      <div id="item_0" >
        <span style="margin-left:25px">  設定1 : </span>
      </div>
      <div id="item_1">
        <span>  </span>
      </div>
      <div id="item_def">
        <input type="number" name="acc1" id="acc1" value=$acc1 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="spd1" id="spd1" value=$spd1 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="tim1" id="tim1" value=$tim1 max="36000" style="width:50px;" >
      </div>
    </div>
 
    <!-- 設定 2 の 入力欄 =====================================    -->
    <div id="conf_box">
      <div id="item_0">
        <input type="checkbox" name="chk2" id="chk2" value="1" $en2 autocomplete="off"  onclick="disp_ctrl_2(this.checked)" >
        <span> 設定2 : </span>
      </div>
      <div id="item_1">
        <select name="trg2" id="trg2" autocomplete="off">
          <option value="0" $trg2_sel0 >前項の続き</option>
     <option value="1" $trg2_sel1 >スイッチ押下</option>
        </select>
      </div>
      <div id="item_def">
        <input type="number" name="acc2" id="acc2" value=$acc2 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="spd2" id="spd2" value=$spd2 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="tim2" id="tim2" value=$tim2 max="36000" style="width:50px;" >
      </div>
    </div>
 
    <!-- 設定 3 の 入力欄 =====================================    -->
    <div id="conf_box">
      <div id="item_0">
        <input type="checkbox" name="chk3" id="chk3" value="1" $en3 autocomplete="off"  onclick="disp_ctrl_3(this.checked)" >
        <span> 設定3 : </span>
      </div>
      <div id="item_1">
        <select name="trg3" id="trg3" autocomplete="off">
          <option value="0" $trg3_sel0>前項の続き</option>
     <option value="1" $trg3_sel1>スイッチ押下</option>
        </select>
      </div>
      <div id="item_def">
        <input type="number" name="acc3" id="acc3" value=$acc3 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="spd3" id="spd3" value=$spd3 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="tim3" id="tim3" value=$tim3 max="36000" style="width:50px;" >
      </div>
    </div>
 
    <!-- 設定 4 の 入力欄 =====================================    -->
    <div id="conf_box">
      <div id="item_0">
        <input type="checkbox" name="chk4" id="chk4" value="1" $en4 autocomplete="off"  onclick="disp_ctrl_4(this.checked)" >
        <span> 設定4 : </span>
      </div>
      <div id="item_1">
        <select name="trg4" id="trg4" autocomplete="off">
          <option value="0" $trg4_sel0>前項の続き</option>
     <option value="1" $trg4_sel1>スイッチ押下</option>
        </select>
      </div>
      <div id="item_def">
        <input type="number" name="acc4" id="acc4" value=$acc4 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="spd4" id="spd4" value=$spd4 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="tim4" id="tim4" value=$tim4 max="36000" style="width:50px;" >
      </div>
    </div>
 
    <!-- 設定 5 の 入力欄 =====================================    -->
    <div id="conf_box">
      <div id="item_0">
        <input type="checkbox" name="chk5" id="chk5" value="1" $en5 autocomplete="off"  onclick="disp_ctrl_5(this.checked)" >
        <span> 設定5 : </span>
      </div>
      <div id="item_1">
        <select name="trg5" id="trg5" autocomplete="off">
          <option value="0" $trg5_sel0>前項の続き</option>
     <option value="1" $trg5_sel1>スイッチ押下</option>
        </select>
      </div>
      <div id="item_def">
        <input type="number" name="acc5" id="acc5" value=$acc5 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="spd5" id="spd5" value=$spd5 max="255" style="width:50px;" >
      </div>
      <div id="item_def">
        <input type="number" name="tim5" id="tim5" value=$tim5 max="36000" style="width:50px;" >
      </div>
    </div>
    <br/>
    <div id="button">
      <input type="submit" name="set" id="set" value="設定" style="width:100px" >
      <input type="checkbox" name="save" id="save" autocomplete="off" >
      <span>ファイルに保存する</span>
      <input type="submit" name="rtn" id="rtn" value="戻る" style="width:100px; margin-left:10%" >
    </div>
  </form>
</div>
 
<!-- JAVA SCRIPT ========================================================= -->
<script>
 
function disp_ctrl_0(enable) {
  if (enable == true) {
    document.getElementById('intval').disabled = false ;
  }else {
    document.getElementById('intval').disabled = true  ;
  }
}
 
function disp_ctrl_2(enable) {
  if (enable == true) {
    document.getElementById('trg2').disabled = false ;
    document.getElementById('acc2').disabled = false ;
    document.getElementById('spd2').disabled = false ;
    document.getElementById('tim2').disabled = false ;
  }else {
    document.getElementById('trg2').disabled = true  ;
    document.getElementById('acc2').disabled = true  ;
    document.getElementById('spd2').disabled = true  ;
    document.getElementById('tim2').disabled = true  ;
  }
}
 
function disp_ctrl_3(enable) {
  if (enable == true) {
    document.getElementById('trg3').disabled = false ;
    document.getElementById('acc3').disabled = false ;
    document.getElementById('spd3').disabled = false ;
    document.getElementById('tim3').disabled = false ;
  }else {
    document.getElementById('trg3').disabled = true  ;
    document.getElementById('acc3').disabled = true  ;
    document.getElementById('spd3').disabled = true  ;
    document.getElementById('tim3').disabled = true  ;
  }
}
 
function disp_ctrl_4(enable) {
  if (enable == true) {
    document.getElementById('trg4').disabled = false ;
    document.getElementById('acc4').disabled = false ;
    document.getElementById('spd4').disabled = false ;
    document.getElementById('tim4').disabled = false ;
  }else {
    document.getElementById('trg4').disabled = true  ;
    document.getElementById('acc4').disabled = true  ;
    document.getElementById('spd4').disabled = true  ;
    document.getElementById('tim4').disabled = true  ;
  }
}
 
function disp_ctrl_5(enable) {
  if (enable == true) {
    document.getElementById('trg5').disabled = false ;
    document.getElementById('acc5').disabled = false ;
    document.getElementById('spd5').disabled = false ;
    document.getElementById('tim5').disabled = false ;
  }else {
    document.getElementById('trg5').disabled = true  ;
    document.getElementById('acc5').disabled = true  ;
    document.getElementById('spd5').disabled = true  ;
    document.getElementById('tim5').disabled = true  ;
  }
}
 
window.onload = function() {
  if(document.getElementById('loop').checked) {
    document.getElementById('intval').disabled = false ;
  }else{
    document.getElementById('intval').disabled = true  ;
  }
  if(document.getElementById('chk2').checked) {
    document.getElementById('trg2').disabled = false ;
    document.getElementById('acc2').disabled = false ;
    document.getElementById('spd2').disabled = false ;
    document.getElementById('tim2').disabled = false ;
  }else{
    document.getElementById('trg2').disabled = true  ;
    document.getElementById('acc2').disabled = true  ;
    document.getElementById('spd2').disabled = true  ;
    document.getElementById('tim2').disabled = true  ;
  }
  if(document.getElementById('chk3').checked) {
    document.getElementById('trg3').disabled = false ;
    document.getElementById('acc3').disabled = false ;
    document.getElementById('spd3').disabled = false ;
    document.getElementById('tim3').disabled = false ;
  }else{
    document.getElementById('trg3').disabled = true  ;
    document.getElementById('acc3').disabled = true  ;
    document.getElementById('spd3').disabled = true  ;
    document.getElementById('tim3').disabled = true  ;
  }
  if(document.getElementById('chk4').checked) {
    document.getElementById('trg4').disabled = false ;
    document.getElementById('acc4').disabled = false ;
    document.getElementById('spd4').disabled = false ;
    document.getElementById('tim4').disabled = false ;
  }else{
    document.getElementById('trg4').disabled = true  ;
    document.getElementById('acc4').disabled = true  ;
    document.getElementById('spd4').disabled = true  ;
    document.getElementById('tim4').disabled = true  ;
  }
  if(document.getElementById('chk5').checked) {
    document.getElementById('trg5').disabled = false ;
    document.getElementById('acc5').disabled = false ;
    document.getElementById('spd5').disabled = false ;
    document.getElementById('tim5').disabled = false ;
  }else{
    document.getElementById('trg5').disabled = true  ;
    document.getElementById('acc5').disabled = true  ;
    document.getElementById('spd5').disabled = true  ;
    document.getElementById('tim5').disabled = true  ;
  }
}
</script>
 
</body>
</html>

XHR 応答 HTML
1
2
3
4
5
6
7
<!DOCTYPE html><html lang='ja'>
  <head> <title>Color LED Controller</title></head>
  <body>
 
    <output id='output1'> $pwr</output>
 
  </body> </html>

MAIN スケッチ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#include <WiFi.h>                         // WiFi 使用の為
#include "FS.h"                           // SPIFFS 使用の為
#include "SPIFFS.h"                       // SPIFFS 使用の為
#include <Ticker.h>
 
//#define DEBUG_HTML                        // Debug用 Serial 表示制御用
//#define DEBUG                             // Debug用 Serial 表示制御用
 
// ---------------------------------------------------------------------------
// | WiFi 設定用 定義                                                        |
// ---------------------------------------------------------------------------
// AP モード用 WIFI 設定 -----------------------------------------------------
const char ssid[] = "ESP32_AP";           // SSID for softAP
const char pass[] = "password";           // password for softAP
const IPAddress ip(192, 168, 4, 1);       // IPアドレス for softAP
const IPAddress subnet(255, 255, 255, 0); // サブネットマスク for softAP
 
// STA モード用 WiFi設定 ------------------------------------------------------
String s_config ;                         // 設定ファイル用 String
char wifi_ssid[128] = "" ;                // SSID        for WiFi STA
char wifi_pass[128] = "" ;                // password    for WiFi STA
IPAddress wifi_ip(192,168,1,66) ;         // IP Address  for WiFi STA
IPAddress wifi_gw(192,168,1,1)  ;         // gate way    for WiFi STA
IPAddress wifi_sm(255,255,255,0) ;        // subnet mask for WiFi STA
IPAddress wifi_dns(192,168,1,1) ;         // dns address for WiFi STA
char wifi_mode[16] = ""   ;               // wifi mode
String foot_msg ="" ;                     // リブートメッセージ用
 
WiFiServer server(80);
 
// 動作モードフラグ -----------------------------------------------------------
#define WIFI_CONF   0                     //  html モード用定義
#define MAIN        1                     //
#define MAIN_CONF   2                     //
 
bool stamode = true ;                     // WiFi STA 接続モード : true
bool sta_exec = false ;                   // WiFi STA接続モード実行中フラグ
int  html_mode = MAIN ;                   // WiFi設定モード ; true
int  html_exec = MAIN ;                   // WiFi設定実行中フラグ
 
// -----------------------------------------------------------------------------
// | HTML ファイル名等                                                         |
// -----------------------------------------------------------------------------
const char fname_CONF[] = "/wifi_conf.html" // WiFi 設定用 HTML ファイル名
const char fname_MAIN[] = "/pwpk.html"   ;     // メイン HTML ファイル名
const char fname_RESP[] = "/pwpk_resp.html" // XHR レスポンス HTML ファイル名
const char fname_MCONF[] = "/pwpk_conf.html"// メイン設定用 HTML ファイル名
   
String html_CONF ;                             // 設定用 HTML 格納用
String html_pwpk ;                             // メイン HTML 格納用
String html_resp ;                             // XHR 応答用 HTML 格納用
String html_MCONF ;                            // メイン設定用 HTML 格納用
 
// -----------------------------------------------------------------------------
// - PWPK処理用                                                                -
// -----------------------------------------------------------------------------
// 運行設定用 変数定義 --------------------------------------------------------
String   m_config ;                   // 設定ファイル用 String
 
int      prg_tbl[6][5] =     // 運行設定
          { {0,1,0,0,0},     // prg_loop,prg_loop_intval, resrv,reserv,reserv,
            {1,0,5,145,0},   // prt_1_en,reserv,   prg_1_acc,prt_1_spd,prg_1_tim,
            {0,0,0,0,0},     // prt_2_en,prg_2_trg,prg_2_acc,prg_2_spd,prg_2_tim,
            {0,0,0,0,0},     // prt_3_en,prg_3_trg,prg_3_acc,prg_3_spd,prg_3_tim,
            {0,0,0,0,0},     // prt_4_en,prg_4_trg,prg_4_acc,prg_4_spd,prg_4_tim,
            {0,0,0,0,0} } ;  // prt_5_en,prg_5_trg,prg_5_acc,prg_5_spd,prg_5_tim,
       
 
// グローバル変数定義 ---------------------------------------------------------
bool     local      = true   ;        // local フラグ
bool     localen    = false  ;        // 制御盤操作許可
byte     duty       = 0      ;        // PWM デューティ設定 (0~255)
int      loopcnt    = 0      ;        // 定期割り込み回数カウント用
bool     ticker_val = false  ;        // 定期割り込みフラグ
bool     pre_strt   = false  ;        // 発車要求スイッチ状態保持用
bool     start_sw   = false  ;        // 発車要求スイッチ押下検出
bool     running    = false  ;        // 走行中フラグ
int      base       = 25     ;        // 準備時 (LED点灯時) の duty 値
int      target     = 145    ;        // 目標デューティ
int      rate       = 5      ;        // 増減速の割合 (1/10 S 当たりの 増加 duty値)
unsigned long start_time = 0 ;        // 開始時刻
unsigned long now_time = 0 ;          // 現在時刻
 
//  ( 制御盤/WEB 操作情報用 ) --------
int      vol_value  = 0      ;        // 制御盤ボリューム値 (0~4095)
int      base_val   = 0      ;        // 最低速度時のDuty 値
bool     dir_bkwd   = false  ;        // 進行方向フラグ
bool     dir_change = false  ;        // 進行方向変化フラグ
bool     pre_rdy    = false  ;        // 準備要求スイッチ状態保持用
bool     ready      = false  ;        // 準備要求フラグ ( LED 常時点灯要求)
bool     rdy_change = false  ;        // 準備要求状態変化
 
//  ( 自動運転用 ) -------------------
bool     prg_run    = false  ;        // 自動運行実行中
bool     prg_start  = false  ;        // 自動運行開始指示
bool     prg_next   = false  ;        // 自動運行設定更新指示
int      prg_no     = 0      ;        // 実行中の運行設定 No.
int      nextno     = 0      ;        // 次の運行設定 No.
int      prg_tim    = 0      ;        // 運行時間
int      prg_loopnum= 1      ;        // 自動運行繰り返し回数
bool     start      = false  ;        // 発車要求フラグ
bool     stop       = false  ;        // 停車要求フラグ
bool     autorun    = false  ;        // 自動走行中フラグ
bool     wait_sw    = false  ;        // STARTスイッチ待ち
bool     time_ovr   = false  ;        // 運行時間オーバー
 
//  ( LED 制御用 ) -------------------
bool     st_blink   = false  ;        // ステータス 点滅
int      st_bl_intvl= 0      ;        // ステータス 点滅間隔
int      st_bl_cnt  = 0      ;        // ステータス 点滅時 カウント値
bool     st_bl_off  = false  ;        // ステータス 点滅時 OFF 状態
bool     st_on      = false  ;        // ステータス 点灯
int      st_val     = 0      ;        // ステータス値
 
 
Ticker ticker;
 
// ------ Define for IO Port --------------------------------------------------
#define PWR_VOL   A7                  // ADC1 A7 (IO35)
#define PWR_OUT    2                  // Degital Output IO2
#define DIR_OUT    4                  // Degital Output IO4 (0:FWD,1:BWD)
#define SW_FWD    27                  // Degital Input  IO27
#define SW_BWD    14                  // Degital Input  IO14   
#define SW_READY  13                  // Degital Input  IO13
#define SW_START  16                  // Degital Input  IO16
#define LED_FWD   17                  // Degital Output IO17
#define LED_BWD   12                  // Degital Output IO12
#define LED_ST1   23                  // Degital Output IO23
#define LED_ST2   19                  // Degital Output IO19
#define LED_ST3   18                  // Degital Output IO18
 
// ----- Define for LEDC ------------------------------------------------------
#define PWM_FEQ   20000
#define DUTY_bw   8
 
// -----------------------------------------------------------------------------
//  arduino 初期化処理                                                        --
// -----------------------------------------------------------------------------
void setup() {
  int res = 0 ;                                // 結果格納用 (ワーク)
 
    pinMode(PWR_OUT,OUTPUT) ;         // Set pin mode for SPEED control
    pinMode(DIR_OUT,OUTPUT) ;         // Set pin mode for Dirction control
    pinMode(LED_FWD,OUTPUT) ;         // Set pin mode for Forward LED
    pinMode(LED_BWD,OUTPUT) ;         // Set pin mode for Backward LED
    pinMode(LED_ST1,OUTPUT) ;         // Set pin mode for status 1 LED
    pinMode(LED_ST2,OUTPUT) ;         // Set pin mode for status 2 LED
    pinMode(LED_ST3,OUTPUT) ;         // Set pin mode for status 3 LED
 
    // セットアップ中、LED を点灯させる
    digitalWrite(LED_FWD,1) ;
    digitalWrite(LED_BWD,1) ;
    digitalWrite(LED_ST1,1) ;
    digitalWrite(LED_ST2,1) ;
    digitalWrite(LED_ST3,1) ;
 
Serial.begin(115200);                        // シリアル 開始
  SPIFFS.begin(true) ;                         // SPIFFS 開始
 
  // 初期設定用 HTML ファイルの読み込み ---------------------------------------
  res = rd_SPIFFS(fname_CONF,html_CONF) ;    // html_CONF に html を格納
 
  // 本体 HTML ファイルの読み込み ----------------------------------------------
  res = rd_SPIFFS(fname_MAIN,html_pwpk) ;    // html_pwpk に html を格納
   
  // XHR 応答ファイルの読み込み ------------------------------------
  res = rd_SPIFFS(fname_RESP,html_resp) ;    // html_resp に html を格納
 
  // メイン用設定 HTML ファイルの読み込み -------------------------------------
  res = rd_SPIFFS(fname_MCONF,html_MCONF) ;  // html_MCONF に html を格納
 
  // wifi 初期設定ファイルを読み込み、変数に格納し、wifi,画面モードを決定 -----
  res = rd_config() ;                          //
 
  // wifiモード(stamode) に応じて AP か STA かを選択してサーバー起動 ----------
  if (stamode == false) {               // APモードの場合 softAP WiFi 開始
    start_AP_server() ;                 // APモードでサーバー起動
    sta_exec = false ;                  //
  } else {                              // STAモードの場合 Wifi 開始
    start_STA_server() ;                // APモードでサーバー起動
    sta_exec = true ;                   //
  }                                     //
 
  // 実行中のモード (設定かメインか) を設定 ------------------------------------
  html_exec = html_mode ;               // 実行中の html_mode を 設定
 
  Serial.println("Server start!");
 
  // for PWM Control ===========================================================
 
  // メイン設定ファイルを読み込み、変数に格納する ------------------------------
  res = rd_mainconf() ;
 
  // ledc 設定 -----------------------------------------------------------------
  ledcSetup(0, PWM_FEQ, DUTY_bw);    // setup channel 0 with frequency 5000 Hz,
                                     // 8 bit precission for LEDC timer
  ledcAttachPin(PWR_OUT,0);          // attach pin 2 to channel 0
  ledcWrite(0, 0);                   // initialize channel 0 to off    
 
  // LED を初期状態に設定。 ----------------------------------------------------
  digitalWrite(LED_FWD,1) ;
  digitalWrite(LED_BWD,0) ;
  digitalWrite(LED_ST1,0) ;
  digitalWrite(LED_ST2,0) ;
  digitalWrite(LED_ST3,0) ;
 
  // 周期割り込みを開始 --------------------------------------------------------
  ticker.attach_ms(100, execTicker) ; // 割り込み間隔と割り込み処理を設定。
 
}
// -----------------------------------------------------------------------------
 
 
// -----------------------------------------------------------------------------
//  arduino メインループ処理                                                  --
// -----------------------------------------------------------------------------
void loop() {
  WiFiClient client = server.available();
  String htmlwk = "" ;                            // html 用 ワーク変数
  String line   = "" ;                            // クライアントからの入力用
  int xhr = 0 ;                                   //
  
  if (ticker_val) {      // 定期割込みフラグが true だったら、定期処理を実行。
     do_JOB() ;
  }
 
  // HTML クライアント処理 ------------------------------------------------------
  if (client) {
    # ifdef DEBUG_HTML
      Serial.println(" +++++++++++++++++ new client! +++++++++++++++++ ");
    # endif                                   //
    while (client.connected()) {                  // クライアントから接続されたとき
      if (client.available()) {                   //
        line = client.readStringUntil('\n');      // 1行分取得
 # ifdef DEBUG_HTML                        //
          Serial.println(line) ;                  //
 # endif                                   //
 if (line.indexOf("GET /?") != -1) {       // GET 処理
   if (html_mode == WIFI_CONF){            // 初期設定用 フォームデータ処理
     set_form2param(line) ;                //   フォームデータを変数に格納
   }else if (html_mode == MAIN_CONF) {     //
     set_mconf2param(line) ;               //   フォームデータを変数に格納
          } else {                                // メイン用 処理
     xhr = proc_main(line) ;               //   フォームデータのメイン処理
   }                                       //
 }                                         //
        // 最終行(空行)を受信した時 -------------------------------------------
        if (line.length() == 1 && line[0] == '\r'){  // 最終行判定
   if (stamode != sta_exec) {         // sta_mode が変わった場合
     if (strcmp(wifi_mode,"ap") == 0){    //  リブートメッセージを設定
       foot_msg = "アクセスポイントモードに移行します。<br>" ;
       foot_msg += "この画面を閉じてアクセスポイントに接続して下さい。" ;
     }else{
       foot_msg = "ステーションモードに移行します。<br>";
       foot_msg += "この画面を閉じて 設定したアドレスに接続して下さい。" ;
     }
            if (html_exec == WIFI_CONF) {         //   初期設定中なら
              send_CONF_html(client) ;            //     初期設定 HTML 送信
     } else {                              //   メイン画面なら
              send_MAIN_html(client) ;            //     メイン HTML 送信
       html_exec = MAIN ;                  //
     }                                     //    ( その後 リブート)
          } else {                                // sta_mode が変わらない場合
            if (xhr) {
              send_resp_html(client) ;            //     メイン HTML 送信
 
            } else if (html_mode == WIFI_CONF) {    //   次に初期設定を表示するなら
              send_CONF_html(client) ;            //     初期設定 HTML 送信
     } else if (html_mode == MAIN_CONF) {  //   次にメイン画面なら
              send_MCONF_html(client) ;           //     メイン設定 HTML 送信
            } else {                              //    メイン設定画面A
              send_MAIN_html(client) ;            //     メイン HTML 送信
            }                                     //
     html_exec = html_mode ;               //
   }                                       //
   # ifdef DEBUG_HTML                      //
     Serial.println("Send HTML") ;         //
   # endif                                 //
          break ;                                 // ループ終了
        }                                         //
 //-------------------------------------------------------------------
      }
    }
    // 接続が切れた場合 ------------------------------------------------------
    client.stop();
    # ifdef DEBUG_HTML                        //
      Serial.println("client disonnected");
      Serial.println("----------------------------------------------------");
    # endif
  }
 
  if (stamode != sta_exec) {                      // sta_mode が変わった場合
    Serial.println("------------------- リブートします------------------- ");
    delay(500);                                   //
    ESP.restart() ;                               // リブート
  } else {
  }
  // --------------------------------------------------------------------------
 
}

WIFI設定 スケッチ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// *****************************************************************************
// *  初期設定ファイル をリードし、グローバル変数に値をセットする              *
// *****************************************************************************
int rd_config() {                                //
  File fp       ;                                // 設定ファイル用ファイルポインタ
  int result = 0 ;                               // 戻り値
                                                 //
  if (SPIFFS.exists("/config.txt")) {            // 設定ファイル存在確認
    // ファイルがあった場合 ---------------------//
    result = rd_SPIFFS("/config.txt",s_config) ; // s_config に config.txt を格納
  } else {                                       //
    // ファイルが無かった場合 -------------------//
    Serial.println("WiFi設定ファイルなし") ;     // 無かったら、APモード
    result = -1 ;                                //
  }                                              //
 
  // ファイルが読み込めたら、グローバル変数にセットする
  if (result == 0)                               //
    # ifdef DEBUG                                // デバッグ用表示
      Serial.println("--- s_config --- ") ;      //
      Serial.println(s_config ) ;                //
    # endif                                      //
    set_conf2wifiparam() ;                       // s_config の内容を変数に設定
  // 初期設定ファイルの状態で wifiモード, 画面モードを設定 ----------------------
  if (result != -1) {                          // 変数に設定できた場合
    if (( strcmp(wifi_ssid,"") ==0) || (strcmp(wifi_pass,"") ==0)) {
                                               // ssid,pass 設定なければ
      stamode = false ;                        //   APモード
      if ( strcmp(wifi_mode,"ap") == 0){       // wifi_mode が "ap" なら
        html_mode = MAIN ;                     //   メイン画面
        Serial.println("set html_mode (rd_config) : MAIN") ;
      }else{                                   // wifi_mode が "ap" でなければ
        html_mode = WIFI_CONF ;                //   初期設定画面
        Serial.println("set html_mode (rd_config) : WIFI_CONF") ;
      }
    } else {                                   // ssid,pass の設定があれば、
      html_mode = MAIN ;                       //   メイン画面
      if ( strcmp(wifi_mode,"ap") == 0)        // wifi_mode が "ap" なら
        stamode = false ;                      //   APモード
      else                                     // "ap" でなければ
        stamode = true  ;                      //   STAモード
    }
  } else {                                     // 変数に設定できなかった場合
    stamode = false ;                          //   APモード
    html_mode = WIFI_CONF ;                    //   初期設定画面
  }
 
  return result ;                              //
}
 
// ----------------------------------------------------------------------------
// - 設定ファイルの内容を グローバル変数に 設定する                           -
// ----------------------------------------------------------------------------
void set_conf2wifiparam() {
  int    pos = 0 ;
  int    npos = 0 ;
  String s_work ;
  String s_name ;
  String s_data ;
  // 記載内容を順次処理 ( 設定情報を取り出し、グローバル変数に設定する ) ------
  while(1) {
    if (s_config.charAt(pos) == '/') {         // 先頭が '/' なら 次の行へ
      npos = s_config.indexOf('\n',pos) ;      //
      pos = npos + 1 ;                         //
    } else {                                   //
      npos = s_config.indexOf(':',pos) ;       // ':' までの文字をs_name に取得
      if (npos == -1) break ;                  //   見つからなければ終了
      s_name = s_config.substring(pos,npos) ;  //
      s_name.trim() ;                          //
      pos = npos+1 ;                           // ポインタを ':' の次へ
      npos = s_config.indexOf('\n',pos) ;      // '\n' までの文字をs_data に取得
      if (npos == -1) npos = s_config.length() ;  //
      s_data = s_config.substring(pos,npos) ;  //
      s_data.trim() ;                          //
      pos = npos+1 ;                           //
      set_wifiparam(s_name,s_data) ;           // 取得した内容をグローバル変数に設定
    }                                          //
  }                                            //
}                                              //
 
// - 設定内容を判定し、グローバル変数に設定 ------------------------------------
void set_wifiparam(String &name, String &data) {   //
  if (name.compareTo("wifi_ssid")==0) {        // 'wifi_ssid' の場合
    data.toCharArray(wifi_ssid,128) ;          //
  }                                            //
  if (name.compareTo("wifi_pass")==0) {        // 'wifi_pass' の場合
    data.toCharArray(wifi_pass,128) ;          //
  }                                            //
  if (name.compareTo("wifi_ip")==0) {          // 'wifi_ip' の場合
    wifi_ip = stoip(data) ;                    //  取得情報(文字列)をIPAddressに変換
  }                                            //
  if (name.compareTo("wifi_gw")==0) {          // 'wifi_gw' の場合
    wifi_gw = stoip(data) ;                    //
  }                                            //
  if (name.compareTo("wifi_sm")==0) {          // 'wifi_sm' の場合
    wifi_sm = stoip(data) ;                    //
  }                                            //
  if (name.compareTo("wifi_dns")==0) {         // 'wifi_dns' の場合
    wifi_dns = stoip(data) ;                   //
  }                                            //
  if (name.compareTo("wifi_mode")==0) {        // 'wifi_mode' の場合
    data.toCharArray(wifi_mode,16) ;           //
  }                                            //
}                                              //
 
// - 文字列 から IPAddress へ変換 ----------------------------------------------
IPAddress stoip(String &data) {                 //
  IPAddress ip ;
  String num = "" ;
  int pos = 0 ;
  while(data.charAt(pos) != '.') {             // 先頭から '.' までの文字を取得
    num += data.charAt(pos++) ;                //
  }                                            //
  ip[0] = num.toInt() ;                        // 数値に変換して 第1オクテット に 代入
  pos++ ;                                      // '.' の次から
  num="";                                      //
  while(data.charAt(pos) != '.') {             // '.' までの文字を取得
    num += data.charAt(pos++) ;                //
  }                                            //
  ip[1] = num.toInt() ;                        // 数値に変換して 第2オクテットに代入
  pos++ ;                                      // '.' の次から
  num="";                                      //
  while(data.charAt(pos) != '.') {             // '.' までの文字を取得
    num += data.charAt(pos++) ;                //
  }                                            //
  ip[2] = num.toInt() ;                        //
  pos++ ;                                      // '.' の次から
  num="";                                      //
  while(data.charAt(pos) != '.') {             // '.' または 最後まで の 文字を取得
    num += data.charAt(pos++) ;                //
    if (pos > data.length()) break ;           //
  }                                            //
  ip[3] = num.toInt() ;                        // 数値に変換して 第4オクテットに代入
                                               //
  return ip ;                                  // IPAddress を戻り値とする
}                                              //
 
// ****************************************************************************
// * アクセスポイント モードで サーバーを起動                                 *
// ****************************************************************************
void start_AP_server() {
  Serial.println(" AP Server exec") ;
  WiFi.softAP(ssid, pass);             // SSIDとパスの設定
  delay(100);                          // delayが必要
  WiFi.softAPConfig(ip, ip, subnet);   // IP address, gateway, subnetmask の設定
  IPAddress myIP = WiFi.softAPIP();    // WiFi.softAPIP()でWiFi起動
  server.begin();                      // サーバーを起動(htmlを表示させるため)
}
 
// ****************************************************************************
// * デバッグ表示用                                                           *
// ****************************************************************************
void disp_mode() {
  # ifdef DEBUG_HTML                              // デバッグ用表示
    Serial.print("html_mode - exec : ") ;         // 設定画面か メイン画面か
    if (html_mode == WIFI_CONF)                   // 変数の状態と実行状況を表示
      Serial.print("WiFi Config MODE - ") ;       //
    else                                          //
      Serial.print("Main MODE - ") ;              //
    if (html_exec == WIFI_CONF)                   //
      Serial.println("WiFi Config MODE") ;        //
    else                                          //
      Serial.println("Main MODE") ;               //
                                                  //
    Serial.print("wifi_mode - exec   : ") ;       // Wifi モードを
    if (stamode)                                  // 変数の状態と実行状況を表示
      Serial.print("STA - ") ;                    //
    else                                          //
      Serial.print("AP - ") ;                     //
    if (sta_exec)                                 //
      Serial.println("STA") ;                     //
    else                                          //
      Serial.println("AP") ;                      //
  # endif                                         //
}
 
// ****************************************************************************
// * クライアントからのフォームデータを変数にセットし、設定ファイルに書き出す *
// ****************************************************************************
void set_form2param(String &line) {
  String s_work ="" ;
 
  if (line.indexOf("set=") != -1) {               // stamode set
    // クライアントからのデータを グローバル変数にセットする。 ------------------
    if (line.indexOf("GET /?ssid=") != -1) {      // wifi_ssid
      s_work = getvalue_s(line,"?ssid=") ;        //   ssid に続く文字列を取得
      s_work.toCharArray(wifi_ssid,128) ;         //   変数にセット
    }
    if (line.indexOf("pass=") != -1) {            // wifi_pass
      s_work = getvalue_s(line,"pass=") ;         //   pass に続く文字列を取得
      s_work.toCharArray(wifi_pass,128) ;         //   変数にセット
    }
    if (line.indexOf("ip1=") != -1) {             // wifi_ip
      wifi_ip[0] = getvalue_i(line,"ip1=") ;      //   ip1 に続く数値を変数にセット
    }
    if (line.indexOf("ip2=") != -1) {             //
      wifi_ip[1] = getvalue_i(line,"ip2=") ;      //   ip2 に続く数値を変数にセット
    }
    if (line.indexOf("ip3=") != -1) {             //
      wifi_ip[2] = getvalue_i(line,"ip3=") ;      //   ip3 に続く数値を変数にセット
    }
    if (line.indexOf("ip4=") != -1) {             //
      wifi_ip[3] = getvalue_i(line,"ip4=") ;      //   ip4 に続く数値を変数にセット
    }
    if (line.indexOf("gw1=") != -1) {             // wifi_gw
      wifi_gw[0] = getvalue_i(line,"gw1=") ;      //   gw1 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("gw2=") != -1) {             //                      
      wifi_gw[1] = getvalue_i(line,"gw2=") ;      //   gw2 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("gw3=") != -1) {             //                      
      wifi_gw[2] = getvalue_i(line,"gw3=") ;      //   gw3 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("gw4=") != -1) {             //                      
      wifi_gw[3] = getvalue_i(line,"gw4=") ;      //   gw4 に続く数値を変数にセット
    }
    if (line.indexOf("sm1=") != -1) {             // wifi_sm
      wifi_sm[0] = getvalue_i(line,"sm1=") ;      //   sm1 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("sm2=") != -1) {             //                      
      wifi_sm[1] = getvalue_i(line,"sm2=") ;      //   sm2 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("sm3=") != -1) {             //                      
      wifi_sm[2] = getvalue_i(line,"sm3=") ;      //   sm3 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("sm4=") != -1) {             //                      
      wifi_sm[3] = getvalue_i(line,"sm4=") ;      //   sm4 に続く数値を変数にセット
    }
    if (line.indexOf("dns1=") != -1) {            // wifi_dns
      wifi_dns[0] = getvalue_i(line,"dns1=") ;    //   dns1 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("dns2=") != -1) {            //                      
      wifi_dns[1] = getvalue_i(line,"dns2=") ;    //   dns2 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("dns3=") != -1) {            //                      
      wifi_dns[2] = getvalue_i(line,"dns3=") ;    //   dns3 に続く数値を変数にセット
    }                                                                     
    if (line.indexOf("dns4=") != -1) {            //                      
      wifi_dns[3] = getvalue_i(line,"dns4=") ;    //   dns4 に続く数値を変数にセット
    }
    if (line.indexOf("stamode=") != -1) {         // stamode set
      s_work = getvalue_s(line,"stamode=") ;      //   ssid に続く文字列を取得
      s_work.toCharArray(wifi_mode,16) ;          //   変数にセット
      if (s_work == "sta") {                      //   設定値により、モードをセット
        stamode = true ;                          //
        html_mode = MAIN ;                        //
      } else {                                    //
        stamode = false ;                         //
        html_mode = MAIN  ;                       //
      }
    }
    Serial.print("html_mode(set_form2param) :") ;
    Serial.println(html_mode) ;
    // グローバル変数を 設定ファイルに書き出す -----------------------------------
    wr_wificonfig() ;                             // 設定を初期設定ファイルに書き出し
  }
  if (line.indexOf("rtn=") != -1) {               // stamode set
    html_mode = MAIN ;
  }
 
}
 
// 要素名に続く値(文字列)を取得する --------------------------------------------
String getvalue_s(String &line,String param) {
  String val="" ;
  int pos = 0 ;
 
  if ((pos=line.indexOf(param)) != -1) {          // 要素名の位置を取得
    pos += param.length() ;                       //
    while(    (line.charAt(pos) != '&' )
            & (line.charAt(pos) != ' ' )
            & (line.charAt(pos) != '\n')  ) {
      val += line.charAt(pos++) ;                 //  '&' か 行末 まで文字を取得
    }                                             //
  }                                               //
  return val ;                                    //  取得した文字列を返す
}
 
// 要素名に続く値(数値)を取得する ---------------------------------------------
int getvalue_i(String &line,String param) {
  String val="" ;
  int pos = 0 ;
 
  if ((pos=line.indexOf(param)) != -1) {          // 要素名の位置を取得
    pos += param.length() ;                       //
    while((line.charAt(pos) >= '0') & (line.charAt(pos) <= '9')) {
      val += line.charAt(pos++) ;                 //  数値でなくなるまで文字を
    }                                             //  取得
  }                                               //
  return val.toInt() ;                            //  数値に変換して返す
}
 
// -----------------------------------------------------------------------------
// - グローバル変数の内容を設定ファイルに書き出す                              -
// -----------------------------------------------------------------------------
void wr_wificonfig() {
  char s_work[128] ;
  File fp ;
 
  // String に 変数の内容を書き込む -------------------------------------------
  sprintf(s_work,"wifi_ssid : %s\n",wifi_ssid) ;  //
  s_config = String(s_work) ;                     //
  sprintf(s_work,"wifi_pass : %s\n",wifi_pass) ;  //
  s_config += String(s_work) ;                    //
  sprintf(s_work,"wifi_ip   : %3d.%3d.%3d.%3d\n",wifi_ip[0],wifi_ip[1],wifi_ip[2],wifi_ip[3]) ;
  s_config += String(s_work) ;                    //
  sprintf(s_work,"wifi_sm   : %3d.%3d.%3d.%3d\n",wifi_sm[0],wifi_sm[1],wifi_sm[2],wifi_sm[3]) ;
  s_config += String(s_work) ;                    //
  sprintf(s_work,"wifi_gw   : %3d.%3d.%3d.%3d\n",wifi_gw[0],wifi_gw[1],wifi_gw[2],wifi_gw[3]) ;
  s_config += String(s_work) ;                    //
  sprintf(s_work,"wifi_dns  : %3d.%3d.%3d.%3d\n",wifi_dns[0],wifi_dns[1],wifi_dns[2],wifi_dns[3]) ;
  s_config += String(s_work) ;                    //
  sprintf(s_work,"wifi_mode : %s\n",wifi_mode) ;  //
  s_config += String(s_work) ;                    //
 
  // 設定ファイルに書き込む ----------------------------------------------------
  fp = SPIFFS.open("/config.txt",FILE_WRITE) ;    // 設定ファイルを開く
  if (!fp) {
    Serial.println(" 設定ファイル オープンエラー !!") ;
  } else {
    // 初期設定ファイル書き込み -------------------------------------------------
    if(fp.print(s_config)) {                      // ファイルに書き込み
      Serial.println("s_config written") ;        //   終了メッセージ
    } else {                                      //
      Serial.println("s_config write error !!") ; //   失敗メッセージ
    }                                             //
    fp.close() ;                                  // ファイルクローズ
  }                                               //
                                                  //
}                                                 //
 
// *****************************************************************************
// * HTML 送信処理                                                             *
// *****************************************************************************
 
// ----------------------------------------------------------------------------
// - CONF_HTML 送信  -----------------------------------------------------------
// ----------------------------------------------------------------------------
void  send_CONF_html(WiFiClient client) {
  String htmlwk ;
 
  // 変数置換え処理 ------------------------------------------------------------
  htmlwk = html_CONF ;
  htmlwk.replace("$ssid",String(wifi_ssid)) ;
  htmlwk.replace("$pass",String(wifi_pass)) ;
  htmlwk.replace("$ip1",String(wifi_ip[0])) ;
  htmlwk.replace("$ip2",String(wifi_ip[1])) ;
  htmlwk.replace("$ip3",String(wifi_ip[2])) ;
  htmlwk.replace("$ip4",String(wifi_ip[3])) ;
  htmlwk.replace("$sm1",String(wifi_sm[0])) ;
  htmlwk.replace("$sm2",String(wifi_sm[1])) ;
  htmlwk.replace("$sm3",String(wifi_sm[2])) ;
  htmlwk.replace("$sm4",String(wifi_sm[3])) ;
  htmlwk.replace("$gw1",String(wifi_gw[0])) ;
  htmlwk.replace("$gw2",String(wifi_gw[1])) ;
  htmlwk.replace("$gw3",String(wifi_gw[2])) ;
  htmlwk.replace("$gw4",String(wifi_gw[3])) ;
  htmlwk.replace("$dns1",String(wifi_dns[0])) ;
  htmlwk.replace("$dns2",String(wifi_dns[1])) ;
  htmlwk.replace("$dns3",String(wifi_dns[2])) ;
  htmlwk.replace("$dns4",String(wifi_dns[3])) ;
  if (stamode) {                                // ステーションモード時
    htmlwk.replace("$checked_sta","checked") ;  //
    htmlwk.replace("$checked_ap","") ;          //
  } else {                                      // アクセスポイントモード時
    htmlwk.replace("$checked_sta","") ;         //
    htmlwk.replace("$checked_ap","checked") ;   //
  }
  htmlwk.replace("$footer",foot_msg ) ;
  // --------------------------------------------------------------------------
 
  send_html(client,htmlwk) ;                       // HTML 送信処理
}

PWPK処理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
// *****************************************************************************
// * SPIFFS ファイルを String に読み込む                                       *
// *****************************************************************************
int rd_SPIFFS(String fname, String &sname) {     //
  File fp = SPIFFS.open(fname,"r") ;             // ファイルをオープンする
  if (!fp) {                                     //  オープン失敗の場合
    Serial.print(fname) ;                        //
    Serial.println(" : file open error") ;       //
    return -1 ;                                  //    戻り値 -1
  }else {                                        //  オープン出来たら
    sname = fp.readString() ;                    //    String変数に読み込む
    fp.close() ;                                 //
  }                                              //
  return 0 ;                                     //  オープン出来た時のみ
}                                                //    戻り値 0
                                                 //
// *****************************************************************************
// *  メイン用初期設定ファイル をリードし、グローバル変数に値をセットする      *
// *****************************************************************************
int rd_mainconf() {                              //
  File fp       ;                                // 設定ファイル用ファイルポインタ
  int result = 0 ;                               // 戻り値
                                                 //
  if (SPIFFS.exists("/mconf.txt")) {             // 設定ファイル存在確認
    // ファイルがあった場合 ---------------------//
    result = rd_SPIFFS("/mconf.txt",m_config) ;  // m_config に config.txt を格納
  } else {                                       //
    // ファイルが無かった場合 -------------------//
    Serial.println("メイン設定ファイルなし") ;   // 無かったら、APモード
    result = -1 ;                                //
  }                                              //
 
  // ファイルが読み込めたら、グローバル変数にセットする
  if (result == 0)                               //
    # ifdef DEBUG                                // デバッグ用表示
      Serial.println("--- m_config --- ") ;      //
      Serial.println(m_config ) ;                //
    # endif                                      //
    set_conf2param() ;                           // m_config の内容を変数に設定
 
  return result ;                              //
}
 
// ----------------------------------------------------------------------------
// - 設定ファイルの内容を グローバル変数に 設定する                           -
// ----------------------------------------------------------------------------
void set_conf2param() {
  int    pos = 0 ;
  int    npos = 0 ;
  String s_work ;
  String s_name ;
  String s_data ;
  // 記載内容を順次処理 ( 設定情報を取り出し、グローバル変数に設定する ) ------
  while(1) {
    if (m_config.charAt(pos) == '/') {         // 先頭が '/' なら 次の行へ
      npos = m_config.indexOf('\n',pos) ;      //
      pos = npos + 1 ;                         //
    } else {                                   //
      npos = m_config.indexOf(':',pos) ;       // ':' までの文字をs_name に取得
      if (npos == -1) break ;                  //   見つからなければ終了
      s_name = m_config.substring(pos,npos) ;  //
      s_name.trim() ;                          //
      pos = npos+1 ;                           // ポインタを ':' の次へ
      npos = m_config.indexOf('\n',pos) ;      // '\n' までの文字をs_data に取得
      if (npos == -1) npos = m_config.length() ;  //
      s_data = m_config.substring(pos,npos) ;  //
      s_data.trim() ;                          //
      pos = npos+1 ;                           //
      set_param(s_name,s_data) ;               // 取得した内容をグローバル変数に設定
    }                                          //
  }                                            //
}                                              //
 
// - 設定内容を判定し、グローバル変数に設定 ------------------------------------
void set_param(String &name, String &data) {   //
  if (name.compareTo("prg_loop")==0) {         // 'prg_loop' の場合
    prg_tbl[0][0] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_loopnum")==0) {      // 'prg_loopnum' の場合
    prg_tbl[0][1] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_1_acc")==0) {        // 'prg_1_acc' の場合
    prg_tbl[1][2] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_1_spd")==0) {        // 'prg_1_spd' の場合
    prg_tbl[1][3] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_1_tim")==0) {        // 'prg_1_tim' の場合
    prg_tbl[1][4] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_2_en")==0) {         // 'prg_2_en'  の場合
    prg_tbl[2][0] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_2_trg")==0) {        // 'prg_2_trg' の場合
    prg_tbl[2][1] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_2_acc")==0) {        // 'prg_2_acc' の場合
    prg_tbl[2][2] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_2_spd")==0) {        // 'prg_2_spd' の場合
    prg_tbl[2][3] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_2_tim")==0) {        // 'prg_2_tim' の場合
    prg_tbl[2][4] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_3_en")==0) {         // 'prg_3_en'  の場合
    prg_tbl[3][0] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_3_trg")==0) {        // 'prg_3_trg' の場合
    prg_tbl[3][1] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_3_acc")==0) {        // 'prg_3_acc' の場合
    prg_tbl[3][2] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_3_spd")==0) {        // 'prg_3_spd' の場合
    prg_tbl[3][3] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_3_tim")==0) {        // 'prg_3_tim' の場合
    prg_tbl[3][4] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_4_en")==0) {         // 'prg_4_en'  の場合
    prg_tbl[4][0] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_4_trg")==0) {        // 'prg_4_trg' の場合
    prg_tbl[4][1] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_4_acc")==0) {        // 'prg_4_acc' の場合
    prg_tbl[4][2] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_4_spd")==0) {        // 'prg_4_spd' の場合
    prg_tbl[4][3] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_4_tim")==0) {        // 'prg_4_tim' の場合
    prg_tbl[4][4] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_5_en")==0) {         // 'prg_5_en'  の場合
    prg_tbl[5][0] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_5_trg")==0) {        // 'prg_5_trg' の場合
    prg_tbl[5][1] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_5_acc")==0) {        // 'prg_5_acc' の場合
    prg_tbl[5][2] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_5_spd")==0) {        // 'prg_5_spd' の場合
    prg_tbl[5][3] = data.toInt() ;             //
  }                                            //
  if (name.compareTo("prg_5_tim")==0) {        // 'prg_5_tim' の場合
    prg_tbl[5][4] = data.toInt() ;             //
  }                                            //
}                                              //
// ****************************************************************************
// * ステーションモードで サーバーを起動                                      *
// ****************************************************************************
void start_STA_server() {
  int lpcnt = 0 ;                                    // ループカウント
  int lpcnt2 = 0 ;                                   // ループカウント2
 
  WiFi.config(wifi_ip, wifi_gw, wifi_sm, wifi_dns);  // Set fixed IP address
  delay(10) ;                                        //
  WiFi.begin(wifi_ssid, wifi_pass);                  // wifi 開始
  lpcnt = 0 ;                                        //
  lpcnt2 = 0 ;                                       //
  while (WiFi.status() != WL_CONNECTED) {            // 接続確認
      lpcnt += 1 ;                                   //
      if (lpcnt > 4) {                               //
        WiFi.begin(wifi_ssid, wifi_pass);            // 4回目(2秒) で再度開始指示
        lpcnt = 0 ;                                  //
        lpcnt2 += 1 ;                                //
      }                                              //
      if (lpcnt2 > 5) {                              // 2秒x5 接続できなければ、
        stamode = false ;                            // APモードにして
        ESP.restart() ;                              // 再起動
      }                                              //
      Serial.print(".");                             //
      delay(500);                                    //   0.5秒毎にチェック
  }                                                  //
  server.begin();                                    // サーバー開始
}
 
// *****************************************************************************
// * HTML 送信処理                                                             *
// *****************************************************************************
 
// -----------------------------------------------------------------------------
// - メイン_HTML 送信                                                          -
// -----------------------------------------------------------------------------
void send_MAIN_html(WiFiClient client) {
  String htmlwk ;                               // HTML 編集用 ワーク
                                                //
  htmlwk = html_pwpk ;                          // HTML をワークにコピー
                                                //
  // 変数を値に変換-----------------------------//
  htmlwk.replace("$pwr",String(duty)) ;         //
  htmlwk.replace("$pwmin",String(base_val)) ;   //
  # ifdef DEBUG_WiFi                            //
    Serial.print("radio_local = ");             //
    Serial.println(local);                      //
    Serial.print("pwr  = ");                    //
    Serial.println(duty);                       //
  #endif                                        //
  if (local) {                                  //
    htmlwk.replace("$checked_lo","checked") ;   //
    htmlwk.replace("$checked_rm","") ;          //
  } else {                                      //
    htmlwk.replace("$checked_lo","") ;          //
    htmlwk.replace("$checked_rm","checked") ;   //
  }                                             //
  if (dir_bkwd) {                               //
    htmlwk.replace("$checked_fw","") ;          //
    htmlwk.replace("$checked_bw","checked") ;   //
  }else {                                       //
    htmlwk.replace("$checked_fw","checked") ;   //
    htmlwk.replace("$checked_bw","") ;          //
  }                                             //
                                                //
  // HTML 送信----------------------------------//
  send_html(client,htmlwk) ;                    // HTML 送信
}                                               //
                                                //
// ----------------------------------------------------------------------------
// - XHR RESPONSE_HTML 送信                                                           -
// ----------------------------------------------------------------------------
void send_resp_html(WiFiClient client) {        //
  String htmlwk ;                               // HTML 編集用 ワーク
                                                //
  htmlwk = html_resp ;                          // htmlwk に HTML をコピー
                                                //
  // 変数を値に変換-----------------------------//
  htmlwk.replace("$pwr",String(duty)) ;         //
                                                //
  send_html(client,htmlwk) ;                    // HTML 送信処理
# ifdef DEBUG_WiFi                              //
      Serial.print("xhr value :"); Serial.println(duty);
#endif                                          //
}                                               //
                                                //
// -----------------------------------------------------------------------------
// - メイン設定_HTML 送信                                                      -
// -----------------------------------------------------------------------------
void send_MCONF_html(WiFiClient client) {       //
  String htmlwk ;                               // HTML 編集用ワーク
                                                //
  htmlwk = html_MCONF ;                         // html を ワークにコピー
                                                //
  // 変数を値に変換-----------------------------//
  if (prg_tbl[0][0]) {                          // loop チェックマーク
    htmlwk.replace("$checked_loop","checked") ; //
  } else {                                      //
    htmlwk.replace("$checked_loop","") ;        //
  }                                             //
  htmlwk.replace("$loopnum",String(prg_tbl[0][1])) ; // loop 間隔
  //    設定1 ----------------------------------//
  htmlwk.replace("$acc1",String(prg_tbl[1][2])) ;   // 設定1 加速度
  htmlwk.replace("$spd1",String(prg_tbl[1][3])) ;   // 設定1 加速度
  htmlwk.replace("$tim1",String(prg_tbl[1][4])) ;   // 設定1 加速度
  //    設定2 ----------------------------------///
  if (prg_tbl[2][0]) {                           // 設定 2 許可
    htmlwk.replace("$en2","checked") ;          //
  } else {                                      //
    htmlwk.replace("$en2","") ;                 //
  }                                             //
  if (prg_tbl[2][1] == 0) {                     // 設定 2 起点
    htmlwk.replace("$trg2_sel0","selected") ;   //
    htmlwk.replace("$trg2_sel1","") ;           //
  } else if (prg_tbl[2][1] == 1) {              //
    htmlwk.replace("$trg2_sel0","") ;           //
    htmlwk.replace("$trg2_sel1","selected") ;   //
  }                                             //
  htmlwk.replace("$acc2",String(prg_tbl[2][2])) ;   // 設定2 加速度
  htmlwk.replace("$spd2",String(prg_tbl[2][3])) ;   // 設定2 加速度
  htmlwk.replace("$tim2",String(prg_tbl[2][4])) ;   // 設定2 加速度
                                                //
  //    設定3 ----------------------------------///
  if (prg_tbl[3][0]) {                           // 設定 2 許可
    htmlwk.replace("$en3","checked") ;          //
  } else {                                      //
    htmlwk.replace("$en3","") ;                 //
  }                                             //
  if (prg_tbl[3][1] == 0) {                     // 設定 3 起点
    htmlwk.replace("$trg3_sel0","selected") ;   //
    htmlwk.replace("$trg3_sel1","") ;           //
  } else if (prg_tbl[3][1] == 1) {              //
    htmlwk.replace("$trg3_sel0","") ;           //
    htmlwk.replace("$trg3_sel1","selected") ;   //
  }                                             //
  htmlwk.replace("$acc3",String(prg_tbl[3][2])) ;   // 設定3 加速度
  htmlwk.replace("$spd3",String(prg_tbl[3][3])) ;   // 設定3 加速度
  htmlwk.replace("$tim3",String(prg_tbl[3][4])) ;   // 設定3 加速度
                                                //
  //    設定4 ----------------------------------///
  if (prg_tbl[4][0]) {                           // 設定 4 許可
    htmlwk.replace("$en4","checked") ;          //
  } else {                                      //
    htmlwk.replace("$en4","") ;                 //
  }                                             //
  if (prg_tbl[4][1] == 0) {                     // 設定 4 起点
    htmlwk.replace("$trg4_sel0","selected") ;   //
    htmlwk.replace("$trg4_sel1","") ;           //
  } else if (prg_tbl[4][1] == 1) {              //
    htmlwk.replace("$trg4_sel0","") ;           //
    htmlwk.replace("$trg4_sel1","selected") ;   //
  }                                             //
  htmlwk.replace("$acc4",String(prg_tbl[4][2])) ;   // 設定4 加速度
  htmlwk.replace("$spd4",String(prg_tbl[4][3])) ;   // 設定4 加速度
  htmlwk.replace("$tim4",String(prg_tbl[4][4])) ;   // 設定4 加速度
                                                //
  //    設定5 ----------------------------------///
  if (prg_tbl[5][0]) {                           // 設定 5 許可
    htmlwk.replace("$en5","checked") ;          //
  } else {                                      //
    htmlwk.replace("$en5","") ;                 //
  }                                             //
  if (prg_tbl[5][1] == 0) {                     // 設定 5 起点
    htmlwk.replace("$trg5_sel0","selected") ;   //
    htmlwk.replace("$trg5_sel1","") ;           //
  } else if (prg_tbl[5][1] == 1) {              //
    htmlwk.replace("$trg5_sel0","") ;           //
    htmlwk.replace("$trg5_sel1","selected") ;   //
  }                                             //
  htmlwk.replace("$acc5",String(prg_tbl[5][2])) ;   // 設定5 加速度
  htmlwk.replace("$spd5",String(prg_tbl[5][3])) ;   // 設定5 加速度
  htmlwk.replace("$tim5",String(prg_tbl[5][4])) ;   // 設定5 加速度
                                                //
  // HTML 送信----------------------------------//
  send_html(client,htmlwk) ;                    //  HTML 送信
}                                               //
                                                //
// ----------------------------------------------------------------------------
// - HTML 送信処理                                                            -
// ----------------------------------------------------------------------------
void send_html(WiFiClient client, String &html ) {
    client.println("HTTP/1.1 200 OK");           //
    client.println("Content-type:text/html");    //
    client.println();                            //
                                                 //
    client.print(html) ;                         //
                                                 //
    # ifdef DEBUG                                //
        Serial.println( " --- send html --- ");  //
    #endif                                       //
}                                                //
                                                 //
// *****************************************************************************
// * メイン処理                                                                *
// *****************************************************************************
 
// ----------------------------------------------------------------------------
// - PWPK メイン画面の クライアントからのフォームデータ 処理                  -
// ----------------------------------------------------------------------------
int  proc_main(String &line) {
  String s_work ="" ;
  bool workflg = false ;
  int val ;
  int xhr = 0 ;
 
  // remote/local のラジオボタンが設定された時の処理 --------------------------
  if (line.indexOf("GET /?remote") != -1) {       //
    s_work = getvalue_s(line,"?remote=") ;        //   remote に続く文字列を取得
    if (s_work=="local") {                        // local の場合
      local = true ;                              //   local フラグを ON
    } else {                                      // remote の場合
      local = false ;                             //   local フラグを OFF
      localen = false ;                           //   locavollen フラグを OFF
    }                                             //
  }                                               //
  // 進行方向が操作された場合の処理 --------------------------------------
  if (line.indexOf("GET /?dir") != -1) {          //
    s_work = getvalue_s(line,"?dir=") ;           // dir  に続く文字列を取得
    if (!local) {                                 //  遠隔時
      if (!running) {                             //    走行中でない時
        workflg = dir_bkwd ;                      //     現在の状態を一時保存
        if (s_work=="foward") {                   //     進行方向を設定
          dir_bkwd = false ;                      //
        } else {                                  //
          dir_bkwd = true ;                       //
        }                                         //
        if (workflg != dir_bkwd) {                //  状態が変わった場合に変更
          dir_change = true ;                     //
        }                                         //
      }                                           //
    }                                             //
  }                                               //
  // 出力値がセットされた場合の処理 -----------------------------------------
  if (line.indexOf("GET /?pwr_v") != -1) {        //
    val = getvalue_i(line,"?pwr_v=") ;            // gw2 に続く数値を変数にセット
    if (!local) {                                 //
      if (val>256) val = 255 ;                    // 255 にクリップ
      duty = val  ;                               // デューティを設定
    }                                             //
  }                                               //
  // スライダーが操作された場合の処理 -----------------------------------------
  if (line.indexOf("GET /?slid") != -1) {         //
    val = getvalue_i(line,"?slid=") ;             //   gw2 に続く数値を変数にセット
    if (!local) {                                 //
      if (val>256) val = 255 ;                    //
      duty = val  ;                               //
    }                                             //
    xhr = 1 ;                                     //   スライダー操作時は レスポンス
  }                                               //
  // 準備/解除がセットされた場合の処理 ----------------------------------------
  if (line.indexOf("GET /?ready") != -1) {        //
    if (!local) {                                 //
      if (ready == false) {                       //
        ready = true ;                            //
        base_val = base ;                         //  最低速度を 設定
        rdy_change = true ;                       //
        if (duty < base_val)                      //
          duty = base_val ;                       //
      }else{                                      //
        ready = false ;                           //
        base_val = 0 ;                            //  最低速度を 0 にする。
        rdy_change = true ;                       //
        duty = base_val ;                         //
      }                                           //
    }                                             //
  }                                           //
  // 発車/停車がセットされた場合の処理 ----------------------------------------
  if (line.indexOf("GET /?start") != -1) {        //
    if (!local) {                                 //
      start_sw = true ;                           //
    }                                             //
    xhr = 1 ;                                     // start 時は、XHR 応答
  }                                           //
  // ポーリング要求があった場合の処理 -----------------------------------------
  if (line.indexOf("GET /?pol") != -1) {          //
    xhr = 1 ;                                     // ポーリング時、XHR 応答
  }                                               //
  // 運行設定の処理 -----------------------------------------------------------
  if (line.indexOf("GET /?mconf") != -1) {        // 運行設定の場合、
    html_mode=MAIN_CONF;                          //   HTML を 運行設定用にする
  }                                               //
  // WiFi設定の処理 -----------------------------------------------------------
  if (line.indexOf("GET /?config") != -1) {       // WiFi設定の場合、
    html_mode=WIFI_CONF;                          //   HTML を WiFi設定 にする
  }                                               //
  // --------------------------------------------------------------------------
  return xhr ;                                    // 戻り値は、 xhr かどうか
}                                                 //
                                                  //
// ----------------------------------------------------------------------------
// - メイン設定の クライアントからのフォームデータ 処理                       -
// ----------------------------------------------------------------------------
void set_mconf2param(String &line) {
  String s_work ="" ;
 
  // クライアントからのデータを グローバル変数にセットする。 ------------------
  if (line.indexOf("set=") != -1) {                 // set
    if (line.indexOf("loop=") != -1) {              // prg_loop チェック有
      prg_tbl[0][0] = true  ;                       // 
    } else {                                        //          チェック無し
      prg_tbl[0][0] = false ;                       //
    }                                               //
    if (line.indexOf("loopnum=") != -1) {           // prg_loop_num
      prg_tbl[0][1] = getvalue_i(line,"loopnum=") ; //  loopnum に続く文字列を取得
    }
    if (line.indexOf("acc1=") != -1) {              // prg_1_acc
      prg_tbl[1][2] = getvalue_i(line,"acc1=") ;    //  acc1 に続く数値を変数にセット
    }
    if (line.indexOf("spd1=") != -1) {              // prg_1_spd
      prg_tbl[1][3] = getvalue_i(line,"spd1=") ;    //  spd1 に続く数値を変数にセット
    }
    if (line.indexOf("tim1=") != -1) {              // prg_1_tim
      prg_tbl[1][4] = getvalue_i(line,"tim1=") ;    //  tim1 に続く数値を変数にセット
    }
    if (line.indexOf("chk2=") != -1) {              // prg_2_en チェック有
      prg_tbl[2][0] = true  ;                       //
    } else {                                        //          チェック無し
      prg_tbl[2][0] = false ;                       //
    }
    if (line.indexOf("trg2=") != -1) {              // prg_2_trg
      prg_tbl[2][1] = getvalue_i(line,"trg2=") ;    //  trg2 に続く数値を変数にセット
    }
    if (line.indexOf("acc2=") != -1) {              // prg_2_acc
      prg_tbl[2][2] = getvalue_i(line,"acc2=") ;    //  acc2 に続く数値を変数にセット
    }
    if (line.indexOf("spd2=") != -1) {              // prg_2_spd
      prg_tbl[2][3] = getvalue_i(line,"spd2=") ;    //  spd2 に続く数値を変数にセット
    }
    if (line.indexOf("tim2=") != -1) {              // prg_2_tim
      prg_tbl[2][4] = getvalue_i(line,"tim2=") ;    //  tim2 に続く数値を変数にセット
    }
    if (line.indexOf("chk3=") != -1) {              // prg_3_en チェック有
      prg_tbl[3][0] = true  ;                       //
    } else {                                        //          チェック無し
      prg_tbl[3][0] = false ;                       //
    }
    if (line.indexOf("trg3=") != -1) {              // prg_3_trg
      prg_tbl[3][1] = getvalue_i(line,"trg3=") ;    //  trg3 に続く数値を変数にセット
    }
    if (line.indexOf("acc3=") != -1) {              // prg_3_acc
      prg_tbl[3][2] = getvalue_i(line,"acc3=") ;    //  acc3 に続く数値を変数にセット
    }
    if (line.indexOf("spd3=") != -1) {              // prg_3_spd
      prg_tbl[3][3] = getvalue_i(line,"spd3=") ;    //  spd3 に続く数値を変数にセット
    }
    if (line.indexOf("tim3=") != -1) {              // prg_3_tim
      prg_tbl[3][4] = getvalue_i(line,"tim3=") ;    //  tim3 に続く数値を変数にセット
    }
    if (line.indexOf("chk4=") != -1) {              // prg_4_en チェック有
      prg_tbl[4][0] = true  ;                       //
    } else {                                        //          チェック無し
      prg_tbl[4][0] = false ;                       //
    }
    if (line.indexOf("trg4=") != -1) {              // prg_4_trg
      prg_tbl[4][1] = getvalue_i(line,"trg4=") ;    //  trg4 に続く数値を変数にセット
    }
    if (line.indexOf("acc4=") != -1) {              // prg_4_acc
      prg_tbl[4][2] = getvalue_i(line,"acc4=") ;    //  acc4 に続く数値を変数にセット
    }
    if (line.indexOf("spd4=") != -1) {              // prg_4_spd
      prg_tbl[4][3] = getvalue_i(line,"spd4=") ;    //  spd4 に続く数値を変数にセット
    }
    if (line.indexOf("tim4=") != -1) {              // prg_4_tim
      prg_tbl[4][4] = getvalue_i(line,"tim4=") ;    //  tim4 に続く数値を変数にセット
    }
    if (line.indexOf("chk5=") != -1) {              // prg_5_en チェック有
      prg_tbl[5][0] = true  ;                       //
    } else {                                        //          チェック無し
      prg_tbl[5][0] = false ;                       //
    }
    if (line.indexOf("trg5=") != -1) {              // prg_5_trg
      prg_tbl[5][1] = getvalue_i(line,"trg5=") ;    //  trg5 に続く数値を変数にセット
    }
    if (line.indexOf("acc5=") != -1) {              // prg_5_acc
      prg_tbl[5][2] = getvalue_i(line,"acc5=") ;    //  acc5 に続く数値を変数にセット
    }
    if (line.indexOf("spd5=") != -1) {              // prg_5_spd
      prg_tbl[5][3] = getvalue_i(line,"spd5=") ;    //  spd5 に続く数値を変数にセット
    }
    if (line.indexOf("tim5=") != -1) {              // prg_5_tim
      prg_tbl[5][4] = getvalue_i(line,"tim5=") ;    //  tim5 に続く数値を変数にセット
    }
    if (line.indexOf("save=") != -1) {              // prg_5_en チェック有
      Serial.println("write main config ") ;
      wr_config() ;                                 //
    }
    Serial.println("set html_mode MAIN") ;
    html_mode = MAIN ;                              //
  }
  if (line.indexOf("rtn=") != -1) {                 //  戻るの場合
    Serial.println("retuen MAIN mode") ;
    html_mode = MAIN ;                              //
  }
 
}
 
// -----------------------------------------------------------------------------
// - グローバル変数の内容を設定ファイルに書き出す                              -
// -----------------------------------------------------------------------------
void wr_config() {
  char s_work[1024] ;
  File fp ;
 
  Serial.println("make m_config data") ;
 
  // String に 変数の内容を書き込む -------------------------------------------
  sprintf(s_work,"prg_loop         : %d\n",prg_tbl[0][0]  ) ;  //
  m_config = String(s_work) ;                     //
  sprintf(s_work,"prg_loopnum      : %d\n",prg_tbl[0][1]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_1_acc        : %d\n",prg_tbl[1][2]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_1_spd        : %d\n",prg_tbl[1][3]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_1_tim        : %d\n",prg_tbl[1][4]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_2_en         : %d\n",prg_tbl[2][0]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_2_trg        : %d\n",prg_tbl[2][1]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_2_acc        : %d\n",prg_tbl[2][2]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_2_spd        : %d\n",prg_tbl[2][3]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_2_tim        : %d\n",prg_tbl[2][4]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_3_en         : %d\n",prg_tbl[3][0]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_3_trg        : %d\n",prg_tbl[3][1]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_3_acc        : %d\n",prg_tbl[3][2]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_3_spd        : %d\n",prg_tbl[3][3]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_3_tim        : %d\n",prg_tbl[3][4]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_4_en         : %d\n",prg_tbl[4][0]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_4_trg        : %d\n",prg_tbl[4][1]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_4_acc        : %d\n",prg_tbl[4][2]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_4_spd        : %d\n",prg_tbl[4][3]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_4_tim        : %d\n",prg_tbl[4][4]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_5_en         : %d\n",prg_tbl[5][0]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_5_trg        : %d\n",prg_tbl[5][1]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_5_acc        : %d\n",prg_tbl[5][2]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_5_spd        : %d\n",prg_tbl[5][3]  ) ;  //
  m_config += String(s_work) ;                    //
  sprintf(s_work,"prg_5_tim        : %d\n",prg_tbl[5][4]  ) ;  //
  m_config += String(s_work) ;                    //
  Serial.println("m_config_data make end ") ;
 
  // 設定ファイルに書き込む ----------------------------------------------------
  Serial.println("now write main config ...........") ;
 
  fp = SPIFFS.open("/mconf.txt",FILE_WRITE) ; // 設定ファイルを開く
  if (!fp) {
    Serial.println(" 設定ファイル オープンエラー !!") ;
  } else {
    Serial.println("/mconf.txt open complete ") ;
    // 初期設定ファイル書き込み -------------------------------------------------
    if(fp.print(m_config)) {                      // ファイルに書き込み
      Serial.println("m_config written") ;        //   終了メッセージ
    } else {                                      //
      Serial.println("m_config write error !!") ; //   失敗メッセージ
    }                                             //
    fp.close() ;                                  // ファイルクローズ
  }                                               //
}                                                 //
 
// ----------------------------------------------------------------------------
// - 定期割込み処理                                                           -
// ----------------------------------------------------------------------------
void execTicker() {
  ticker_val = true // フラグを True にするだけ。
}
 
// 定期処理 (定期割込みフラグが立っていた時の処理) ------------------------
void do_JOB() {
  bool workflg = false ;
 
  // +---------------------------------------------------------------------
  // | 制御盤情報の取得                                                   |
  // +---------------------------------------------------------------------
 
  // loxal の場合 制御盤情報を取得する。-----------------------------------
  if (local == true) {
    // 出力用ボリューム値を取得 -------------------------------------------
    vol_value  = analogRead(PWR_VOL);
 
    // 制御盤の操作が許可されていた場合 -----------------------------------
    if (localen == true) {
      // 進行方向スイッチのチェック ---------------------------------------
      if (!running) {                         // 走行中は切り替え不可
        workflg = dir_bkwd ;                  // 現在の状態を一時保存
        if (!digitalRead(SW_FWD))  {          // SW_FWD : Low Active
          dir_bkwd = 0 ;                      //
        }                                     //
        if (!digitalRead(SW_BWD))  {          // SW_BWD : Low Activ
          dir_bkwd = 1 ;                      //
        }                                     //
        if (workflg != dir_bkwd) {            // 状態が変わった場合に変更
          dir_change = true ;
        }                                     //
      }                                       //
                                              //
      // 準備/解除スイッチのチェック ---------------------------------------
      if (!digitalRead(SW_READY))  {          // SW_READY が押された時 (Low Active)
        if (pre_rdy == false ) {              // 前回割り込み時、SW が OFF
          if (ready == false) {               //   かつ LED常時点灯になっていない場合
            ready = true ;                    //  ON にする
            base_val = base ;                 //  最低速度を 設定
            rdy_change = true ;               //  準備要求状態変化フラグを ON
          } else {                            // LED常時点灯中の場合
            ready = false ;                   //  OFF にする
            base_val = 0 ;                    //  最低速度を 0 にする。
            rdy_change = true ;               //  準備要求状態変化フラグを ON
          }                                   //
        }                                     //
        pre_rdy = true ;                      // 前回割り込み情報を更新
      } else {                                //
        pre_rdy = false ;                     //
      }                                       //
                                              //
      // 発車/停車が押下された場合の処理 -------------------------------------------
      if (!digitalRead(SW_START)) {           // SW_START が押された時 ( Low Active)
        if (pre_strt == false) {              // 前回割込み時、SW が OFF
          start_sw = true ;                   //  発車要求フラグを ON
 }                                     //
        pre_strt = true ;                     // 前回割り込み情報を更新
      } else {                                //
 pre_strt = false ;                    //
      }                                       //
                                              //
      // PWM の デューティを設定 ----------------------------------------------
      if (prg_run == false)                   // 自動走行でない場合
        duty = ((vol_value*(255-base_val))/4095)+base_val  ;
                                              //   ボリュームの値で 出力制御
    // Local だが、制御盤の操作が許可されていない場合 --------------------------
    } else  {
      duty = base_val ;                       // 出力 OFF
      // ボリューム が 0 の場合
      if (vol_value == 0)                     // ボリュームが 0 に戻されたら
        localen = true ;                      // 制御盤の操作を許可する。
    }                                         //
  // remote の場合  ------------------------
  } else {
    // 準備/解除スイッチのチェック 押されたら Local にする --------------------
    if (!digitalRead(SW_READY)) {             // SW_START が押された時 ( Low Active)
      if (pre_rdy == false) {                 // 前回割込み時、SW が OFF
        local   = true ;                      // Local(制御盤操作可能) にする
 localen = false ;                     // 制御盤操作許可は OFF
      }
      pre_rdy = true ;                        // 前回割り込み情報を更新
    } else {
      pre_rdy = false ;
    }
  }
 
  // +-------------------------------------------------------------------------
  // | 自動運転制御                                                           |
  // +-------------------------------------------------------------------------
 
  // 発車 処理 (自動 加減速 開始) REMOTE/LOCAL 共通処理 ----------------------
  if (start_sw == true) {               // 発車要求スイッチ押下状態 が 真の場合
    if (prg_run == false) {             //   自動運行中でなければ、
      prg_start = true ;                //     自動運行開始指示。
    } else {                            //   自動運行中の場合
      if (wait_sw) {                    //     STARTスイッチ待ちなら
        prg_next = true ;               //       次No.の実行を指示
        st_on = true ;                  //       ステータス LED ON (更新)
      } else {                          //     でなければ
        start = false ;                 //       発車要求フラグを OFF
        stop  = true  ;                 //       停車要求フラグを ON
      }                                 //
    }                                   //
    start_sw = false ;                  //   発車要求スイッチ状態を OFF
  }                                     //
                                        //
  // 自動運転開始指示時 ----------------//
  if (prg_start == true) {              //   自動運行開始時。(まだ動いていない時)
    prg_no = 1 ;                        //   実行する 運動設定 No. を '1' に設定。
    rate   = prg_tbl[1][2] ;            //     加速度設定
    target = prg_tbl[1][3] ;            //     目標速度設定
    prg_tim = prg_tbl[1][4] ;           //     運行時間設定
    prg_loopnum = prg_tbl[0][1] ;       //     ループ回数を取得。
    if (target < base_val)              //     目標速度が 最低速度より小さい時
        target = base_val ;             //       目標速度は 最低速度
    start  = true ;                     //     発車要求
    stop  = false ;                     //
    wait_sw = false ;                   //
    st_on  = true ;                     //     LED 点灯設定
    st_val       = prg_no ;             //     ステータス LED 表示番号設定
    prg_start = false ;                 //  
    prg_run = true ;                    //     自動運行フラグをセット。
    Serial.print("prg_no :") ;
    Serial.print(prg_no) ;
    start_time = millis();              //     開始時刻を取得
  }                                     //
                                        //
  // 自動運行中の処理 ---------------------------------------------------------
  if (prg_run == true) {                // 自動運行実行中の場合
    now_time = millis() ;               //     現在時刻を取得
    if (prg_tim <=                      //   経過時間が運行時間以上になったら
             ((now_time - start_time)/100) ) { //
      time_ovr = true ;                 //   運行時間オーバー
    }                                   //
                                        //  
    // 運行時間経過時、次の運行No.を選択//
    if (!wait_sw & time_ovr)  {         //   運行時間オーバーでスイッチ待ちでない時
      nextno = prg_no + 1 ;             //     次の運行No.を設定。
      while (nextno != prg_no) {        //     No.が 一周するまでチェック
        if (nextno > 5) {               //     No.が上限を超えた場合、
          if (   (prg_tbl[0][0] == 1)   //       ループ En で
              && (prg_loopnum >  1)) {  //       繰り返し回数が 1以下でなければ
            nextno = 1 ;                //         No. を最初にする。
            prg_loopnum = prg_loopnum -1 ;//
            Serial.print("loopnum:") ;
            Serial.println(prg_loopnum) ;
          } else {                      //       ループ En でないか、繰り返し回数
                                        //       に達してれば
            nextno = prg_no ;           //         No.を現状にして
            now_time = millis() ;       //         現在時刻を取得
            now_time = now_time - start_time ;//   経過時間を取得
            Serial.print(" | time : "); //
            Serial.println(now_time) ;  //
            stop = true ;               //         停車要求
            break ;                     //         while を抜ける
          }
        }                               //
        if (prg_tbl[nextno][0] == 0) {  //      選択したNo.が有効(En)でなければ、
          nextno = nextno + 1 ;         //        次の No.
        } else {                        //      選択したNo.が有効(En)な時、
          prg_no = nextno ;             //        運行No.を選択したNo.に更新
          if (prg_tbl[prg_no][1] == 0)  //        起点が前No.の続きなら、
            prg_next = true ;           //          次No.の運行を指示
          else{                         //        起点がスイッチ押下なら、
            wait_sw = true ;            //          スイッチ待ちフラグを ON
            st_blink = true ;           //          ステータス点滅設定
            st_bl_intvl = 5 ;           //          点滅間隔設定
          }                             //
          break ;                       //        次No.選択を抜ける。  
        }                               //
      }                                 //
      time_ovr = false ;                //
    }                                   //
                                        //
    // 設定更新指示時 ------------------//
    if (prg_next == true) {             //   設定更新の場合
      rate   = prg_tbl[prg_no][2] ;     //     加速度設定
      target = prg_tbl[prg_no][3] ;     //     目標速度設定
      prg_tim = prg_tbl[prg_no][4] ;    //     運行時間設定
      if (target < base_val)            //     目標速度が 最低速度より小さい時
          target = base_val ;           //       目標速度は 最低速度
      start  = true ;                   //     発車要求
      stop  = false ;                   //
      wait_sw = false ;                 //
      st_on  = true ;                   //     LED 点灯設定
      st_val       = prg_no ;           //     ステータス LED 表示番号設定
      now_time = millis() ;             //     現在時刻を取得
      now_time = now_time - start_time ;//     経過時間を取得
      Serial.print(" | time : ") ;
      Serial.println(now_time) ;
      Serial.print("prg_no :") ;
      Serial.print(prg_no) ;
      start_time = millis();            //     開始時刻を取得
      prg_next = false ;                //     設定更新終了
    }                                   //
                                        //
    // 発車要求時 ----------------------//
    if (start == true) {                //   発車要求フラグ が 真の場合
      autorun = true ;                  //     自動走行中のフラグを ON
      // 速度が目標値未満の時 ----------//
      if (duty < target) {              //     現状が目標デューティ未満の時
        if (duty < base)                //       LED常時点灯時の値未満の時は
          duty = base ;                 //         LED常時点灯時の値に更新
        if ((target - duty) < rate)     //       目標値との差分が増減値未満の時
          duty = target ;               //         出力を目標値に更新
        else                            //       増減値以上の場合
          duty = duty + rate ;          //         出力を 増減値分加算
      // 速度が目標値より大きい時 ------//
      } else if (duty > target){        //     現状が目標デューティより大きい時
        if ((duty - target) < rate)     //       目標値との差分が増減値未満の時
          duty = target ;               //         出力を目標値に更新
        else                            //       増減値以上の時
          duty = duty - rate ;          //         出力を 増減値分減算
      // 目標値となった時 --------------//
      } else {                          //     目標デューティに達したら
        now_time = millis() ;           //         現在時刻を取得
        now_time = now_time - start_time ;//   経過時間を取得
        Serial.print(" duty:") ;
        Serial.print(duty) ;
        Serial.print(" | time : ");     //
        Serial.print(now_time) ;        //
        Serial.print(" | ") ;           //
        start = false ;                 //       発車要求を解除
      }                                 //
    }                                   //
                                        //
    // 停車要求時 ----------------------//
    if (stop  == true) {                //   停車要求フラグが真の場合
      autorun = true ;                  //     自動走行中のフラグを ON
      if (duty > base_val){             //     現状が、最低速度より大きい時
        if ((duty - base_val) < rate)   //       最低速度との差分が増減値未満の時
          duty = base_val ;             //         出力を 最低族度に設定
        else                            //       増減値以上の時
          duty = duty - rate ;          //         出力を 増減値 分減算
      } else {                          //     最低速度以下の時
        stop  = false ;                 //       停車要求を OFF
        autorun = false;                //       自動走行中フラグを OFF
        prg_run = false;                //       自動運行中フラグを OFF
        if (ready == true) {            //       LED常時点灯の場合
          st_blink = true ;             //         ステータス点滅 ON
          st_val   = 7 ;                //         ステータス値を 7
          st_bl_intvl = 5 ;             //         点滅間隔 5
        } else {                        //       常時点灯ではない場合
          st_on    = true ;             //         ステータスLED 消灯
          st_val   = 0 ;                //
        }                               //
      }                                 //
    }                                   //
  // 自動運行中でない時 ----------------//
  } else {                              //  自動運行実行中ではない時
    if (rdy_change) {                   //    準備要求状態変化フラグがONの時
      if (ready) {                      //      常時点灯なら、
        st_blink = true ;               //        LED点滅を設定
        st_val   = 7 ;                  //
        st_bl_intvl = 5 ;               //
      } else {                          //      常時点灯でなければ
        st_on    = true ;               //        LED消灯を設定
        st_val   = 0 ;                  //
      }                                 //
      rdy_change = false ;              //
    }                                   //
  }                                     //
                                        //
  // 走行中フラグを更新 -------------------------------------------------------
  if (duty > base_val)                  //  最低速度より大きな Duty の時
    running = true ;                    //    走行中フラグを ON
  else                                  //  最低速度以下の時
    running = false ;                   //    走行中フラグを OFF
                                        //
  // +=========================================================================+
  // | 操作盤制御                                                              |
  // +=========================================================================+
 
  // 進行方向 設定 -------------------------------------------------------------
  if (dir_change) {                          // 進行方向が変化した時の設定
    ledcWrite(0, 0) ;                        // 切り替え前に PWM出力を停止
    delay(10);                               //
    digitalWrite(LED_FWD,!dir_bkwd) ;        // 前進用 LED 設定
    digitalWrite(LED_BWD,dir_bkwd) ;         // 後退用 LED 設定
    digitalWrite(DIR_OUT,dir_bkwd) ;         // 進行方向用リレー 設定
    delay(10);                               //
    ledcWrite(0, duty) ;                     // PWM出力を元に戻す。
    dir_change = false ;
  }                                          //
                                             //
  // ステータス LED 制御 -------------------------------------------------------
  //   ( ステータス LED を点灯 ) ------------//
  if (st_on == true) {                       // ステータス 点灯要求時
    digitalWrite(LED_ST3, (st_val & 0x01) != 0) ; // LED 設定
    digitalWrite(LED_ST2, (st_val & 0x02) != 0) ; //
    digitalWrite(LED_ST1, (st_val & 0x04) != 0) ; //
    st_on = false ;                          //
    st_blink = false ;                       //
  }                                          //
                                             //
  //   ( ステータス LED を点滅 ) ------------//
  if (st_blink == true) {                    // 点滅設定時
    if (st_bl_off == true) {                 //   消灯状態時
      if (st_bl_cnt == 0) {                  //     カウント値が 0 なら
        st_bl_cnt = st_bl_intvl ;            //       カウント値を初期値にする
        st_bl_off = false ;                  //       LED を点灯状態にする
        digitalWrite(LED_ST3, (st_val & 0x01) != 0) ; // LED 設定
        digitalWrite(LED_ST2, (st_val & 0x02) != 0) ; //
        digitalWrite(LED_ST1, (st_val & 0x04) != 0) ; //
      } else {                               //     カウント値が 0 でなければ
        st_bl_cnt = st_bl_cnt -1 ;           //       -1
      }                                      //
    } else {                                 //  点灯状態の時
      if (st_bl_cnt == 0) {                  //     カウント値が 0 なら
        st_bl_cnt = st_bl_intvl ;            //       カウント値を初期値にする
        st_bl_off = true  ;                  //       LED を消灯状態にする
        digitalWrite(LED_ST3,  0) ;          //
        digitalWrite(LED_ST2,  0) ;          //
        digitalWrite(LED_ST1,  0) ;          //
      } else {                               //     カウント値が 0 でなければ
        st_bl_cnt = st_bl_cnt -1 ;           //       -1
      }                                      //
    }                                        //
  }                                          //
                                             //
  // PWM デューティを設定 ----------------------------------------------------
  ledcWrite(0, duty) ;                       // PWM デューティを設定
                                             //
  // +=========================================================================+
  // | 管理情報                                                                |
  // +=========================================================================+
 
  // 割り込み処理の実行回数をカウント ------------------------------------------
  loopcnt++ ;                                // ループ回数 インクリメント
                                             //
  // 実行回数が 10 回目の場合 (1秒毎) ------------------------------------------
  if (loopcnt ==10) {                        //
    # ifdef DEBUG_Hard                       // デバッグ用出力
      Serial.println("") ;                   //
      Serial.print( "PWR_VOL :") ; Serial.println(vol_value) ;
      Serial.print( "duty     :") ; Serial.println(duty) ;
      Serial.print( "running  :") ; Serial.println(running) ;
      Serial.print( "autorun  :") ; Serial.println(autorun) ;
      Serial.print( "stop     :") ; Serial.println(stop ) ;
      Serial.print( "ready    :") ; Serial.println(ready) ;
      Serial.print( "start    :") ; Serial.println(start) ;
      Serial.print( "prg_start:") ; Serial.println(prg_start) ;
      Serial.print( "prg_next :") ; Serial.println(prg_next ) ;
      Serial.print( "prg_run  :") ; Serial.println(prg_run  ) ;
      Serial.print( "prg_tim  :") ; Serial.println(prg_tim  ) ;
    #endif                                   //
                                             //
    loopcnt = 0;                             // ループ回数をクリア
  }                                          //
  ticker_val = false ;                       // 処理を実行したら、定期割込みフラグ
                                             // を false にする。
}                                            //
                                             //


 以下、メモ
<WiFi設定 HTML> "softAPでWiFi設定" からの変更部分
・"戻る"ボタンを追加。

<PWPK設定 HTML>
・新規追加
・自動走行時の走行パターン(加速度,速度,走行時間等を 最大5パターン)設定可能

<MAIN HTML>
"パワーパック_改" からの変更部分
・WiFi設定、運行設定のボタンを追加・スライダーの MIN 値を変数化(LED常時点灯時用)

<MAIN スケッチ>
・詳細は コメント参照。
(行#1~4)
include文。SPIFFS, Ticker を使用。

(行#9~53)
WiFi設定用 変数等を定義。
APモード時の SSID は "ESP32_AP", パスワードは "password"
HTML の ファイル名もここで定義。

(行#54~135)
パワーパック制御、自動運行用の変数等を定義。
LED,SW に接続するIOピン番号, PWM 周波数 もここで定義。

(行#139~210)
setup 関数。以下の順に実行
・IO PIN 設定
・LED 全点灯 (設定中であることがわかる様に)
・シリアル開始
・SPIFFS開始
・各 HTML ファイルを読み込み
・WiFi設定ファイルを読み込み
・WiFi設定内容により、WiFiのモード(AP or STA) 、
・HTMLモード、画面(WiFi設定 or メイン) を決定。
・サーバーを起動
・PWPK設定を読み込み
・PWM 初期設定
・LED を初期状態に設定 (初期設定終了がわかる様に)
・周期割り込みを起動

(行#216~300)
loop 関数。以下の順に実行
・定期割込みフラグが立っていれば、定期処理実行。
・クライアントからの接続があれば、
・クライアントからのデータを1行分取得
・"GET /?" であれば、HTMLモードによりフォームデータの解析を実行。
・最終行であれば、HTMLモードにより送信するHTMLを選択して送信。
・WiFiのモードに変更がある場合は、HTMLにリブートメッセージを追加して送信。
・HTML送信後、クライアントを切断。
・WiFiのモードに変更があった場合、リブートを実行。
この時、HTML送信直後にリブートを行うと、クライアントが受け取れない
ことがある為、Delay を挿入している。(時間は適当)

<WiFi設定 スケッチ>
(行#1~137)
rd_config() : wifi設定をリードして変数に設定。

(行#138~149)
start_AP_server() : アクセスポイントモードでのサーバー起動。

(行#153~176)
disp_modi() : デバッグ用表示

(行#180~331)
set_form2param() : クライアントからのフォームデータを変数に設定し、ファイルに書き出す。

(行#339~374)
send_CONF_html() : WiFi設定用HTML送信。

<PWPK処理 スケッチ>
(行#1~15)
rd_SPIFFS() : SPIFFS ファイルを読み込む

(行#20~151)
rd_mainconf() : pwpk設定をリードして変数に設定。

(行#155~179)
start_STA_server() : ステーションモードでサーバー起動。

(行#185~237)
send_MAIN_html() : MAIN HTML 送信

(行#241~328)
send_MCONF_html() : PWPK設定 HTML 送信

(行#332~343)
send_html() : HTML送信処理

(行#348~440)
proc_main() : MAIN HTML用のクライアントからのフォームデータ処理。

(行#444~627)
set_mconf2param() : PWPK設定 HTML用のクライアントからのフォームデータを変数に設定し、ファイルに書き出す。

(行#631~633)
execTicker() : 定期割込み処理。

(行#636~982)
do_JOB() :
割込み発生時の処理。
・制御盤情報の取得 (スイッチ状態のリード等)してフラグセット。
・自動運転制御。
 各フラグの状態から、走行設定を決めて制御フラグをセット
・操作盤制御。
 制御フラグに従い、IO出力(LED ON/OFF, PWM Duty設定等) を行う。
の順に実行。
定期割込みが 100mS 毎に発生する為、運行時間は処理回数でカウントしたところ、実行時間のばらつきが多きかった。割り込み処理間隔が 100mS 以上になる場合があると思われる。この為、millis() で経過時間を測定して運行時間を計算する様にした。



0 件のコメント:

コメントを投稿