Ошибка компиляции: "cannot declare 'client' to be of abstract type 'Client'"

Я знаю, что это не мой исходный код, но я использую его для более крупного проекта, над которым сейчас работаю. Я продолжаю получать это сообщение об ошибке: «невозможно объявить «клиент» абстрактным типом «Клиент»». вот код:

// RoboSapienServer.cpp
// RobosapienServer — веб-включение RoboSapien
// Кевин Н. Хоу
// http://www.KevinHaw.com/RoboSapienServer.php

// Этот проект объединяет пример веб-сервера по умолчанию в дистрибутиве IDE и RoboSapienIR Карла Каслтона (http://home.mesastate.edu/~kcastlet) (http://playground.arduino.cc/Main/RoboSapienIR).
// Исходный код объединен из этих двух источников.

// Включить файлы
#include <Ethernet.h>
#include <string.h>
#include <WebServer.h>

////////////////////////////////////////////////// ////////////////
// Начать определения переменных, специфичных для веб-сервера
////////////////////////////////////////////////// ////////////////

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// KNH, 09.02.2010 - Смена IP-адреса для использования локальной подсети дома
//byte ip[] = { 10, 0, 0, 177 };
byte ip[] = { 192, 168, 1, 177 };

// Сервер для веб-запросов
EthernetServer server(80);

// Определяем имя поля в отправленной форме
#define SUBMIT_BUTTON_FIELDNAME "RSCmd"

// Строка для переменных HTTP-запроса
char pcHttpReqRsCmd[20] = {'\0'};


volatile int viRobsapienUrlCmd = -1;  // Команда robosapien, отправленная по URL-адресу HTTP-запроса веб-страницы


////////////////////////////////////////////////// ////////////////
// Начать определение переменных, специфичных для Robosapien
////////////////////////////////////////////////// ////////////////


// Определены некоторые, но не все команды RS
#define RSTurnRight       0x80
#define RSRightArmUp      0x81
#define RSRightArmOut     0x82
#define RSTiltBodyRight   0x83
#define RSRightArmDown    0x84
#define RSRightArmIn      0x85
#define RSWalkForward     0x86
#define RSWalkBackward    0x87
#define RSTurnLeft        0x88
#define RSLeftArmUp       0x89
#define RSLeftArmOut      0x8A
#define RSTiltBodyLeft    0x8B
#define RSLeftArmDown     0x8C
#define RSLeftArmIn       0x8D
#define RSStop            0x8E
#define RSWakeUp          0xB1
#define RSBurp            0xC2
#define RSRightHandStrike 0xC0
#define RSNoOp            0xEF

// Подмножество дополнительных кодов, взятых с http://www.contrib.andrew.cmu.edu/~ebuehl/robosapien-lirc/ir_codes.htm
#define RSRightHandSweep  0xC1
#define RSRightHandStrike2 0xC3
#define RSHigh5           0xC4
#define RSFart            0xC7
#define RSLeftHandStrike  0xC8
#define RSLeftHandSweep  0xC9

#define RSWhistle         0xCA
#define RSRoar            0xCE


int IRIn = 2;            // Мы будем использовать прерывание
int IROut = 3;           // Откуда будет отправлена эхо-команда


boolean RSEcho = true;    // Должны ли команды Arduino Echo RS
boolean RSUsed = true;    // Была ли использована последняя команда
volatile int RSBit = 9;   // Всего бит данных
volatile int RSCommand;   // Однобайтовая команда из ИК
int bitTime = 516;        // Битовое время (теоретически 833, но 516)
// работает на передачу и быстрее
int last;                 // Предыдущая команда из ИК





////////////////////////////////////////////////// ////////////////
// Начать специальный код Robosapien
////////////////////////////////////////////////// ////////////////



// Получаем понемногу.
// ПРИМЕЧАНИЕ. Не используется в приложении RoboServer.
void RSReadCommand() {
  delayMicroseconds(833 + 208); // примерно 1 1/4 бита
  int bit = digitalRead(IRIn);
  if (RSBit == 9) { // Должно быть начало новой команды
    RSCommand = 0;
    RSBit = 0;
    RSUsed = true;
  }
  if (RSBit < 8) {
    RSCommand <<= 1;
    RSCommand |= bit;
  }
  RSBit++;
  if (RSBit == 9) RSUsed = false;
}

// отправляем все 8 бит
void RSSendCommand(int command) {
  digitalWrite(IROut, LOW);
  delayMicroseconds(8 * bitTime);
  for (int i = 0; i < 8; i++) {
    digitalWrite(IROut, HIGH);
    delayMicroseconds(bitTime);
    if ((command & 128) != 0) delayMicroseconds(3 * bitTime);
    digitalWrite(IROut, LOW);
    delayMicroseconds(bitTime);
    command <<= 1;
  }
  digitalWrite(IROut, HIGH);
  delay(250); // Даем 1/4 секунды до следующего
}


// Настраиваем функциональность RoboSpapien
void RSSetup()
{
  pinMode(IRIn, INPUT);
  pinMode(IROut, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(IROut, HIGH);

  attachInterrupt(0, RSReadCommand, RISING);

  last = RSNoOp;

  // Сделать отрыжку робота, чтобы показать, что настройка завершена
  RSSendCommand(RSBurp);

}


// Цикл для функциональности RoboSapien
// Функциональность только для записи - отправить команду с веб-страницы роботу, игнорируя любой ввод с удаленного
void RSLoop()
{
  // Пришла ли новая команда с сервера?
  if (viRobsapienUrlCmd != -1)
  {
    // Новая команда - отправляем ее роботу
    Serial.print("Sending command to RoboSapien: ");
    Serial.println(viRobsapienUrlCmd, HEX);
    RSSendCommand(viRobsapienUrlCmd);

    // Теперь очистить команду
    viRobsapienUrlCmd = -1;
  }
}

////////////////////////////////////////////////// ////////////////
// Запуск кода, специфичного для веб-сервера
////////////////////////////////////////////////// ////////////////

// Печатаем наш заголовок MIME и HTML в верхней части веб-страницы
void HtmlHeader(Client client)
{
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println();
  client.println("<HTML>\n<HEAD>");
  client.println("  <TITLE>Kevin's Arduino Webserver</TITLE>");//
  // client.println("<META HTTP-EQUIV=\"обновить\" CONTENT=\"5\">");
  client.println("</HEAD><BODY bgcolor=\"#9bbad6\">");
}

// Печать нижнего колонтитула в нижней части веб-страницы
void HtmlFooter(Client client)
{
  client.println("</BODY></HTML>");
}

// Печать кнопки отправки с указанной меткой, обернутой в форму для указанной шестнадцатеричной команды
void SubmitButton(Client &client, char *pcLabel, int iCmd)
{
  client.print("<form method=post action=\"/?");
  client.print(iCmd, HEX);
  client.print("\"><input type=submit value=\"");
  client.print(pcLabel);
  client.print("\" name=\"" SUBMIT_BUTTON_FIELDNAME "\">");
  client.println("</form>");
}

// Разбираем заголовок HTTP-запроса посимвольно, ищем строковые переменные
void ParseHttpHeader(Client &client)
{
  char c;

  // Пропускаем, пока не наткнемся на вопросительный знак (первый)
  while ((c = client.read()) != '?' && client.available())
  {
    // Отладка - печать данных
    Serial.print(c);
  }

  // Мы здесь из-за вопросительного знака или у нас закончились данные?
  if (client.available() > 2)
  {
    char pcUrlNum[3], *pc;

    // У нас достаточно данных для шестнадцатеричного числа - читаем его
    for (int i = 0; i < 2; i++)
    {
      // Чтение и сброс данных в порт отладки
      Serial.print(c = pcUrlNum[i] = client.read());
    }
    // Нулевая завершающая строка
    pcUrlNum[2] = '\0';

    // Получить шестнадцатеричное число
    viRobsapienUrlCmd = strtol(pcUrlNum, &pc, 0x10);
  }

  // Пропустить и удалить все оставшиеся данные
  while (client.available())
  {
    // Отладка - печать данных
    Serial.print(c = client.read());
  }
}

// Настраиваем функциональность веб-сервера
void WebServerSetup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

// Цикл веб-сервера
void WebServerLoop()
{
  Client client = server.available();
  boolean bPendingHttpResponse = false; // Истинно, когда мы получили весь HTTP-запрос и нам нужно вывести веб-страницу
  char c;  // Для чтения в HTTP-запросе по одному символу за раз

  if (client) {
    // Цикл, пока есть соединение
    while (client.connected()) {
      // Есть ли у нас ожидающие данные (запрос HTTP)?
      if (client.available()) {

        // Указываем, что нам нужно ответить на HTTP-запрос, как только мы закончим его обработку
        bPendingHttpResponse = true;

        ParseHttpHeader(client);
      }
      else
      {
        // В клиентском сокете нет данных, ожидающих чтения. У нас есть ожидающий HTTP-запрос?
        if (bPendingHttpResponse)
        {
          // Да, у нас есть ожидающий запрос. Снимите флажок, а затем отправьте веб-страницу клиенту.
          bPendingHttpResponse = false;

          // отправляем стандартный HTTP-заголовок ответа и HTML-заголовок
          HtmlHeader(client);

          // Выводим текстовый заголовок
          client.println("<H1>Kevin's RoboSapien Webserver</H1>");

          client.println("<table border cellspacing=0 cellpadding=5><tr>");
          client.println("<td>");

          // Создаем кнопки
          SubmitButton(client, "WakeUp", RSWakeUp);
          SubmitButton(client, "Roar", RSRoar);
          SubmitButton(client, "Whistle", RSWhistle);
          SubmitButton(client, "High5", RSHigh5);
          client.println("<br>");

          client.println("</td><td>");

          SubmitButton(client, "LeftArmUp", RSLeftArmUp);
          SubmitButton(client, "LeftArmIn", RSLeftArmIn);
          SubmitButton(client, "LeftArmOut", RSLeftArmOut);
          SubmitButton(client, "LeftArmDown", RSLeftArmDown);
          SubmitButton(client, "LeftArmSweep", RSLeftHandSweep);
          client.println("<br>");

          client.println("</td><td>");

          SubmitButton(client, "RightArmUp", RSRightArmUp);
          SubmitButton(client, "RightArmIn", RSRightArmIn);
          SubmitButton(client, "RightArmOut", RSRightArmOut);
          SubmitButton(client, "RightArmDown", RSRightArmDown);
          SubmitButton(client, "RightArmSweep", RSRightHandSweep);
          client.println("<br>");

          client.println("</td></tr></table>");

          client.print("<br><br><br>URL Hex no: ");
          client.print(viRobsapienUrlCmd, HEX);
          client.println("<br />");

          // отправить нижний колонтитул HTML
          HtmlFooter(client);

          // дать веб-браузеру время для получения данных
          delay(1);
          client.stop();
        }
      }
    }  // Конец пока(подключено)
  }
}

////////////////////////////////////////////////// ////////////////
// начинаем точки входа arduino
////////////////////////////////////////////////// ////////////////

void setup()
{
  // открываем последовательный порт на скорости 9600 бит/с:
  Serial.begin(9600);

  // Распечатать приветствие
  Serial.println("Kevin's RobSapien Server");

  RSSetup();
  WebServerSetup();
}

void loop()
{
  RSLoop();
  WebServerLoop();
}

, 👍2


2 ответа


2

Вы не можете напрямую использовать Клиент. Это просто абстрактный класс. Вы должны использовать один из классов, таких как EthernetClient или WiFiClient, который его реализует.

Клиент похож на оболочку класса. В нем говорится, что будут классы, которые действуют как клиенты и будут иметь эту базовую форму. Но у него нет никакого кода, только схема. Базовые классы, которые реализуют этот абстрактный класс, например EthernetClient или WiFiClient, на самом деле имеют код, который фактически БУДЕТ клиентом.

,

0

Я предполагаю, что проблема здесь:

void HtmlFooter(Client client) { 
    client.println("</BODY></HTML>"); 
} 

(также функция HtmlHeader)

Когда вы вызываете эту функцию, вы создаете новый объект Client и копируете в него содержимое существующего объекта. Поскольку клиент является чисто виртуальным, вы не можете этого сделать. Вместо этого вы должны работать со ссылкой, как и в других функциях:

void HtmlFooter(Client &client) {   
    client.println("</BODY></HTML>"); 
} 
,