lost update from Jun 2020

1 parent 8cda0041
...@@ -111,9 +111,10 @@ Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT) ...@@ -111,9 +111,10 @@ Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT)
INT_NO = MHZ_INT; INT_NO = MHZ_INT;
RECEIVER_PIN = MHZ; RECEIVER_PIN = MHZ;
pinMode(MHZ, INPUT); // Вывод, на который подключён приёмник pinMode(MHZ, INPUT); // Вывод, на который подключён приёмник
//digitalWrite(MHZ, HIGH); // ДОБАВЛЕННО mr.Tech ВРЕМЕННО ТОЛЬКО ДЛЯ ОТЛАДКИ. нЕОБХОДИМО УДАЛИТЬ! //digitalWrite(MHZ, LOW); // ДОБАВЛЕННО mr.Tech ВРЕМЕННО ТОЛЬКО ДЛЯ ОТЛАДКИ. нЕОБХОДИМО УДАЛИТЬ!
} }
Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT, byte led, bool pull_up) Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT, byte led, bool pull_up)
{ {
INT_NO = MHZ_INT; INT_NO = MHZ_INT;
...@@ -122,7 +123,7 @@ Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT, byte led, bool pull_up) ...@@ -122,7 +123,7 @@ Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT, byte led, bool pull_up)
RECEIVER_PIN = MHZ; RECEIVER_PIN = MHZ;
pinMode(MHZ, INPUT); // Вывод, на который подключён приёмник pinMode(MHZ, INPUT); // Вывод, на который подключён приёмник
pinMode(LED, OUTPUT); // Вывод светодиода pinMode(LED, OUTPUT); // Вывод светодиода
//digitalWrite(MHZ, HIGH); // ДОБАВЛЕННО mr.Tech ВРЕМЕННО ТОЛЬКО ДЛЯ ОТЛАДКИ. нЕОБХОДИМО УДАЛИТЬ! //digitalWrite(MHZ, LOW); // ДОБАВЛЕННО mr.Tech ВРЕМЕННО ТОЛЬКО ДЛЯ ОТЛАДКИ. нЕОБХОДИМО УДАЛИТЬ!
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
......
#include <Arduino.h> #include <Arduino.h>
#ifndef Oregon_NR_h_AIR #ifndef Oregon_NR_h
#define Oregon_NR_h_AIR #define Oregon_NR_h
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This Arduino code is for receive and transmit data using Oregon Scientific RF protocol version 2.1 and 3.0. // This Arduino code is for receive and transmit data using Oregon Scientific RF protocol version 2.1 and 3.0.
......
...@@ -635,11 +635,11 @@ bool Oregon_TM::transmit() ...@@ -635,11 +635,11 @@ bool Oregon_TM::transmit()
if (millis() >= time_marker_send && send_time) if (millis() >= time_marker_send && send_time)
{ {
digitalWrite(7, LOW);// Включение режима TX на 7-й ноге. Добавлено mr.Tech 09.03.2020 digitalWrite(7, LOW);// Включение режима TX на 7-й ноге - начало TX. Добавлено mr.Tech 09.03.2020
delay(500); delay(500); // задержка перед началом преамбулы. mr.Tech
SendPacket(); SendPacket();
time_marker_send = millis() + send_time; time_marker_send = millis() + send_time;
digitalWrite(7, HIGH);// Отключение режима TX на 7-й ноге. Добавлено mr.Tech 09.03.2020 digitalWrite(7, HIGH);// Отключение режима TX на 7-й ноге - конец TX. Добавлено mr.Tech 09.03.2020
return true; return true;
} }
......
...@@ -13,79 +13,83 @@ ...@@ -13,79 +13,83 @@
#include <Oregon_NR_MY.h> #include <Oregon_NR_MY.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <ESP8266WebServer.h> //#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h> //#include <ESP8266mDNS.h>
//#include <Wire.h> // Подключаем библиотеку Wire
//#include <Adafruit_BME280.h> // Подключаем библиотеку Adafruit_BME280
//#include <Adafruit_Sensor.h> // Подключаем библиотеку Adafruit_Sensor
/*#include <SPI.h>
#define BME_SCK 14
#define BME_MISO 12
#define BME_MOSI 13
#define BME_CS 15*/
//Режимы работы //Режимы работы
#define TEST_MODE false //Режим отладки (данные на narodmon.ru не отсылаются) #define TEST_MODE false //Режим отладки (данные на narodmon.ru не отсылаются)
//#undef TEST_MODE //#undef TEST_MODE
#define SEND_INTERVAL 120000 //350000 - 5 min //Как часто отсылать данные на сервер #define SEND_INTERVAL 120000 //350000 - 5 min //Как часто отсылать данные на сервер
#define CONNECT_TIMEOUT 10000 //Время ожидания соединения //#define SEND_INTERVAL 12000
#define DISCONNECT_TIMEOUT 10000 //Время ожидания отсоединения #define CONNECT_TIMEOUT 10000 //Время ожидания соединения
#define DISCONNECT_TIMEOUT 10000 //Время ожидания отсоединения
//#define mac "#FF:FF:FF:FF:FF:FF" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b //#define mac "#FF:FF:FF:FF:FF:FF" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b
//#define mac "#D8:F1:5B:07:1C:0B" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b //#define mac "#D8:F1:5B:07:1C:0B" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b
#define mac "#ESP826677671C0B" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b #define mac "#ESP826677671C0B" //МАС-адрес на narodmon.ru d8-f1-5b-07-1c-0b
//#define mac "#ESP8266FFFFFFFF" //ID или MAC на narodmon.ru //#define mac "#ESP8266FFFFFFFF" //ID или MAC на narodmon.ru
const char* ssid = "ASUS"; //Параметры входа в WiFi
const char* ssid = "ASUS"; //Параметры входа в WiFi
const char* password = "123456789"; const char* password = "123456789";
//настройки сети для хитрого маршрута //настройки сети для хитрого маршрута
//IPAddress ip(192,168,137,17); //статический IP //IPAddress ip(192,168,137,17); //статический IP
//IPAddress gateway(192,168,137,1); //IPAddress gateway(192,168,137,1);
//IPAddress subnet(255,255,255,0); //IPAddress subnet(255,255,255,0);
//IPAddress dns1(8,8,8,8); //IPAddress dns1(8,8,8,8);
//ESP8266WebServer server(80); //ESP8266WebServer server(80);
//**************************************************************************************** //****************************************************************************************
Oregon_NR oregon(13, 13, 2, true); // Приёмник 433Мгц подключён к D7 (GPIO13), Светодиод на D2 подтянут к +пит. //Oregon_NR oregon(13, 13, 2, true);// Приёмник 433Мгц подключён к D7 (GPIO13), Светодиод на D2 подтянут к +пит.
Oregon_NR oregon(15, 15, 3, true); // Приёмник 433Мгц подключён к D7 (GPIO13), Светодиод на D2 подтянут к +пит.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Массивы для хранения полученных данных для датчиков Oregon: //Массивы для хранения полученных данных для датчиков Oregon:
float r_tmp[3]; //Температура float r_tmp[3]; //Температура
float r_hmdty[3]; //Влажность. Если = 101 - значит нет данных float r_hmdty[3]; //Влажность. Если = 101 - значит нет данных
bool r_bat[3], bat_pcr, bat_wrt; //Флаг батареи bool r_bat[3], bat_pcr, bat_wrt; //Флаг батареи
bool r_isreceived[3]; //Флаг о том, что по данному каналу приходил хоть один правильный пакет и данные актуальны bool r_isreceived[3]; //Флаг о том, что по данному каналу приходил хоть один правильный пакет и данные актуальны
word r_type[3]; //Тип датчика
word r_type[3]; //Тип датчика unsigned long rcv_time[3]; // времена прихода последних пакетов
unsigned long rcv_time[3]; // времена прихода последних пакетов float number_of_receiving[3]; //сколько пакетов получено в процессе сбора данных
float number_of_receiving[3]; //сколько пакетов получено в процессе сбора данных float wa_speed; // Скорость ветра
float wa_speed; // Скорость ветра float mw_speed; // Макс скорость ветра
float mw_speed; // Макс скорость ветра float w_d; // Направление ветра
// bool w_direction; // Направление ветра float r_rate; // Интенсивность осадков - дождя
float w_d; // Направление ветра float r_total; // Колличество осадков - дождя
float r_rate; // Интенсивность осадков - дождя float tempC; // Температура
float r_total; // Колличество осадков - дождя float humidity; // Влажность
float pressureHgmm; // Давление мм Рт.ст
//**************************************************************************************** //****************************************************************************************
//Oregon_NR::Oregon_NR(byte MHZ, byte MHZ_INT)
//{
// //INT_NO = MHZ_INT;
// //RECEIVER_PIN = MHZ;
// //pinMode(MHZ, INPUT); // Вывод, на который подключён приёмник
// digitalWrite(MHZ, HIGH); // ДОБАВЛЕННО mr.Tech ВРЕМЕННО ТОЛЬКО ДЛЯ ОТЛАДКИ. нЕОБХОДИМО УДАЛИТЬ!
//}
#define BLUE_LED 2 //Индикация подключения к WiFi
#define GREEN_LED 14 //Индикатор успешной доставки пакета а народмон
#define RED_LED 255 //Индикатор ошибки доставки пакета на народмон
//Параметоы соединения с narodmon:
//IPAddress nardomon_server(94,19,113,221);
char nardomon_server[] = "narodmon.ru";
int port=8283;
WiFiClient client; //Клиент narodmon
const unsigned long postingInterval = SEND_INTERVAL;
unsigned long lastConnectionTime = 0;
boolean lastConnected = false;
unsigned long cur_mark;
#define BLUE_LED 2 //Индикация подключения к WiFi
#define GREEN_LED 14 //Индикатор успешной доставки пакета а народмон
#define RED_LED 255 //Индикатор ошибки доставки пакета на народмон
// #define BME280_ADDRESS 0x77
// Adafruit_BME280 bme;
//Параметоы соединения с narodmon:
//IPAddress nardomon_server(94,19,113,221);
char narodomon_server[] = "narodmon.ru";
int port=8283;
WiFiClient client; //Клиент narodmon
WiFiServer server(80); // Указываем порт Web-сервера
String header;
const unsigned long postingInterval = SEND_INTERVAL;
unsigned long lastConnectionTime = 0;
boolean lastConnected = false;
unsigned long cur_mark;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SETUP////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SETUP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
...@@ -93,14 +97,19 @@ unsigned long cur_mark; ...@@ -93,14 +97,19 @@ unsigned long cur_mark;
void setup() void setup()
{ {
pinMode(BLUE_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT); pinMode(RED_LED, OUTPUT);
// pinMode(1, INPUT);
// pinMode(2, INPUT);
// pinMode(3, INPUT);
// pinMode(4, INPUT);
// pinMode(5, INPUT);
digitalWrite(2, LOW);
digitalWrite(1, LOW);
digitalWrite(15, LOW);
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
//Инициализация памяти //Инициализация памяти
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
...@@ -109,48 +118,55 @@ void setup() ...@@ -109,48 +118,55 @@ void setup()
r_isreceived[i] = 0; r_isreceived[i] = 0;
number_of_receiving[i] = 0; number_of_receiving[i] = 0;
} }
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
//Запуск Serial-ов //Запуск Serial-ов
Serial.begin(115200); Serial.begin(115200);
Serial.println(""); Serial.println("");
if (TEST_MODE) Serial.println("Test mode"); if (TEST_MODE) Serial.println("Test mode");
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
//Запуск Wifi //Запуск Wifi
wifi_connect(); wifi_connect();
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
digitalWrite(BLUE_LED, HIGH); digitalWrite(BLUE_LED, HIGH);
if (test_narodmon_connection()){ if (test_narodmon_connection()){
digitalWrite(GREEN_LED, HIGH); digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW); digitalWrite(RED_LED, LOW);
} }
else { else {
digitalWrite(GREEN_LED, LOW); digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH); digitalWrite(RED_LED, HIGH);
} }
//вкючение прослушивания радиоканала //вкючение прослушивания радиоканала
oregon.start(); oregon.start();
oregon.receiver_dump = false;
oregon.receiver_dump = true; //Если не распознаются последние байты принятого пакета можно попробовать подстроить частоту захвата данных
//Если не распознаются последние байты принятого пакета можно попробовать подстроить частоту захвата данных
oregon.timing_correction = 0; // коррекция частоты завхвата данных. Обычно достаоточно подобрать значение от -5 до 5 oregon.timing_correction = 0; // коррекция частоты завхвата данных. Обычно достаоточно подобрать значение от -5 до 5
oregon.decode_method = 3; //или использовать метод 3 для декодирования oregon.decode_method = 1; //или использовать метод 3 для декодирования
//подключение датчика давления, температуры и влажности BME280
// Wire.begin(D1, D2);
// Wire.setClock(100000);
// if (!bme.begin(BME280_ADDRESS )) { // Проверка инициализации датчика
// Serial.println("Could not find a valid BME280 sensor, check wiring!"); // Печать, об ошибке инициализации.
// while (1) delay(3000); // Зацикливаем
// }
// Wire.begin();
// Wire.setClock(100000);
// if (!bme.begin(BME280_ADDRESS ))
// {
// Serial.println("Could not find a valid BME280 sensor, check wiring!");
// while (1)
// {
// yield();
// delay(3000);
// }
// }
//
server.begin();
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
//LOOP////////////////////////////////////////////////////////////////////// //LOOP//////////////////////////////////////////////////////////////////////
...@@ -158,13 +174,23 @@ void setup() ...@@ -158,13 +174,23 @@ void setup()
void loop() void loop()
{ {
// if (!bme.begin(BME280_ADDRESS ))
// {
// Serial.println("Could not find a valid BME280 sensor, check wiring!");
//// while (1)
// {
// yield();
// // delay(3000);
// }
// }
WiFiClient client = server.available(); // Получаем данные, посылаемые клиентом
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
//Защита от подвисаний///////////////////////////////////////// //Защита от подвисаний/////////////////////////////////////////
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
if (micros() > 0xFFF00000) while ( micros() < 0xFFF00000); //Висим секунду до переполнения if (micros() > 0xFFF00000) while ( micros() < 0xFFF00000); //Висим секунду до переполнения
if (millis() > 0xFFFFFC0F) while ( millis() < 0xFFFFFC0F); //Висим секунду до переполнения if (millis() > 0xFFFFFC0F) while ( millis() < 0xFFFFFC0F); //Висим секунду до переполнения
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
//Проверка полученных данных,///////////////////////////////////////// //Проверка полученных данных,/////////////////////////////////////////
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
...@@ -182,29 +208,22 @@ void loop() ...@@ -182,29 +208,22 @@ void loop()
if (millis() - lastConnectionTime > postingInterval && is_a_data_to_send) { if (millis() - lastConnectionTime > postingInterval && is_a_data_to_send) {
//Обязательно отключить прослушивание канала //Обязательно отключить прослушивание канала
oregon.stop(); oregon.stop();
digitalWrite(BLUE_LED, HIGH); digitalWrite(BLUE_LED, HIGH);
if (send_data()){ if (send_data()){
digitalWrite(GREEN_LED, HIGH); digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW); digitalWrite(RED_LED, LOW);
} }
else { else {
digitalWrite(GREEN_LED, LOW); digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH); digitalWrite(RED_LED, HIGH);
} }
oregon.start(); oregon.start();
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
//Захват пакета,////////////////////////////////////////////// //Захват пакета,//////////////////////////////////////////////
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
oregon.capture(0); oregon.capture(0); // (1) - отладка отображается в консоль
// //
//Захваченные данные годны до следующего вызова capture //Захваченные данные годны до следующего вызова capture
...@@ -332,7 +351,7 @@ if (oregon.sens_type == WGR800 && oregon.crc_c){ ...@@ -332,7 +351,7 @@ if (oregon.sens_type == WGR800 && oregon.crc_c){
Serial.print("PCR800,"); Serial.print("PCR800,");
Serial.print(" RAIN RATE: "); Serial.print(" RAIN RATE: ");
Serial.print(oregon.rain_rate, 4); Serial.print(oregon.rain_rate, 4);
// Serial.print(oregon.rain_rate, 3); //Serial.print(oregon.rain_rate, 3);
//Serial.print(" | "); //Serial.print(" | ");
//Serial.print(oregon.rain_rate, 1); //Serial.print(oregon.rain_rate, 1);
Serial.print(" mm/h, "); Serial.print(" mm/h, ");
...@@ -354,6 +373,53 @@ if (oregon.sens_type == WGR800 && oregon.crc_c){ ...@@ -354,6 +373,53 @@ if (oregon.sens_type == WGR800 && oregon.crc_c){
r_rate = oregon.rain_rate; r_rate = oregon.rain_rate;
r_total = oregon.total_rain; r_total = oregon.total_rain;
} }
// tempC = bme.readTemperature();
// humidity = bme.readHumidity();
// pressureHgmm = bme.readPressure() / 133.322;
// Print to serial monitor
// printToSerial(tempC, humidity, pressureHgmm);
////////////////////////////////////////////
/// JSON client ////////////////////////////
if (client) {
Serial.println("New Client."); // Отправка "Новый клиент"
String currentLine = ""; // Создаем строку для хранения входящих данных от клиента
while (client.connected()) { // Пока есть соединение с клиентом
if (client.available()) { // Если клиент активен
char c = client.read(); // Считываем посылаемую информацию в переменную "с"
Serial.write(c); // Отправка в Serial port
header += c;
if (c == '\n') { // Вывод HTML страницы
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK"); // Стандартный заголовок HTTP
client.println("Access-Control-Allow-Origin: *"); // разрешаю cross-origin запросы
client.println("Content-type:text/html ");
client.println("Connection: close"); // Соединение будет закрыто после завершения ответа
client.println("Refresh: 13"); // Автоматическое обновление каждые 13 сек
client.println();
// Формирую данные в формате JSON
client.print("{\"w_d\" :\"");
client.print(w_d);
client.print("\",\"wa_speed\" :\"");
client.print(wa_speed);
client.print("\",\"mw_speed\" :\"");
client.print(mw_speed);
client.println("\"}");
client.println();
break;
} else {
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
header = "";
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
} }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************************************************** //***************************************************************************************************************************************
...@@ -400,7 +466,7 @@ void wifi_connect() { ...@@ -400,7 +466,7 @@ void wifi_connect() {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool test_narodmon_connection() { bool test_narodmon_connection() {
if (client.connect(nardomon_server, port)) { if (client.connect(narodomon_server, port)) {
client.println("##"); client.println("##");
cur_mark = millis(); cur_mark = millis();
do { do {
...@@ -429,7 +495,7 @@ bool send_data() { ...@@ -429,7 +495,7 @@ bool send_data() {
if (WiFi.status() != WL_CONNECTED) wifi_connect(); if (WiFi.status() != WL_CONNECTED) wifi_connect();
bool what_return = false; bool what_return = false;
if (client.connect(nardomon_server, port)) { if (client.connect(narodomon_server, port)) {
//Отправляем MAC-адрес //Отправляем MAC-адрес
Serial.println(' '); Serial.println(' ');
String s = mac; String s = mac;
...@@ -537,7 +603,25 @@ void sendOregonData() { ...@@ -537,7 +603,25 @@ void sendOregonData() {
default: s += " 50"; default: s += " 50";
} }
Serial.println(s); Serial.println(s);
if (!TEST_MODE) client.print(s); if (!TEST_MODE) client.println(s);
// // TEMPERATURE ##
// s = "\n#T1#";
// s += tempC;
// Serial.println(s);
// if (!TEST_MODE) client.print(s);
//
// // HUMIDITY ##
// s = "\n#H1#";
// s += humidity;
// Serial.println(s);
// if (!TEST_MODE) client.print(s);
//
// // PRESURE ##
// s = "\n#P1#";
// s += pressureHgmm;
// Serial.println(s);
// if (!TEST_MODE) client.print(s);
// ######################################################################################## // ########################################################################################
...@@ -577,6 +661,27 @@ void sendOregonData() { ...@@ -577,6 +661,27 @@ void sendOregonData() {
// if (!TEST_MODE) client.println(s); // if (!TEST_MODE) client.println(s);
// } // }
} }
/////////////////////////////////////////////////////////////////////////////
void printToSerial(float tempC, float humidity, float pressurePascals)
{
//// Temperature
Serial.print("Temperature: ");
Serial.print(tempC);
Serial.println("C");
//// Barometric pressure
Serial.print("Pressure: ");
Serial.print(pressureHgmm);
Serial.println("Hgmm");
//// Humidity
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println("%");
delay(3000);
}
//////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// ЗАМЕНА DELAY, которая работает и не приводит к вылету... // ЗАМЕНА DELAY, которая работает и не приводит к вылету...
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!