Сопряжение 2 скетчей

Satanael
Offline
Зарегистрирован: 22.06.2018

Доброго времени суток.

В программировании Ардуино я новичок, но тем не менее хочу попробовать осуществить управление готовым скетчем при помощи веб интерфейса. Суть в том, что имеется скетч (полностью рабочий)и к нему надо так же привинтить аналоговое управление через web-страничку, чтобы можно было изменять ход циклов на ходу. Изначально всё управлялось через COM-порт посредством C++ или Python. Точно сказать не могу потому как расшифровать готовую программу у меня знаний не хватит. И в целом занялся этим делом потому как с Web-программированием я более-менее знаком ну и так для меня будет проще вносить поправки в скетч/web-страничку. А собственно проблема в том, то я не могу понять как мне по запросу с браузера заставить работать определённый цикл в программе. По нажатию "Start" (HTTP_req, "pin=01") должен выполняться "case '1'", по нажатию "Stop"(HTTP_req, "pin=02" "case 'g'" из цикла void ReadSerial(){switch (Serial.read())......} (находится в конце скетча).

Собственно сам скетч:
 

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#define REQ_BUF_SZ 80
// Входы
#define keycell       22       // Ключ в лебёдке
#define keycollar     24       // Ошейник
#define keychair      26       // Эл стул
#define keyout        28       // Выходная дверь

#define noise         A0      // Вход от датчика шума
#define button        A1      // Кнопка на газ.камере

// Выходы
#define volt          30      // Стрелочный индикатор
#define screen_open   32      // Экран открыть
#define screen_close  34      // Экран закрыть
#define blades        36      // Лезвия
#define lamp          38      // Освещение
#define mp3           40      // Плеер в душевой
#define collar        42      // Запуск ошейника
#define door_chamber  44      // Дверь газкамеры

#define smoke         46      // Дыммашина
#define fire          48      // Пол в газкамере
#define door_out      31      // Выходная дверь из квеста

#define limit         250     // Предел микроамперметра с учётом -10
#define v             1       // Шаг стрелки амперметра
#define timeScreen    3200    // Время движения экрана на потолке
#define timeSpeed     20      // Задержка между измерениями датчика шума (влияет на сорость)

#define beep          A9      // Бузер
#define GND           A8      // Земля бузера


File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer
byte mac[] = { 0x78, 0xAC, 0xC0, 0xC0, 0x26, 0x75};
IPAddress ip( 10, 10, 35, 140);

EthernetServer server(80);

int sign = 0;
int amper = 0;
int a = 0;
int var = v;
int low = 640;
int high = 665;
int long beepTime = 0;
int p = 0;
int u = 0;
int f = 0;
int fl = 0;

bool game = false;
bool cell_lable = true;
bool collar_lable = true;
bool chair_lable = true;
bool chamber_lable = false;
bool button_lable = true;
bool svet = false;
bool beep_lable = false;

bool p01;
bool p02;
bool p03;
bool p04;
bool p05;
bool p06;
bool p07;
bool p08;
bool p09;
bool p10;
bool p11;
bool p12;
bool p13;
bool p14;
bool p15;
bool p16;
int pd;

void setup() {
  pinMode(37, OUTPUT);

  setup_in();
  setup_out();
  res_logic();
  res_rele();
  Serial.begin(9600);

  SD.begin(4);
  Ethernet.begin(mac, ip);
  server.begin();
}

void res_logic()
{
  game = false;
  cell_lable = true;
  collar_lable = true;
  chair_lable = true;
  chamber_lable = false;
  button_lable = true;
  svet = false;
  amper = 0;
  var = v;
  beep_lable = false;
  beepTime = 0;
  p = 0;
  u = 0;
}

void res_rele()
{
  digitalWrite(screen_open, HIGH);
  digitalWrite(screen_close, HIGH);
  digitalWrite(blades, HIGH);
  digitalWrite(lamp, HIGH);
  digitalWrite(mp3, HIGH);
  digitalWrite(collar, HIGH);
  digitalWrite(door_chamber, HIGH);
  digitalWrite(door_out, LOW);
  digitalWrite(smoke, LOW);
  digitalWrite(fire, LOW);
  digitalWrite(beep, LOW);
  digitalWrite(GND, LOW);
}

void setup_in()
{
  pinMode(keycell, INPUT_PULLUP);
  pinMode(keycollar, INPUT_PULLUP);
  pinMode(keychair, INPUT_PULLUP);
  pinMode(keyout, INPUT_PULLUP);
  pinMode(button, INPUT_PULLUP);
}

void setup_out()
{
  pinMode(screen_open, OUTPUT);
  pinMode(screen_close, OUTPUT);
  pinMode(blades, OUTPUT);
  pinMode(lamp, OUTPUT);
  pinMode(mp3, OUTPUT);
  pinMode(collar, OUTPUT);
  pinMode(door_chamber, OUTPUT);
  pinMode(door_out, OUTPUT);
  pinMode(smoke, OUTPUT);
  pinMode(fire, OUTPUT);
  pinMode(beep, OUTPUT);
  pinMode(GND, OUTPUT);
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c; // save HTTP request character
          req_index++;
        }
        if (c == '\n' && currentLineIsBlank) {
          if (StrContains(HTTP_req, "GET /")) {
            if (StrContains(HTTP_req, "/ ")
                || StrContains(HTTP_req, "/index.htm")) {
              sendHtmlFile(client, "index.htm");
            } else if (StrContains(HTTP_req, "/my.css")) {
              sendFile(client, "my.css");
            } else if (StrContains(HTTP_req, "ajax_inputs")) {
              sendBaseAnswer(client);

              char buff[64];
              sprintf(buff, "%d:%d:%d:%d:%d:%d:%d:%d:",
                      digitalRead(22), digitalRead(24), digitalRead(26), digitalRead(28),digitalRead(30), digitalRead(32), digitalRead(34), digitalRead(36),digitalRead(38), digitalRead(40), digitalRead(42), digitalRead(44),digitalRead(46), digitalRead(48), digitalRead(31), digitalRead(37),
                      pd);
              client.println(buff);
            } else if (StrContains(HTTP_req, "inputs")) {
              if (StrContains(HTTP_req, "pin=01")) {
                Serial.print('1');
              } else if (StrContains(HTTP_req, "pin=02")) {
                Serial.print('g');
              } else if (StrContains(HTTP_req, "pin=03")) {
                p03 = !p03;
                digitalWrite(26, p03);
              } else if (StrContains(HTTP_req, "pin=04")) {
                p04 = !p04;
                digitalWrite(28, p04);
              } else if (StrContains(HTTP_req, "pin=05")) {
                p05 = !p05;
                digitalWrite(30, p05);
              } else if (StrContains(HTTP_req, "pin=06")) {
                p06 = !p06;
                digitalWrite(32, p06);
              } else if (StrContains(HTTP_req, "pin=07")) {
                p07 = !p07;
                digitalWrite(34, p07);
              } else if (StrContains(HTTP_req, "pin=08")) {
                p08 = !p08;
                digitalWrite(36, p08);
              } else if (StrContains(HTTP_req, "pin=09")) {
                p09 = !p09;
                digitalWrite(38, p09);
              } else if (StrContains(HTTP_req, "pin=10")) {
                p01 = !p01;
                digitalWrite(40, p01);
              } else if (StrContains(HTTP_req, "pin=11")) {
                p02 = !p02;
                digitalWrite(42, p02);
              } else if (StrContains(HTTP_req, "pin=12")) {
                p03 = !p03;
                digitalWrite(44, p03);
              } else if (StrContains(HTTP_req, "pin=13")) {
                p04 = !p04;
                digitalWrite(46, p04);
              } else if (StrContains(HTTP_req, "pin=14")) {
                p05 = !p05;
                digitalWrite(48, p05);
              } else if (StrContains(HTTP_req, "pin=15")) {
                p06 = !p06;
                digitalWrite(31, p06);
              } else if (StrContains(HTTP_req, "pin=16")) {
                p07 = !p07;
                digitalWrite(37, p07);
              } else if (StrContains(HTTP_req, "pin=17")) {
                String input = HTTP_req;
                int posStart = input.indexOf("value=");
                int posEnd = input.indexOf(' ', posStart);
                String param = input.substring(posStart + 6, posEnd + 1);
                pd = param.toInt();
              }
              sendBaseAnswer(client);
            }
          }
          req_index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }

if (Serial.available() > 0) ReadSerial();
  if (game) {
    if (cell_lable) Cell();
    if (collar_lable) Collar();
    if (chair_lable) Chair();
    if (chamber_lable) GasCam();
    if (button_lable) Fire();
    Keyout();
  }
  if (beep_lable) BEEP(500);
  
}
bool sendHtmlFile(EthernetClient client, char *fileName) {
  webFile = SD.open(fileName);
  sendBaseAnswer(client);
  return sendFile(client, webFile);
}
bool sendFile(EthernetClient client, char *fileName) {
  webFile = SD.open(fileName);
  sendHttpOkAnswer(client);
  client.println();
  return sendFile(client, webFile);
}
bool sendFile(EthernetClient client, File &webFile) {
  if (webFile) {
    while (webFile.available())
      client.write(webFile.read()); // send web page to client
    webFile.close();
    return 1;
  }
  return 0;
}
void sendBaseAnswer(EthernetClient client) {
  sendHttpOkAnswer(client);
  client.println(F("Content-Type: text/html"));
  client.println(F("Connection: close"));
  client.println();
}
void sendHttpOkAnswer(EthernetClient client) {
  client.println(F("HTTP/1.1 200 OK"));
}

void StrClear(char *str, char length) {
  for (int i = 0; i < length; i++) {
    str[i] = 0;
  }
}

char StrContains(char *str, char *sfind) {
  char found = 0;
  char index = 0;
  char len;
  len = strlen(str);
  if (strlen(sfind) > len) {
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {
      found++;
      if (strlen(sfind) == found) {
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }
  return 0;
}

void Cell()
{
  int x = 0;
  while (digitalRead(keycell))
  {
    x++;
    if (x > 10) {
      Screen_open();
      Serial.println("cell");
      cell_lable = false;
      break;
    }
    delay(10);
  }
}

void Collar()
{
  int x = 0;
  while (!digitalRead(keycollar)) // Реле замыкает на минус 5В
  {
    x++;
    if (x > 10) {
      Screen_open();
      Serial.println("collar");
      collar_lable = false;
      break;
    }
    delay(10);
  }
}

void Chair()
{
  int x = 0;
  while (digitalRead(keychair))
  {
    x++;
    if (x > 10) {
      Screen_open();
      Serial.println("chair");
      chair_lable = false;
      break;
    }
    delay(10);
  }
}

void GasCam()
{
 int x = 0;
  while (digitalRead(door_chamber))
  {
    x++;
    if (x > 10) {
      Screen_open();
      chamber_lable = false;
      digitalWrite(door_chamber, HIGH);
      delay(10);
      Smoke();
      digitalWrite(fire, LOW);
      Screen_open();
      Serial.println("gasCamera");
      
      break;
    }
    delay(10);
  }
}

void Keyout()
{
  int x = 0;
  while (digitalRead(keyout))
  {
    x++;
    if (x > 10) {
      digitalWrite(door_out, LOW);
      Serial.println("win");
      delay(50);
      Finish();
      break;
    }
    delay(10);
  }
}

void Fire()
{
  int x = 0;
  while (!digitalRead(button)) // Кнопка замыкает на минус 5В
  {
    x++;
    if (x > 10) {
      chamber_lable = true;
      button_lable = false;
      BEEP(0);
      Smoke();
      BEEP(0);
      digitalWrite(fire, HIGH);
      Serial.println("fire");
      break;
    }
    delay(50);
  }
}



void Smoke()
{
  digitalWrite(smoke, HIGH);
  delay(500);
  digitalWrite(smoke, LOW);
  Serial.println("smoke");
}

void Screen_open()
{
  digitalWrite(screen_open, LOW);
  delay(timeScreen);
  digitalWrite(screen_open, HIGH);
}

void Screen_close()
{
  digitalWrite(screen_close, LOW);
  delay(timeScreen);
  digitalWrite(screen_close, HIGH);
}

void Blades()
{
  digitalWrite(blades, LOW);
  delay(500);
  digitalWrite(blades, HIGH);
}

void Finish()
{
  Screen_close();
  setup_out();
  res_logic();
  res_rele();
}

void BEEP(int f)
{
  if ((digitalRead(keyout)) or (!digitalRead(button)) or (chamber_lable))
  {
    if (millis() > beepTime + f)
    {
      switch (fl) {
        case 0: digitalWrite(beep, HIGH);
          fl = 1;
          break;
        case 1: digitalWrite(beep, LOW);
          fl = 0;
          break;
      }
      beepTime = millis();
    }
  }
  else {
    digitalWrite(beep, LOW);
    fl = 0;
  }
}

//void BEEP()
//{
//  if ((digitalRead(keyout)) or (!digitalRead(button)))
//  {
//    switch (u) {
//      case 0: if (p < 1024) p++;
//        else u = 1;
//        break;
//      case 1: if (p > 0) p--;
//        else u = 0;
//        break;
//    }
//    analogWrite(beep, p);
//    delay(1);
//  }
//  else digitalWrite(beep, LOW);
//}




////////////////////////////  Чтение порта  /////////////////////////////////////
void ReadSerial()
{
  switch (Serial.read()) {
    case '1':                             // Старт игры
      digitalWrite(beep, LOW);
      res_logic();
      fl = 0;
      beep_lable = false;
      Screen_close();
      Blades();
      digitalWrite(door_chamber, LOW);
      digitalWrite(mp3, LOW);
      digitalWrite(lamp, HIGH);
      digitalWrite(collar, LOW);
      digitalWrite(door_out, HIGH);
      Serial.println("New game");
      game = true;
      break;
    case '2':                             // Включить плеер
      digitalWrite(mp3, LOW);
      Serial.println("MP3 on");
      break;
    case '3':                             // Выключить плеер
      digitalWrite(mp3, HIGH);
      Serial.println("MP3 off");
      break;
    case '4':                             // Закрыть экран
      Screen_close();
      if (!svet) {
        digitalWrite(lamp, LOW);
        svet = true;
      }
      Serial.println("close screen");
      break;
    case '5':                             // Запустить лезвия
      Blades();
      break;
    case '6':                             // Включить свет
      digitalWrite(lamp, LOW);
      Serial.println("Svet on");
      break;
    case '7':                             // Выключить свет
      digitalWrite(lamp, HIGH);
      Serial.println("Svet off");
      break;
    case '8':                             // Открыть экран
      Screen_open();
      Serial.println("video");
      break;
    case '9':                             // Конец игры
      Serial.println("Game over");
      //Screen_close();
      res_logic();
      res_rele();
      break;
    case 'a':                            // Включить ошейник
      digitalWrite(collar, LOW);
      Serial.println("close collar");
      break;
    case 'b':                            // Выключить ошейник
      digitalWrite(collar, HIGH);
      Serial.println("open collar");
      break;
    case 'c':                            // Включить ремни на стуле

      break;
    case 'd':                            // Выключить ремни на стуле

      break;
    case 'e':                            // Открыть выходную дверь
      digitalWrite(door_out, LOW);
      break;
    case 'f':                            // Закрыть выходную дверь
      digitalWrite(door_out, HIGH);
      break;
    case 'g':                            // Режим "Подготовка"
      digitalWrite(lamp, LOW);
      digitalWrite(collar, LOW);
      digitalWrite(door_chamber, LOW);
      digitalWrite(door_out, HIGH);
      beep_lable = true;
      break;
    case 'h':                            // Открыть газовую камеру
      digitalWrite(door_chamber, HIGH);
      digitalWrite(beep, LOW);
      break;
    case 'k':                            // Включить теплопушку


    case 'l':                            // Включить кнопку авария
      chamber_lable = true;
      button_lable = false;
      delay(20);
      Smoke();
      digitalWrite(fire, HIGH);
      Serial.println("fire");
      break;
    case 'm':                            // Включить дым.машину
      Smoke();
      break;
    case 'n':                            //

      break;
    case 'o':                            //

      break;
    case 'p':                            //

      break;
    case 'r':                            //

      break;
    case 's':                            //

      break;
    case 't':                            //

      break;
  }
}

P.S. Плата Arduino Mega R3 2560, Ethernet-Shield W5100.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Satanael пишет:

как мне по запросу с браузера заставить работать определённый цикл в программе. По нажатию "Start" (HTTP_req, "pin=01") должен выполняться "case '1'", по нажатию "Stop"(HTTP_req, "pin=02" "case 'g'" из цикла void ReadSerial(){switch (Serial.read())......} (находится в конце скетча).

Никак. Так не делается.

И, да, про цикл return не забываем.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Satanael пишет:
проблема в том, то я не могу понять ...

Ну, это ведь не вопрос - это утверждение. Оно принято к сведению. Вопросы у Вас есть? Чего Вы ждёте от сообщества, опубликовав Ваш пост? Вы ждёте, что Вам посочувствуют? Подскажут литературу? Поменяют Ваш код за Вас? Что Вам нужно-то? 

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016
void loop() {
  String req;
  char c;
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        req+=c;
        if (c == '\n' && currentLineIsBlank) {
//          if (req.indexOf("?")>-1) Serial.println(req.substring(6,req.indexOf(" HTTP")));          // DEBUG: Dump request
          // приём, получает поля GET запроса (то что есть в URI)
          if(req.indexOf("ovenunlock")>-1)         locks(2);
          if(req.indexOf("secretunlock")>-1)       locks(3);
          if(req.indexOf("door1unlock")>-1)        locks(4);
          if(req.indexOf("door2unlock")>-1)        locks(5);
          // ..........
          // поняли смысл?
          if(req.indexOf("room2l_on")>-1)          setlight(2,1);
          if(req.indexOf("room2l_off")>-1)         setlight(2,0);
          if(req.indexOf("room1l_on")>-1)          setlight(1,1);
          if(req.indexOf("room1l_off")>-1)         setlight(1,0);
          // и т д и т п
//          Serial.println(req);                       // DEBUG: Dump HTTP data
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: application/json");
          client.println("Access-Control-Allow-Origin: *");
          client.println("Connection: close");
          client.println();
          // передача
          client.print("{");
          client.print("\"thr0\":\"");
          client.print(throne0);
          client.print("\",\"thr1\":\"");
          client.print(s_throne[0]);
          // ....
          client.print("\",\"sf\":\"");
          client.print(seq_fr);
          client.print("\",\"sn\":\"");
          client.print(seq_n);
          client.print("\"");
          client.println("}"); // end JSON
          req="";
          break;
        }
        if (c == '\n') currentLineIsBlank = true;
         else if (c != '\r') currentLineIsBlank = false;
      }
    }
    delay(1);
    client.stop();
  }
  time_current=millis();  // яж надеюсь ясно зачем это
  service_door();         // асинхронные (отвязанные от delay) службы
  service_jaws();
  service_locks();
  // .........
}
Satanael
Offline
Зарегистрирован: 22.06.2018

Выходит, что я могу управлять лишь отдельными элементами кода и переменными?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Не, не можешь, это куклавуд может :)))

Satanael
Offline
Зарегистрирован: 22.06.2018

Спасибо Voodoo Doll. Долго ломал голову как оно работает, а по факту просто на каждое действие нужна отдельная кнопка со ссыкой, части которых будут отлавливаться кодом и менять значение переменных либо слать сигнал прямо в порт. Вот только пока не додумался что писать в сервисы.

Satanael
Offline
Зарегистрирован: 22.06.2018

Чем больше думаю тем больше понимаю - в сервис пишется переменная (как locks в примере). Получается, что в service_locks пишется переменная которая отвечает за отправку сигнала в тот или иной порт, а так же там можно указать часть программы которая будет выполняться при вызове переменной из сервиса.

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Satanael

Исходник выложен мной в таком виде не потому что было лень чистить, а потому что я хочу, чтобы отложилось главное: любые сервисные функции должны быть неблокирующими. В эскейп-румах, да и вообще любых субклассах неглупого дома код типа while(!digitalRead(N)) является в недопустимым, особенно если после while стоят пустые скобки, NOP или точка с запятой - это всё равно что программе сказали: "Вась, покури тут пока кнопку нажмут, вот тебе 40-тонный контейнер Marlboro, как останется последняя пачка - ещё подвезу". И программа будет тупить и курить, потому что курево у неё не кончится - просто примите как данность, что с открытием последней пачки чудодейственным образом из ничего материализуется новый контейнер, битком набитый такими же пачками. Несмотря ни на какие доводы Лавуазье и Ломоносова о том, что ничто не появляется из ничего. Курение так и будет продолжаться, пока условие в while не станет ложно.

В каждой из service_xxxx(), locks(), setlight() - либо максимально короткое действие которое не замедлит опрос Ethernet, либо максимально нечувствительное к многократному повторению действие. Дверь закрылась? Чудно, подаём единицу на транзистор, коммутирующий замок. Или двигатель, у которого предусмотрены оба концевика. Следующий проход loop()? Дверь не открыли? Подаём единицу. Уже была? Плевать, подаём единицу. Пятьсот, тысячу, 2 млн. раз в секунду. Другая секунда? Ну, может надо что-то открыть - это предусматривается в функциях service_xxxx(). Переменная, которая помнит такие секунды - unsigned long time_current;. Как-то так.