diff --git a/code/Arduino/config/Constants.cpp b/code/Arduino/config/Constants.cpp index c9e2008..2180006 100644 --- a/code/Arduino/config/Constants.cpp +++ b/code/Arduino/config/Constants.cpp @@ -53,6 +53,7 @@ const uint32_t Constants::kBluetoothSerialSpeed = 9600; // const uint8_t Constants::wifi_RX = 17; // const uint8_t Constants::wifi_TX = 16; const uint32_t Constants::kWifiSerialSpeed = 115200; +const uint32_t Constants::kWifiHandshakeWaitMs = 30000; /* USB (Hardware Serial) */ // const uint8_t Constants::usb_RX = 0; diff --git a/code/Arduino/config/Constants.h b/code/Arduino/config/Constants.h index c656928..5c2fc55 100644 --- a/code/Arduino/config/Constants.h +++ b/code/Arduino/config/Constants.h @@ -12,6 +12,7 @@ class Constants // static const uint8_t wifi_RX; // static const uint8_t wifi_TX; static const uint32_t kWifiSerialSpeed; + static const uint32_t kWifiHandshakeWaitMs; // static const uint8_t usb_RX; // static const uint8_t usb_TX; diff --git a/code/Arduino/connection/Bluetooth.cpp b/code/Arduino/connection/Bluetooth.cpp index c5d44d8..3114427 100644 --- a/code/Arduino/connection/Bluetooth.cpp +++ b/code/Arduino/connection/Bluetooth.cpp @@ -4,12 +4,14 @@ bool Bluetooth::is_inited_ = false; -Bluetooth::Bluetooth(unsigned long speed) : IConnector(&Serial3) +#define MODULE_SERIAL Serial2 + +Bluetooth::Bluetooth(unsigned long speed) : IConnector(&MODULE_SERIAL) { if (!is_inited_) { is_inited_ = true; - Serial3.begin(speed); + MODULE_SERIAL.begin(speed); DisplayManager::get_manager()->init_connector(ConnectorEnum::bluetooth_connector); } } diff --git a/code/Arduino/connection/DebugSerial.cpp b/code/Arduino/connection/DebugSerial.cpp index 7b48f33..1264dbe 100644 --- a/code/Arduino/connection/DebugSerial.cpp +++ b/code/Arduino/connection/DebugSerial.cpp @@ -21,7 +21,7 @@ Stream* DebugSerial::get_serial() return serial_; } -void DebugSerial::write_answer(uint8_t* answer_ptr, int length) +void DebugSerial::write_answer(const uint8_t* answer_ptr, int length) { IConnector::write_answer(answer_ptr, length); } diff --git a/code/Arduino/connection/DebugSerial.h b/code/Arduino/connection/DebugSerial.h index 4d8d300..d5dcd55 100644 --- a/code/Arduino/connection/DebugSerial.h +++ b/code/Arduino/connection/DebugSerial.h @@ -48,7 +48,7 @@ class DebugSerial : public IConnector * * @param answer_ptr String to send */ - void write_answer(uint8_t* answer_ptr, int length) override; + void write_answer(const uint8_t* answer_ptr, int length) override; /** * @brief Prints data string to debug console * diff --git a/code/Arduino/connection/IConnector.cpp b/code/Arduino/connection/IConnector.cpp index 3ea0cab..795676d 100644 --- a/code/Arduino/connection/IConnector.cpp +++ b/code/Arduino/connection/IConnector.cpp @@ -18,11 +18,12 @@ IConnector::IConnector(int rx, int tx, unsigned long speed) device_->setTimeout(Constants::kCommandsWaitTime); } -void IConnector::write_answer(uint8_t* answer_ptr, int length) +void IConnector::write_answer(const uint8_t* answer_ptr, int length) { + const char* ptr = reinterpret_cast(answer_ptr); for (int i = 0; i < length; ++i) { - device_->print((reinterpret_cast(answer_ptr))[i]); + device_->print(ptr[i]); } } diff --git a/code/Arduino/connection/IConnector.h b/code/Arduino/connection/IConnector.h index a1ee0c4..d4da031 100644 --- a/code/Arduino/connection/IConnector.h +++ b/code/Arduino/connection/IConnector.h @@ -16,6 +16,6 @@ class IConnector virtual bool is_need_to_read_message(); virtual int read_message(uint8_t* pointer, int max_length); - virtual void write_answer(uint8_t* answer_ptr, int length); + virtual void write_answer(const uint8_t* answer_ptr, int length); }; diff --git a/code/Arduino/connection/WiFi_my.cpp b/code/Arduino/connection/WiFi_my.cpp index 39f2f4a..d2e30e9 100644 --- a/code/Arduino/connection/WiFi_my.cpp +++ b/code/Arduino/connection/WiFi_my.cpp @@ -1,263 +1,179 @@ -#include "ConnectorEnum.h" -#include "../peripheral/display/DisplayManager.h" -#include "WiFi_my.h" -#include "../utils/Timer.h" +#include "WiFi_my.h" #include "DebugSerial.h" +#include "../config/Constants.h" +#include "../peripheral/display/DisplayManager.h" + +#define MODULE_SERIAL Serial3 -WiFi_my::WiFi_my(unsigned long speed) :IConnector(&Serial2) { - //Добавить вывод IP +WiFi_my::WiFi_my(unsigned long speed) :IConnector(&MODULE_SERIAL) { DEBUG_PRINTLN("Constructor wifi"); if (is_inited_) { return; } is_inited_ = true; - Serial2.begin(speed); - is_server_started_ = false; - DEBUG_PRINTLN("Constructor wifi2"); - for (uint32_t i = 0; i <= MAX_CONNECT_ID; i++) { - connected_ids_[i] = NOT_CONNECTED; - } - start_tcp_server(); - DEBUG_PRINTLN("Constructor wifi3"); - - DisplayManager::get_manager()->init_connector(ConnectorEnum::wifi_connector); -} + MODULE_SERIAL.begin(speed); -bool WiFi_my::start_tcp_server() { - device_->print(SET_WIFI_MODE_COM); - String answer = read_answer(); - if (!answer.startsWith(SET_WIFI_MODE_COM) && !answer.endsWith(POSITIVE_ANSWER)) { - is_server_started_ = false; - return false; + connect_to_module(); + if (is_connected_) + { + DisplayManager::get_manager()->init_connector(ConnectorEnum::wifi_connector); } - DEBUG_PRINTLN("WiFi_my mode was set."); - device_->print(ENABLE_MULTIPLE_CONNECTION_COM); - answer = read_answer(); - if (!answer.startsWith(ENABLE_MULTIPLE_CONNECTION_COM) && !answer.endsWith(POSITIVE_ANSWER)) { - is_server_started_ = false; - return false; - } - DEBUG_PRINTLN("multiple connection was set."); + DEBUG_PRINTLN("Constructor wifi end"); +} - device_->print(SETUP_SERVER_COM); - answer = read_answer(); - if (!answer.startsWith(SETUP_SERVER_COM) && !answer.endsWith(POSITIVE_ANSWER)) { - is_server_started_ = false; - return false; - } - DEBUG_PRINTLN("server started."); - DEBUG_PRINTLN("Port: " + PORT); - device_->print(GET_IP_MAC); - answer = read_answer(); - String ip = answer.substring(answer.indexOf("+CIFSR:APIP,\"") + String("+CIFSR:APIP,\"").length(), - answer.indexOf("+CIFSR:APMAC,") - 3); - DEBUG_PRINTLN("IP: " + ip); - is_server_started_ = true; - return true; +bool WiFi_my::is_module_connected() const +{ + return is_connected_; } -//void WiFi_my::stop_connection(int id) { -// device_->print(DELETE_TCP_CONNECTION + String(char(id)) + EOC); -// String answer = read_answer(); -// if (!answer.endsWith(POSITIVE_ANSWER)) { -// DEBUG_PRINTLN("Error in deleting the connection.(stopConnection method)."); -// } -//} +bool WiFi_my::is_message_was_read_before_timeout(Timer& timer, const char* to_compare, const uint16_t length) +{ + static const int kDelayMs = 100; -String WiFi_my::read_answer() { - char buf[BUFFER_SIZE]; - for (uint32_t i = 0; i < BUFFER_SIZE; i++) { - buf[i] = 0; - } + const bool prev_is_connected = is_connected_; + is_connected_ = true; - //block for not receiving data - Timer timer(MAX_WAIT_ANSWER_MS); - timer.start_or_resume(); - while (!timer.isFinished()) { - if (device_->available()) { - device_->readBytes(buf, BUFFER_SIZE); - break; - } - } - if (timer.isFinished()) + while (!(is_need_to_read_message() && is_message_equal(to_compare, length))) { - DEBUG_PRINTLN("WiFi read timer timeout. ERROR"); + if (timer.isFinished()) + { + is_connected_ = prev_is_connected; + return false; + } + delay(kDelayMs); } - - DEBUG_PRINTLN("Read ans: " + String(buf)); - DEBUG_PRINT("Read hex ans: "); - DEBUG_PRINTLNHEX(buf); - return String(buf); + is_connected_ = prev_is_connected; + return true; } -//int WiFi_my::wait_client() { -// String answer = read_answer(); -// String str_number = answer.substring(0, answer.indexOf(",CONNECT")); -// int num = atoi(str_number.c_str()); -// return num; -//} +bool WiFi_my::is_message_equal(const char* to_compare, const uint16_t length) +{ + uint8_t buffer[BUFFER_SIZE] = { 0 }; + const uint16_t read_length = read_message(buffer, sizeof(buffer)); -bool WiFi_my::is_need_to_read_message() { - if (!is_server_started_) + if (length != read_length) { return false; } - //DEBUG_PRINTLN("IMPORTANT: " + String((int)'\|')); - //DEBUG_PRINTLN(String(__LINE__)); - char buf[BUFFER_SIZE]; - memset(buf, 0, BUFFER_SIZE); - if (device_->available()) { - device_->readBytes(buf, BUFFER_SIZE); - } - else { -#ifdef DEBUG_ON - static int i = 0; - i++; - if (i > 12000) - { - DEBUG_PRINTLN("From Wifi: " + String(__LINE__)); - i = 0; - } + return (memcmp(buffer, to_compare, length) == 0); +} - if (!data_buffer_.isEmpty()) - { - DEBUG_PRINTLN("Wifi: need to read message"); - } -#endif - return !data_buffer_.isEmpty(); - } - String buf_str(buf); - while (buf_str.startsWith("\r\n")) { - buf_str = buf_str.substring(2); - } +void WiFi_my::connect_to_module() +{ + const char require_request[] = "I'm ready, Milord!"; + const char require_second_request[] = "Yes, Sir"; + const char responce[] = "Sir"; + + Timer timer(Constants::kWifiHandshakeWaitMs); + timer.start_or_resume(); - if (buf_str.length() == 0) + if (!is_message_was_read_before_timeout(timer, require_request, strlen(require_request))) { - return !data_buffer_.isEmpty(); + DEBUG_PRINTLN("Handshake part 1 error"); + return; } - DEBUG_PRINTLN("Text Buf: "); - DEBUG_PRINTLN(buf_str); - - DEBUG_PRINTLN("Buf: "); - DEBUG_PRINTLNHEX(buf_str); - - //don't lose last command - buf_str += EOC; - - String sub_str = buf_str.substring(0, buf_str.indexOf("\r\n")); - while (buf_str.indexOf("\r\n") != -1) { - //DEBUG_PRINT("SubStr: "); - //DEBUG_PRINTLNHEX(subStr); - if (sub_str.indexOf(",CONNECT") != -1) { - String str_number = sub_str.substring(0, sub_str.indexOf(",CONNECT")); - uint32_t num = str_number.toInt(); - connected_ids_[num] = CONNECTED; - DEBUG_PRINTLN("Connected: " + String(num)); - } - else if (sub_str.indexOf(",CLOSED") != -1) { - String str_number = sub_str.substring(0, sub_str.indexOf(",CLOSED")); - uint32_t num = str_number.toInt(); - connected_ids_[num] = NOT_CONNECTED; - DEBUG_PRINTLN("Disconnected: " + String(num)); - } - else if (sub_str.indexOf(INFO_PREFIX) != -1) { - DEBUG_PRINTLN("WiFi: IPD detect"); - String data = sub_str.substring(sub_str.indexOf(":") + 1); - DEBUG_PRINT("WiFi: data in IPD: "); - DEBUG_PRINTLNHEX(data); - if (data.length()) { - data_buffer_.push(data); - DEBUG_PRINT("Get data: "); - DEBUG_PRINTLNHEX(data); - } - } - //... + const bool prev_is_connected = is_connected_; + is_connected_ = true; + write_answer(reinterpret_cast(responce), strlen(responce)); + is_connected_ = prev_is_connected; - buf_str = buf_str.substring(buf_str.indexOf("\r\n") + 2); - sub_str = buf_str.substring(0, buf_str.indexOf("\r\n")); + if (!is_message_was_read_before_timeout(timer, require_second_request, strlen(require_second_request))) + { + DEBUG_PRINTLN("Handshake part 3 error"); + return; } - DEBUG_PRINTLN(String(__LINE__)); - DEBUG_PRINTF("Is data buffer empty: %d\n", data_buffer_.isEmpty()); - return !data_buffer_.isEmpty(); + is_connected_ = true; + DEBUG_PRINTLN("Wi-Fi was connected"); } -String WiFi_my::get_message() { - char buf[BUFFER_SIZE]; - for (uint32_t i = 0; i < BUFFER_SIZE; i++) { - buf[i] = 0; - } - while (true) { - if (device_->available()) { - device_->readBytes(buf, BUFFER_SIZE); - break; - } - } - String data = String(buf); - DEBUG_PRINTLN("Read: " + data); - int infoStartIndex = data.indexOf(":") + 1; - String info = data.substring(infoStartIndex); - return info; +bool WiFi_my::is_need_to_read_message() { + return is_connected_ && device_->available(); } -void WiFi_my::write_answer(uint8_t* answer_ptr, int length) { - if (!length || !is_server_started_) { +void WiFi_my::write_answer(const uint8_t* answer_ptr, int length) { + if (!length || !is_connected_) { return; } - //remove crc from message - static const int kCrcLength = sizeof(uint16_t); - length -= kCrcLength; + uint8_t buffer_ptr[BUFFER_SIZE]; + int buffer_length = 0; - String command = SEND_BUFFER_COM + length + EOC; // may be space needed.(between command and length.) - device_->print(command); - String answer = read_answer(); - if (!answer.indexOf('>') == -1) { - DEBUG_PRINTLN("Can't send info (method send)"); - is_server_started_ = false; - return; - } - IConnector::write_answer(answer_ptr, length); - answer = read_answer(); - if (!answer.endsWith("SEND OK" + EOC)) { - DEBUG_PRINTLN("Error in answer (method send)"); + for (int i = 0; i < length && buffer_length < (BUFFER_SIZE - 2); i++, buffer_length++) + { + switch (answer_ptr[i]) + { + case 10: + buffer_ptr[buffer_length] = 10; + buffer_length++; + buffer_ptr[buffer_length] = 10; + break; + case 13: + buffer_ptr[buffer_length] = 10; + buffer_length++; + buffer_ptr[buffer_length] = 11; + break; + default: + buffer_ptr[buffer_length] = answer_ptr[i]; + break; + } } + + buffer_ptr[buffer_length] = stop_symbol_; + buffer_length++; + + IConnector::write_answer(buffer_ptr, buffer_length); } int WiFi_my::read_message(uint8_t* pointer, int max_length) { - if (!is_server_started_) + if (!is_connected_ || !max_length) { return 0; } - static const int kLenSize = 0; - static const int kCrcAndLenSize = 2 + kLenSize; + bool is_escaped = false; + int answer_length = 0; + uint8_t buffer_ptr[BUFFER_SIZE] = { 0 }; + const int buffer_length = device_->readBytesUntil(stop_symbol_, buffer_ptr, BUFFER_SIZE); - if (!data_buffer_.isEmpty()) { - String data = data_buffer_.pop(); - DEBUG_PRINT("FROM VECTOR: "); - DEBUG_PRINTLNHEX(data); - - if (max_length < static_cast(data.length() + kCrcAndLenSize)) + for (int buffer_i = 0; answer_length < max_length && buffer_i < buffer_length; answer_length++, buffer_i++) + { + if (is_escaped) { - DEBUG_PRINTF("Message was so long: %d (buffer size %d)\n", data.length(), max_length); - return 0; + is_escaped = false; + switch (buffer_ptr[buffer_i]) + { + case 10: + pointer[answer_length] = 10; + break; + case 11: + pointer[answer_length] = 13; + default: + DEBUG_PRINTLN("Escape parsing error from Wi-Fi"); + return -1; + } + } + else + { + switch (buffer_ptr[buffer_i]) + { + case 10: + is_escaped = true; + answer_length--; + break; + case 13: + return answer_length; + default: + pointer[answer_length] = buffer_ptr[buffer_i]; + break; + } } - - memset(pointer, 0, data.length() + kCrcAndLenSize); - - //length in message now - //memset(pointer, data.length(), kLenSize); - memcpy(pointer + kLenSize, data.c_str(), data.length()); - uint16_t crc16 = crc_calculator_.modbus(pointer, data.length() + kLenSize); - memcpy(pointer + data.length() + kLenSize, &crc16, kCrcAndLenSize - kLenSize); - - return (data.length() + kCrcAndLenSize); } - return 0; -} \ No newline at end of file + + return answer_length; +} diff --git a/code/Arduino/connection/WiFi_my.h b/code/Arduino/connection/WiFi_my.h index bf00ec2..17fe6f1 100644 --- a/code/Arduino/connection/WiFi_my.h +++ b/code/Arduino/connection/WiFi_my.h @@ -1,55 +1,25 @@ #pragma once -#include - -#include "../utils/Vector.h" #include "IConnector.h" +#include "../utils/Timer.h" -const uint32_t MAX_CONNECT_ID = 4; -const uint32_t CONNECTED = 1; -const uint32_t NOT_CONNECTED = 0; -const uint32_t MAX_WAIT_ANSWER_MS = 3000; - -// COM = command, EOC = end of command. -const String PORT = "333"; -const String LINK_ID = "0"; -const String EOC = "\r\n"; // end of command -const String POSITIVE_ANSWER = "OK" + EOC; -const String NEGATIVE_ANWSER = "ERROR" + EOC; -const String SET_WIFI_MODE_COM = "AT+CWMODE=3" + EOC; -const String ENABLE_MULTIPLE_CONNECTION_COM = "AT+CIPMUX=1" + EOC; -const String SETUP_SERVER_COM = "AT+CIPSERVER=1," + PORT + EOC; -const String SEND_BUFFER_COM = "AT+CIPSENDBUF=" + LINK_ID + ","; -const String DELETE_TCP_CONNECTION = "AT+CIPCLOSE="; -const String GET_IP_MAC = "AT+CIFSR" + EOC; -const String INFO_PREFIX = "+IPD,"; // port: 333, IP: 192.168.4.1 class WiFi_my : public IConnector { private: bool is_inited_ = false; - bool is_server_started_ = false; - Vector data_buffer_; - // 1 - there is connection with this ID, 0 - there is no connection with this ID. (id - is num of element) - uint32_t connected_ids_[MAX_CONNECT_ID + 1]; - FastCRC16 crc_calculator_; - - // port is declareted in constants above. - bool start_tcp_server(); - // if send 5 as id, you will discconect all connections - //void stop_connection(int id); - String read_answer(); - // retrun number of connection - //int wait_client(); + bool is_connected_ = false; + const uint8_t stop_symbol_ = 13; - // synchronous methods - String get_message(); + void connect_to_module(); + bool is_message_was_read_before_timeout(Timer& timer, const char* to_compare, const uint16_t length); + bool is_message_equal(const char* to_compare, const uint16_t length); public: - WiFi_my(unsigned long speed); + bool is_module_connected() const; bool is_need_to_read_message() override; // return empty string if there is not data. int read_message(uint8_t* pointer, int max_length) override; - void write_answer(uint8_t* answer_ptr, int length) override; + void write_answer(const uint8_t* answer_ptr, int length) override; }; \ No newline at end of file diff --git a/code/c++/cxx-api/SerialConnector.cpp b/code/c++/cxx-api/SerialConnector.cpp index 157a0c4..c75a00d 100644 --- a/code/c++/cxx-api/SerialConnector.cpp +++ b/code/c++/cxx-api/SerialConnector.cpp @@ -2,10 +2,6 @@ #include "SerialConnector.h" #include "trackPlatformAllExceptions.h" -extern "C" { -#include "checksum.h" -} - void SerialConnector::write(const std::string& s) { writePort->write(s); @@ -31,43 +27,15 @@ SerialConnector::~SerialConnector() delete readPort; } -std::string SerialConnector::read() +std::string SerialConnector::streamRead(uint64_t size) { - if (buffer.empty()) - { - buffer += readPort->read(sizeof(uint8_t)); - } - if (buffer.empty()) - { - throw TimeoutException(); - } - const uint8_t len = buffer[0]; - const uint16_t substring_len = sizeof(len) + len + crc_length; - if ((substring_len) > buffer.length()) - { - buffer += readPort->read(std::max(substring_len - sizeof(len), readPort->available())); - } - - if ((substring_len) > buffer.length()) - { - throw TimeoutException(); - } - std::string answer = buffer.substr(0, substring_len); - buffer.erase(0, substring_len); - - return answer; + return readPort->read(size); } -std::string SerialConnector::generatePackage(const std::string& command) +uint64_t SerialConnector::streamAvailable() { - std::string package = static_cast(command.length()) + command; - uint16_t crc = crc_modbus(reinterpret_cast(package.c_str()), package.length()); - for (size_t i = 0; i < crc_length; ++i) - { - package.push_back((reinterpret_cast(&crc))[i]); - } - return package; + return readPort->available(); } bool SerialConnector::isConnected() diff --git a/code/c++/cxx-api/SerialConnector.h b/code/c++/cxx-api/SerialConnector.h index 396b6fb..bc0b914 100644 --- a/code/c++/cxx-api/SerialConnector.h +++ b/code/c++/cxx-api/SerialConnector.h @@ -1,10 +1,10 @@ #ifndef _BLUETOOTH_CONNECTOR_H_ #define _BLUETOOTH_CONNECTOR_H_ -#include "TrackPlatform_BasicConnector.h" #include "serial/serial.h" +#include "StreamConnector.h" -class SerialConnector : public TrackPlatform_BasicConnector +class SerialConnector : public StreamConnector { static const size_t messageMaxSize = 65535; static const size_t timeoutInMs = 1500; @@ -16,12 +16,11 @@ class SerialConnector : public TrackPlatform_BasicConnector serial::Serial* readPort; serial::Serial* writePort; - std::string buffer; - protected: void write(const std::string& s) override; - std::string read() override; - std::string generatePackage(const std::string& command) override; + + std::string streamRead(uint64_t size) override; + uint64_t streamAvailable() override; public: SerialConnector(const std::string& rx, const std::string& tx, uint32_t baudRate); diff --git a/code/c++/cxx-api/StreamConnector.cpp b/code/c++/cxx-api/StreamConnector.cpp new file mode 100644 index 0000000..eec5202 --- /dev/null +++ b/code/c++/cxx-api/StreamConnector.cpp @@ -0,0 +1,32 @@ +#include +#include "trackPlatformAllExceptions.h" + +#include "StreamConnector.h" + +std::string StreamConnector::read() +{ + if (buffer.empty()) + { + buffer += streamRead(sizeof(uint8_t)); + } + if (buffer.empty()) + { + throw TimeoutException(); + } + const uint8_t len = buffer[0]; + const uint16_t substring_len = sizeof(len) + len + crc_length; + if ((substring_len) > buffer.length()) + { + buffer += streamRead(std::max(substring_len - sizeof(len), streamAvailable())); + } + + if ((substring_len) > buffer.length()) + { + throw TimeoutException(); + } + + std::string answer = buffer.substr(0, substring_len); + buffer.erase(0, substring_len); + + return answer; +} diff --git a/code/c++/cxx-api/StreamConnector.h b/code/c++/cxx-api/StreamConnector.h new file mode 100644 index 0000000..111902f --- /dev/null +++ b/code/c++/cxx-api/StreamConnector.h @@ -0,0 +1,12 @@ +#pragma once +#include "TrackPlatform_BasicConnector.h" + +class StreamConnector : public TrackPlatform_BasicConnector +{ + std::string buffer; + +protected: + virtual std::string streamRead(uint64_t size = 1) = 0; + virtual uint64_t streamAvailable() = 0; + std::string read() override; +}; diff --git a/code/c++/cxx-api/TCPIP_Connector.cpp b/code/c++/cxx-api/TCPIP_Connector.cpp index 29cb50c..d864e57 100644 --- a/code/c++/cxx-api/TCPIP_Connector.cpp +++ b/code/c++/cxx-api/TCPIP_Connector.cpp @@ -41,13 +41,14 @@ void TCPIP_Connector::write(const std::string& s) } } -std::string TCPIP_Connector::read() +std::string TCPIP_Connector::streamRead(uint64_t size) { char recvbuf[onePacketMaxSize]; - int iResult; + int iResult = 1; - do { + while (iResult > 0 && receivedBuffer.length() < size) + { // Check if something is already in buffer (and wait `microsecondsToWaitAnswer` if required) timeval tval = { 0, microsecondsToWaitAnswer }; @@ -77,27 +78,24 @@ std::string TCPIP_Connector::read() } receivedBuffer += std::string(recvbuf, iResult); - } while (iResult > 0); + } - uint8_t len = receivedBuffer[0]; - if ((len + sizeof(receivedBuffer[0])) > receivedBuffer.length()) + if (receivedBuffer.length() < size) { throw TimeoutException(); } - const uint16_t substring_len = sizeof(len) + len; - std::string answer = receivedBuffer.substr(0, substring_len); - receivedBuffer.erase(0, substring_len); + std::string answer = receivedBuffer.substr(0, size); + receivedBuffer = receivedBuffer.substr(size); - //emulating receiving crc16 - uint16_t crc = crc_modbus(reinterpret_cast(answer.c_str()), answer.length()); - for (size_t i = 0; i < crc_length; ++i) - { - answer.push_back((reinterpret_cast(&crc))[i]); - } return answer; } +uint64_t TCPIP_Connector::streamAvailable() +{ + return receivedBuffer.length(); +} + bool TCPIP_Connector::connectSocket() { if (isSocketConnected) { @@ -175,11 +173,6 @@ void TCPIP_Connector::closeSocket() } } -std::string TCPIP_Connector::generatePackage(const std::string& command) -{ - return (static_cast(command.length()) + command); -} - bool TCPIP_Connector::isConnected() { return (TrackPlatform_BasicConnector::isConnected() && isSocketConnected); diff --git a/code/c++/cxx-api/TCPIP_Connector.h b/code/c++/cxx-api/TCPIP_Connector.h index 55a2162..06b94e8 100644 --- a/code/c++/cxx-api/TCPIP_Connector.h +++ b/code/c++/cxx-api/TCPIP_Connector.h @@ -24,9 +24,9 @@ #endif /* (defined(__linux__) || defined(__unix__)) */ -#include "TrackPlatform_BasicConnector.h" +#include "StreamConnector.h" -class TCPIP_Connector : public TrackPlatform_BasicConnector +class TCPIP_Connector : public StreamConnector { std::string ip; uint16_t port; @@ -48,9 +48,9 @@ class TCPIP_Connector : public TrackPlatform_BasicConnector void closeSocket(); protected: - std::string generatePackage(const std::string& command) override; void write(const std::string& s) override; - std::string read() override; + std::string streamRead(uint64_t size) override; + uint64_t streamAvailable() override; bool connectSocket(); bool disconnectSocket(); diff --git a/code/c++/cxx-api/TimeoutException.h b/code/c++/cxx-api/TimeoutException.h index 07a5a4a..a8e1f58 100644 --- a/code/c++/cxx-api/TimeoutException.h +++ b/code/c++/cxx-api/TimeoutException.h @@ -1,5 +1,7 @@ #pragma once +#include "TrackPlatformException.h" + class TimeoutException : public TrackPlatformException { public: diff --git a/code/c++/cxx-api/TrackPlatform_BasicConnector.cpp b/code/c++/cxx-api/TrackPlatform_BasicConnector.cpp index 42f74c9..b13f58d 100644 --- a/code/c++/cxx-api/TrackPlatform_BasicConnector.cpp +++ b/code/c++/cxx-api/TrackPlatform_BasicConnector.cpp @@ -16,7 +16,13 @@ const std::string TrackPlatform_BasicConnector::errorAnswer = "ERROR"; std::string TrackPlatform_BasicConnector::generatePackage(const std::string& command) { - return command; + std::string package = static_cast(command.length()) + command; + uint16_t crc = crc_modbus(reinterpret_cast(package.c_str()), package.length()); + for (size_t i = 0; i < crc_length; ++i) + { + package.push_back((reinterpret_cast(&crc))[i]); + } + return package; } void TrackPlatform_BasicConnector::sendStartCommand() diff --git a/code/c++/cxx-api/cxx-api.vcxproj b/code/c++/cxx-api/cxx-api.vcxproj index 6178632..042a88a 100644 --- a/code/c++/cxx-api/cxx-api.vcxproj +++ b/code/c++/cxx-api/cxx-api.vcxproj @@ -164,6 +164,7 @@ + @@ -188,6 +189,7 @@ + diff --git a/code/c++/cxx-api/cxx-api.vcxproj.filters b/code/c++/cxx-api/cxx-api.vcxproj.filters index f99e54d..9bc1cd0 100644 --- a/code/c++/cxx-api/cxx-api.vcxproj.filters +++ b/code/c++/cxx-api/cxx-api.vcxproj.filters @@ -129,6 +129,9 @@ exceptions\header + + Communication\header + @@ -188,5 +191,8 @@ libcrc\source + + Communication\source + \ No newline at end of file diff --git a/code/c++/cxx-api/serial_support b/code/c++/cxx-api/serial_support index 827c4a7..5a354ea 160000 --- a/code/c++/cxx-api/serial_support +++ b/code/c++/cxx-api/serial_support @@ -1 +1 @@ -Subproject commit 827c4a784dd4fdd35dc391f37ef152eab7c9c9b2 +Subproject commit 5a354eaab7c064a155857d377a2fa3f0f8390c34 diff --git a/code/esp/README.md b/code/esp/README.md new file mode 100644 index 0000000..6606c69 --- /dev/null +++ b/code/esp/README.md @@ -0,0 +1,48 @@ +# ESP 8266 + +В данном разделе расположены прошивки для ESP8266 модуля (проверялось на ESP8266-07). + +## Прошивка модуля + +Прошивки скомпилированы из библиотеки [nodemcu](https://github.com/nodemcu/nodemcu-firmware) с помощью [специального сайта](https://nodemcu-build.com/). + +В прошивке присутствуют следующие модули (их 7): + +* file +* gpio +* net +* node +* tmr (timer) +* uart +* wifi + +Для залития прошивки на модуль использовалась утилита `ESP8266Flasher`, которую можно найти [тут](https://github.com/nodemcu/nodemcu-flasher). + +Документацию для перевода esp в режим прошивки или выхода из него можно найти [тут](https://github.com/esp8266/esp8266-wiki/wiki/Boot-Process#esp-boot-modes). + +## Скрипты для автоматической настройки модуля + +В папке `lua-source` расположены файлы, предназначенные для загрузки на esp модуль после его прошивки для его автоматической настройки. Требуется загружать все файлы из папки. + +Загрузка производилась через утилиту `ESPlorel`. + +В скриптах автоматической настройки стоит защита, которая позволяет залить скрипты в течении 5 секунд перед выполением остальных скриптов. Эта особенность может помочь, если выполнение какого-либо из остальных (кроме `init.lua`) скриптов приводит к перезагрузке модуля. + +## Протокол общения по UART + +В качестве конца передачи пакета данных используется символ с кодом 13: `"\n"`. + +Если в посылке встречается символ с кодом 13, он заменяется набором символов со следующими кодами: 10 и 11. + +Если в посылке встречается символ с кодом 10: `"\r"`, он экранируется дополнительным символом с кодом 10. + +### Установка соединения с модулем + +Установка соединения основана на трехэтапном рукопожатии (3-way handshake). + +По завершению запуска модуля по UART отправляется `I'm ready, Milord!` с периодичностью 10 секунд. + +Модуль ждет ответа `Sir`, отвечает `Yes, Sir` и переходит в режим "Соедиение установлено". + +**Внимание!** Всё общение с модулем должно работать по протоколу, в том числе и установление соединения. + diff --git a/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-float.bin b/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-float.bin new file mode 100644 index 0000000..f34b2c6 Binary files /dev/null and b/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-float.bin differ diff --git a/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-integer.bin b/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-integer.bin new file mode 100644 index 0000000..cee792d Binary files /dev/null and b/code/esp/firmwares/nodemcu-master-7-modules-2018-02-02-20-20-04-integer.bin differ diff --git a/code/esp/lua-source/gpio_config.lua b/code/esp/lua-source/gpio_config.lua new file mode 100644 index 0000000..c1a6e59 --- /dev/null +++ b/code/esp/lua-source/gpio_config.lua @@ -0,0 +1,20 @@ +print("Configuring GPIO") + +DEFAULT_GPIO_SEQ = {1000000, 5000} +gpio_seq_cfg_us = DEFAULT_GPIO_SEQ + +-- use GPIO2 pin (with pin num = 4) +local diode_pin = 4 +gpio.mode(diode_pin, gpio.OUTPUT) + +-- asynchronous diode flashes +local function start_gpio() + gpio.serout(diode_pin, gpio.HIGH, gpio_seq_cfg_us, 1, start_gpio) +end + +-- start flashes +start_gpio() + +print("GPIO was configured") + +collectgarbage() diff --git a/code/esp/lua-source/init.lua b/code/esp/lua-source/init.lua new file mode 100644 index 0000000..35bcb81 --- /dev/null +++ b/code/esp/lua-source/init.lua @@ -0,0 +1,12 @@ +local time_to_wait = 5000 +local timer_num = 0 +print ( "Waiting to rewrite scripts in " .. time_to_wait .. " ms ...") +tmr.register (timer_num, time_to_wait, tmr.ALARM_SINGLE, + function (t) + print ( "Starting esp8266...") + dofile ("main.lua") + end +) +tmr.start (timer_num) + +collectgarbage() diff --git a/code/esp/lua-source/main.lua b/code/esp/lua-source/main.lua new file mode 100644 index 0000000..975953b --- /dev/null +++ b/code/esp/lua-source/main.lua @@ -0,0 +1,10 @@ +-- configure modules +dofile("gpio_config.lua") +dofile("uart_config.lua") +dofile("wifi_config.lua") + +print("ESP8266 was started") + +uart_decive_ready_callback() + +collectgarbage() diff --git a/code/esp/lua-source/uart_config.lua b/code/esp/lua-source/uart_config.lua new file mode 100644 index 0000000..9889db5 --- /dev/null +++ b/code/esp/lua-source/uart_config.lua @@ -0,0 +1,125 @@ +print("Configuring UART") + +uart_id = 0 +local uart_callback_name = "data" -- do not change text, otherwise app will crash +local uart_delim_num = 13 +local uart_escape_num = 10 + +local cfg = {} +cfg.id = uart_id +cfg.speed = 115200 +cfg.databits = 8 +cfg.parity = uart.PARITY_NONE +cfg.stopbits = uart.STOPBITS_1 +cfg.echo = 0 -- disable uart echo + +local handshake = {} +handshake.first = "I'm ready, Milord!" +handshake.second = "Sir" +handshake.third = "Yes, Sir" + +local is_handshake_made = false +local handshake_timer_num = 2 +local handshake_timer_period_ms = 10000 + +local escape = {} +-- 13 -> 10 11 +escape[string.char(uart_delim_num)] = string.char(uart_escape_num, 11) +-- 10 -> 10 10 +escape[string.char(uart_escape_num)] = string.char(uart_escape_num, uart_escape_num) + +function table_invert(t) + local s={} + for k,v in pairs(t) do + s[v]=k + end + return s +end +local invert_escape = table_invert(escape) + +uart.setup(cfg.id, + cfg.speed, + cfg.databits, + cfg.parity, + cfg.stopbits, + cfg.echo +) + +function uart_write(data) + -- escaping string + data = string.gsub(data, ".", + function(pattern) + local res = escape[pattern] + if not res then + res = pattern + end + + return res + end + ) + + -- write to serial port + uart.write(uart_id, data .. string.char(uart_delim_num)) + + collectgarbage() +end + +local function handshake_manager() + if not is_handshake_made then + uart_write(handshake.first) + tmr.register(handshake_timer_num, handshake_timer_period_ms, tmr.ALARM_SINGLE, + handshake_manager) + tmr.start(handshake_timer_num) + end +end + +function uart_decive_ready_callback() + handshake_manager() +end + +-- protocol parsing callback +function uart_protocol_parser(data) + local delim_string = string.char(uart_delim_num) + if string.sub(data, -1) ~= delim_string then + print("Protocol error") + else + data = string.gsub(data, delim_string, "") + data = string.gsub(data, string.char(uart_delim_num) .. ".", + function(pattern) + return invert_escape[pattern] + end + ) + end + + delim_string = nil + return data +end + +-- protocol callback +function uart_connected_callback(data) + data = uart_protocol_parser(data) + + wifi_write(data) +end + +-- only handshake callback +function uart_callback(data) + data = uart_protocol_parser(data) + if data==(handshake.second) then + is_handshake_made = true + uart_write(handshake.third) + + -- unregister callback function + uart.on(uart_callback_name) + + -- register new callback + uart.on(uart_callback_name, string.char(uart_delim_num), uart_connected_callback, 0) + end +end + +uart.on(uart_callback_name, string.char(uart_delim_num), uart_callback, 0) + +print("UART was configured") + +cfg = nil +collectgarbage() diff --git a/code/esp/lua-source/wifi_config.lua b/code/esp/lua-source/wifi_config.lua new file mode 100644 index 0000000..18fbf83 --- /dev/null +++ b/code/esp/lua-source/wifi_config.lua @@ -0,0 +1,65 @@ +print("Configuring Wi-Fi") + +local cfg={} +cfg.ssid="TrackPlatformWiFi" +cfg.pwd="1234567890" +cfg_tcp_port = 333 + +global_socket = nil + +-- configure access point +wifi.setmode(wifi.STATIONAP) +wifi.ap.config(cfg) + +local ip = wifi.ap.getip() +print("AP IP: " .. ip) +print("AP port: " .. cfg_tcp_port) + +-- create TCP server +server = net.createServer(net.TCP) + +function receiver(socket, data) + -- received data UART sending + uart_write(data) +end + +function wifi_write(data) + if not global_socket then + print("ERROR: wi-fi socket is null") + else + global_socket:send(data) + end +end + +function connected_callback(socket) + global_socket = socket + + -- set diode flashing sequence + gpio_seq_cfg_us = {600000, 100000, 200000, 100000} + +-- print("Connected") +end + +function disconnected_callback(socket) + -- set diode flashing sequence + gpio_seq_cfg_us = DEFAULT_GPIO_SEQ + +-- print("Disonnected") +end + +if server then + server:listen(cfg_tcp_port, + function(socket) + socket:on("receive", receiver) + socket:on("connection", connected_callback) + socket:on("disconnection", disconnected_callback) + end + ) +else + print("ERROR: Cannot create TCP server") +end + +print("Wi-Fi was configured") + +cfg=nil +collectgarbage()