Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //////////////////////////////////////////////////////////////////
- //Это cExtensionMaster.cpp
- // Протокол обмена данными между периферийными устройствами
- // описание устройства типа 10
- //Взаимодействие классов:
- //Класс cExtensionMaster предназначен для взаимодействия с периферией,
- //он нумерует устройства и реализует функции отправки пакетов.
- //На каждое обнаруженное устройство создается элемент в массиве устройств типа cExtensionDevice10
- //В свою очередь каждое устройство этого типа имеет массив указателей на cExtensionPort
- //Передача данных происходит из класса cExtensionMaster, он формирует заголовок для пакета данных
- //В него другие классы передают адрес передачи, коды функций и сериализованные данные
- //Данные присоединяются к заголовку, снова сериализуются и отправляются в порт
- //Прием данных осуществляется в обратном порядке: декодируется стандартный заголовок, определяется
- //размер блока даныных и он передается в класс устройства, который будет его обрабатывать
- //Функция назначения определяется уже там, там же декодируется пакет данных и обрабатывается.
- //
- //про адресацию: проще сделать для каждого типа устройства свой массив
- //при этом получается что удобнее сделать для каждого типа устойств свою сквозную нумерацию, соответствующую индексам массива
- //нумерация адресов устройств начинается с нуля
- #include <Arduino.h>
- //https://github.com/FrankBoesing/FastCRC
- #include <FastCRC.h>
- #define EXTDEV_TYPE_10_MAXCOUNT 8 //максимальное количество устройств типа 0х10
- struct sHeader
- {
- uint16_t Start = 0x0000;// Стартовая последовательность
- byte Src = 0xFF;// Адрес Мастер-девайса
- byte Dst = 0x00;// Адрес устройства куда направить пакет
- byte Type = 0x00; // тип устройства
- byte Func = 0x00; // функция
- byte Size = 0x00; // Длинна блока данных, максимум 256 байт, должно хватить
- unsigned long Trans = 0x00000000; // номер транзцакции
- uint16_t CRC = 0x0000; // контрольная сумма
- unsigned long Value; //Данные для простого обмена, например, для обслуживания протокола
- };
- //тип указатель на функцию c аргументом в виде пакета
- typedef void (*PHandlerPacket)(sHeader param);
- //тип указатель на функцию c аргументом в виде байта
- typedef void (*PHandlerByte)(byte param);
- //#include "cExtensionMaster.h"
- #define EXTDEV_TYPE_10 0x10 //код типа устройства 10
- #define EXTDEV_FUNC_SET 0x10 //установить значение порта
- #define EXTDEV_FUNC_GET 0x10 //событие получения состояния порта
- #define EXTDEV_FUNC_GETALL 0x29 //получить значение всех портов
- #define EXTDEV_FUNC_KEYREAD 0x50 //считан ключ iButton
- //типы портов
- #define EXTDEV_INPUT 0 //Цифровой вход
- #define EXTDEV_OUTPUT 1 //Цифровой выход
- #define EXTDEV_COUNTER 2 //Счетчик импульсов
- #define EXTDEV_FREQ 3 //Генератор последовательности импульсов
- #define EXTDEV_PWM 4 //ШИМ выход
- #define EXTDEV_ANALOG 5 //Аналоговый вход
- //типы триггеров
- #define EXTDEV_TRIGOFF 0 //Триггер не задан или нет возможности
- #define EXTDEV_TRIGNORM 1 //Значение вошло в норму
- #define EXTDEV_TRIGUP 2 //Значение превысило порог
- #define EXTDEV_TRIGDOWN 3 //Значение ниже заданного
- //Состояние портов периферийного устройства, используется при получении пакетов
- //Эта структура используется для обмена данными по одному порту, в т.ч по событию
- struct PortState {
- byte Num = 0; // Номер порта в устройстве
- uint16_t Value = 0; // Значение в порту
- byte TrigType = 0; // какой триггер сработал
- };
- //значения портов периферийного устройства, используется при получении состояния всех портов
- //получить можно только состояние портов которые можно прочитать
- struct sPortsStateAll{
- uint16_t Value4=0x0000;
- uint16_t Value5=0x0000;
- uint16_t Value6=0x0000;
- uint16_t Value7=0x0000;
- uint16_t Value8=0x0000;
- uint16_t Value9=0x0000;
- uint16_t Value10=0x0000;
- uint16_t Value11=0x0000;
- uint16_t Value12=0x0000;
- uint16_t Value13=0x0000;
- uint16_t Value14=0x0000;
- uint16_t Value15=0x0000;
- uint16_t Value16=0x0000;
- uint16_t Value17=0x0000;
- uint16_t Value18=0x0000;
- uint16_t Value19=0x0000;
- uint16_t Value20=0x0000;
- };
- //другой вариант - с массивом, чтоб можнобыло перебором определить что изменилось и вызвать обработчик
- //uint16_t PortsStateAll[17];
- //тип указатель на функцию c аргументами номер порта, значение, тип триггера который сработал
- typedef void (*PHandlerPort)(byte port, long value, byte trigType);
- //тип указатель на функцию без аргументов
- typedef void (*PHandler)();
- //тип указатель на функцию аргументом-массивом для считывателя ключа
- typedef void (*PHandlerByteArr8)(char addr[8]);
- //тип указатель на функцию c аргументом в виде пакета
- typedef void (*PHandlerPacket)(sHeader param);
- class cExtensionMaster;
- class cExtensionDevice10;
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //cExtensionPort
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //для каждого порта свой экземпляр класса
- class cExtensionPort
- {
- private:
- //указатель на функцию в родительском классе, которая будет заниматься передачей данных
- PHandlerPacket SendPacketFunction;
- //указатель на объект девайса. нужен для доступа к параметрам передачи от имени порта
- cExtensionDevice10 * ExtensionDevice;
- public:
- //внутри объекта храним указатель на функцию обратного вызова когда порт изменится
- PHandlerPort OnChangeHandler = NULL;
- //описание состояния порта
- byte Num = 0; // Номер порта в устройстве
- byte Type = 0; // Тип порта
- uint16_t Value = 0; // Значение в порту
- uint16_t TrigUp = 0; // триггер если больше чем это, 0 - отключить
- uint16_t TrigDown = 0; // триггер если меньше чем это 0 - отключить
- //конструктор класса, передаем указатель на функцию, которая будет обрабатывать изменения в порту
- cExtensionPort(byte vNum, byte vType, cExtensionDevice10 * pExtensionDevice );
- //конструктор класса на тот случай когда ничего не надо делать
- //cExtensionPort();
- //задать значение порта
- //Это чтоб делать так: device.ports[0].set(123).Send()
- cExtensionPort Set(long vValue);
- cExtensionPort Set(long vValue, long vTrigUp, long vTrigDown);
- //Отправка состояния порта в периферию
- cExtensionPort Send();
- //получение состояния порта
- cExtensionPort Get();
- //метод вызывается из родительского класса и служит для вызова функции обработки
- cExtensionPort OnChange(PHandlerPort h);
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //cExtensionDevice10
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //тип девайса 10
- class cExtensionDevice10
- {
- private:
- //указатель на функцию которая будет вызвана когда значение портов прочитано
- PHandler DigitalGetHandler;
- //указатель на функцию, которая будет вызвана если ключ прочитан
- PHandlerByteArr8 KeyReadHandler;
- //указатель на объект девайса. нужен для доступа к параметрам передачи от имени порта
- cExtensionMaster * ExtensionMaster;
- public:
- //описание девайса
- static const byte PortCount = 21;
- static const byte DigitalOutCount = 4;
- static const byte DigitalInCount = 9;
- static const byte AnalogOutCount = 0;
- static const byte AnalogInCount = 8;
- //параметры найденного устройства
- const byte Type=0x10;
- byte Addr=0x00;
- cExtensionPort* Port[PortCount];
- //конструктор класса создает массив объектов типа порт
- //первый параметр - адрес девайса
- cExtensionDevice10(byte vAddr, cExtensionMaster * pExtensionMaster);
- //Запоминаем обработчик события получения номера ключа
- void OnKeyRead(PHandlerByteArr8 h);
- //Отправка данных одного порта, обычно вызывается из объекта типа порт
- void Set(byte vNum);
- //Синхронизация состояния всех портов
- void UpdateAll();
- //отправка состояния всех портов
- void SetAll();
- //получение состояния всех портов
- void GetAll();
- //метод вызывается при получении пакета, анализируется и т.п.
- //получает параметры: адрес устройства, тип устройства, код функции, размер данных, блок данных
- //возвращает true если все хорошо
- bool onRecieve(byte vAddr, byte vType, byte vFunc, byte vSize, char *buf);
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //cExtensionMaster
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- class cExtensionMaster
- {
- private:
- //указатель на последовательный порт
- //порт может быть любым, аппаратным или программным
- Stream* serialPort = NULL;
- //внутри объекта храним указатель на функцию обратного вызова
- PHandlerPacket RecieveHandler;
- PHandlerByte DiscoveryHandler;
- FastCRC16 CRC16;
- //номер транзакции
- unsigned long transaction=0;
- //магическое число начала пакета
- #define MAGICHEAD 0xAABB
- //номер транзакции
- unsigned long Transaction=0;
- public:
- //массив для устройств типа cExtensionDevice10, максимум 8 штук
- cExtensionDevice10 * Dev10[EXTDEV_TYPE_10_MAXCOUNT];
- byte Dev10Count=0;
- //конструктор класса, передаем указатель на последовательный порт
- //и назначаем переменной объекта адрес этого порта
- cExtensionMaster(Stream* _s);
- // void cExtension();
- //зададим функцию приема сообщения
- //void setup(PHandlerPacket h, PacketStd p);
- //тут отрабатываем прием сообщений и вызов callback процедуры
- void process();
- //передача сформированного пакета данных
- //параметры: адрес, тип устройства, функция,длинна данных, данные
- void transmit(byte vAddr, byte vType, byte vFunc, byte vSize, uint8_t *buf);
- //передача стандартного пакета
- void transmitStd(sHeader Header);
- //запустить процедуру обнаружения устройств
- //передаем в нее функцию в которая будет вызвана когда что-то найдено
- //в нее будет передано количество обнаруженных устройств.
- void discovery(PHandlerByte h);
- void PrintHeader(String title, sHeader Header);
- };
- /////////////////////////////////////////////////////////////////////////////
- //Это cExtensionMaster.cpp
- #include "cExtensionMaster.h"
- /////////////////////////////////////////////////////////////////////////////
- //cExtensionPort
- /////////////////////////////////////////////////////////////////////////////
- //первый параметр - номер порта, его нужно задать.
- //второй параметр - тип порта
- //третий параметр - указатель на родительский объект чтоб использовать его свойства и методы
- cExtensionPort::cExtensionPort(byte vNum, byte vType, cExtensionDevice10 * pExtensionDevice )
- {
- if(!pExtensionDevice)
- return;
- //в переменной объекта запоминаем указатель функцию которая будет отсылать команды
- //ей передается сформированный пакет
- //this->SendPacketFunction = (PHandlerPacket)h;
- //тут запоминаем указатель на объект устройства чтоб использовать его свойства и методы
- this->ExtensionDevice = pExtensionDevice;
- //запоминаем в свойстве объекта номер порта и тип
- this->Num=vNum;
- this->Type=vType;
- }
- //конструктор класса на тот случай когда ничего не надо делать
- //cExtensionPort::cExtensionPort();
- //задать значение порта
- //Это чтоб делать так: device.ports[0].set(123).Send()
- cExtensionPort cExtensionPort::Set(long vValue)
- {
- this->Value=vValue;
- return *this;
- }
- //задать значение порта и значения триггеров
- cExtensionPort cExtensionPort::Set(long vValue, long vTrigUp, long vTrigDown)
- {
- this->Value=vValue;
- this->TrigUp=vTrigUp;
- this->TrigDown=vTrigDown;
- return *this;
- }
- //Отправка состояния порта в периферию
- cExtensionPort cExtensionPort::Send()
- {
- //вызываем функцию отправки в родительском объекте и передаем номер, какой послать
- this->ExtensionDevice->Set(this->Num);
- return *this;
- }
- //получение состояния порта
- //cExtensionPort cExtensionPort::Get();
- //метод вызывается из родительского класса и служит для вызова функции обработки
- //логика такая: прилетает событие изменения порта в объект cExtensionMaster, тот видит тип устройства 10
- //передает пакет в объект cExtensionDevice10, тот видит номер порта и вызывает эту функцию
- cExtensionPort cExtensionPort::OnChange(PHandlerPort h)
- {
- if(!h)
- return *this;
- this->OnChangeHandler=h;
- }
- // void cExtensionPort::PrintPort(String title, byte vNum)
- // {};
- /////////////////////////////////////////////////////////////////////////////
- //cExtensionDevice10
- /////////////////////////////////////////////////////////////////////////////
- //конструктор класса создает массив объектов типа порт
- cExtensionDevice10::cExtensionDevice10(byte vAddr, cExtensionMaster * pExtensionMaster)
- {
- Serial.print("cExtensionDevice10: vAddr ");
- Serial.println(vAddr);
- Serial.print("cExtensionDevice10: this->Addr ");
- Serial.println(this->Addr);
- //сохраняем адрес устройства
- this->Addr=vAddr;
- Serial.print("cExtensionDevice10: this->Addr ");
- Serial.println(this->Addr);
- //сохраняем ссылку на класс ExtensionMaster для работы с его функциями
- this->ExtensionMaster=pExtensionMaster;
- //инициализируем порты
- //порты-выходы идут первыми чтоб удобнее циклы делать
- this->Port[0]= new cExtensionPort(0,EXTDEV_OUTPUT,this); // DO0 32 PD2 Выход сирены
- this->Port[1]= new cExtensionPort(1,EXTDEV_OUTPUT,this); // DO1 1 PD3 Выход сигнальной лампы
- this->Port[2]= new cExtensionPort(2,EXTDEV_OUTPUT,this); // DO2 2 PD4 Выход замка двери 1
- this->Port[3]= new cExtensionPort(3,EXTDEV_OUTPUT,this); // DO3 9 PD5 Выход замка двери 2
- //порты-входы идут последними
- this->Port[4]= new cExtensionPort(4,EXTDEV_INPUT,this); // DI0 12 PB0 Пожарный шлейф 0
- this->Port[5]= new cExtensionPort(5,EXTDEV_INPUT,this); // DI1 13 PB1 Пожарный шлейф 1
- this->Port[6]= new cExtensionPort(6,EXTDEV_INPUT,this); // DI2 14 PB2 Пожарный шлейф 2
- this->Port[7]= new cExtensionPort(7,EXTDEV_INPUT,this); // DI3 15 PB3 Пожарный шлейф 3
- this->Port[8]= new cExtensionPort(8,EXTDEV_INPUT,this); // DI4 16 PB4 Пожарный шлейф 4
- this->Port[9]= new cExtensionPort(9,EXTDEV_INPUT,this); // DI5 17 PB5 Пожарный шлейф 5
- this->Port[10]= new cExtensionPort(10,EXTDEV_INPUT,this); // DI6 7 PB6 Пожарный шлейф 6
- this->Port[11]= new cExtensionPort(11,EXTDEV_INPUT,this); // DI7 8 PB7 Пожарный шлейф 7
- this->Port[12]= new cExtensionPort(12,EXTDEV_INPUT,this); // DI8 11 PD7 Открытие корпуса
- this->Port[13]= new cExtensionPort(13,EXTDEV_ANALOG,this); // AI0 23 PC0 Охранный шлейф 0
- this->Port[14]= new cExtensionPort(14,EXTDEV_ANALOG,this); // AI1 24 PC1 Охранный шлейф 1
- this->Port[15]= new cExtensionPort(15,EXTDEV_ANALOG,this); // AI2 25 PC2 Охранный шлейф 2
- this->Port[16]= new cExtensionPort(16,EXTDEV_ANALOG,this); // AI3 26 PC3 Охранный шлейф 3
- this->Port[17]= new cExtensionPort(17,EXTDEV_ANALOG,this); // AI4 27 PC4 Охранный шлейф 4
- this->Port[18]= new cExtensionPort(18,EXTDEV_ANALOG,this); // AI5 28 PC5 Охранный шлейф 5
- this->Port[19]= new cExtensionPort(19,EXTDEV_ANALOG,this); // AI6 19 ADC6 Охранный шлейф 6
- this->Port[20]= new cExtensionPort(20,EXTDEV_ANALOG,this); // AI7 22 ADC7 Охранный шлейф 7
- }
- //Запоминаем обработчик события получения номера ключа
- void cExtensionDevice10::OnKeyRead(PHandlerByteArr8 h)
- {
- if(h)
- this->KeyReadHandler=h;
- }
- //Отправка данных одного порта
- void cExtensionDevice10::Set(byte vNum)
- {
- //делаем указатель на переменную типа uint8_t для побайтового перевода в массив байтов
- const uint8_t * ptr = (const uint8_t *) &(this->Port[vNum]);
- //делаем буфер размером со структуру данных порта
- uint8_t buf[sizeof(this->Port[vNum])];
- //записываем все байты в массив буфера
- for(byte i=1;i<sizeof(this->Port[vNum]);i++)
- {
- buf[i]=*ptr++;
- //Serial.print(*ptr,HEX);
- }
- //передача данных, параметры: адрес, тип устройства, функция,длинна данных, данные
- this->ExtensionMaster->transmit(this->Addr,EXTDEV_TYPE_10,EXTDEV_FUNC_SET,sizeof(buf),buf);
- }
- //Синхронизация состояния всех портов
- void cExtensionDevice10::UpdateAll()
- {
- this->SetAll();
- this->GetAll();
- }
- //отправка состояния всех портов
- void cExtensionDevice10::SetAll()
- {
- //переберем все порты в цикле
- for (byte i=0; i<this->PortCount; i++)
- {
- //если это порт-выход
- if(this->Port[i]->Type==EXTDEV_OUTPUT)
- {
- //отправим команду с данными в порт
- this->Set(i);
- }
- }
- }
- //получение состояния всех портов
- void cExtensionDevice10::GetAll()
- {
- //для запроса состояния всех портов используем специальную функцию протокола 0х10
- //массив с единственным нулем, просто так
- uint8_t buf[1]={0x00};
- //передача данных, параметры: адрес, тип устройства, функция,длинна данных, данные
- this->ExtensionMaster->transmit(this->Addr,EXTDEV_TYPE_10,EXTDEV_FUNC_GETALL,sizeof(buf), buf);
- }
- //метод вызывается при получении пакета, анализируется и т.п.
- //получает параметры: адрес устройства, тип устройства, код функции, размер данных, блок данных
- //возвращает true если все хорошо
- bool cExtensionDevice10::onRecieve(byte vAddr, byte vType, byte vFunc, byte vSize, char buf[])
- {
- Serial.print("cExtensionDevice10::onRecieve: this->Addr ");
- Serial.println(this->Addr);
- //если адрес на наш и тип устройства не подходит то ничего не делаем
- if(vAddr != this->Addr || vType!= EXTDEV_TYPE_10)
- return false;
- Serial.print("cExtensionDevice10::onRecieve: ");
- Serial.println(vAddr);
- //смотрим на код функции и решаем что делать
- switch(vFunc)
- {
- //прилетело состояние одного порта
- case EXTDEV_FUNC_GET:
- {
- Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_GET");
- Serial.println(vAddr);
- //если данных меньше чем надо, возвращаем ошибку
- if(vSize<sizeof(PortState))
- return false;
- //Эта структура используется для обмена данными по одному порту
- PortState RXVals;
- //указатель типа байт ссылается на структуру
- uint8_t* pRXVals = (uint8_t*)&RXVals;
- //последовательно примем все байты данных
- for (byte i=0; i < vSize; i++)
- {
- *pRXVals++ = buf[i];
- }
- //проверяем номер порта, не должен быть больше чем у нас портов
- if(RXVals.Num > this->PortCount || RXVals.Num < 0)
- return false;
- //сравниваем данные что были и что получили и если установлен обработчик события
- if(this->Port[RXVals.Num]->Value !=RXVals.Value && this->Port[RXVals.Num]->OnChangeHandler)
- //если значение изменилось то вызываем функцию которую кто-то навесил
- this->Port[RXVals.Num]->OnChangeHandler(RXVals.Num, RXVals.Value, RXVals.TrigType);
- //данные получены, пишем в состояние порта
- this->Port[RXVals.Num]->Value = RXVals.Value;
- break;
- }
- //прилетело состояние всех портов
- case EXTDEV_FUNC_GETALL:
- {
- Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_GETALL");
- Serial.println(vAddr);
- //массив для данных о портах
- uint8_t RXVals[17];
- //если данных меньше чем надо, возвращаем ошибку
- if(vSize<sizeof(RXVals))
- return false;
- //Эта структура используется для обмена данными по одному порту
- //PortsStateAll RXVals; !у нас массивом захуярено
- //указатель типа байт ссылается на структуру
- uint8_t* pRXVals = (uint8_t*)&RXVals;
- //последовательно примем все байты данных
- for (byte i=0; i < vSize; i++)
- {
- *pRXVals++ = buf[i];
- }
- //данные получены, переберем все порты в пакете данных
- for(byte i=0; i < 17; i++)
- {
- //номера портов ввода начинаются с четырех
- byte currNum = i+4;
- //сравниваем данные что были и что получили и если установлен обработчик события
- if(this->Port[currNum]->Value !=RXVals[i] && this->Port[currNum]->OnChangeHandler)
- //если значение изменилось то вызываем функцию которую кто-то навесил
- this->Port[currNum]->OnChangeHandler(currNum, RXVals[i], EXTDEV_TRIGOFF);
- //пишем в состояние порта актуальное значение
- this->Port[currNum]->Value = RXVals[i];
- }
- break;
- }
- //прилетело событие чтения ключа iButton
- case EXTDEV_FUNC_KEYREAD:
- {
- Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_KEYREAD ");
- Serial.println(vAddr);
- //если данных меньше чем надо, возвращаем ошибку
- if(vSize<8)
- return false;
- //передаем массив функции, которая обрабатывает обнаруженные ключи
- this->KeyReadHandler(buf);
- break;
- }
- }
- //если все нормально, вернем true
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //cExtensionMaster
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //конструктор класса, передаем указатель на последовательный порт
- //и назначаем переменной объекта адрес этого порта
- // void cExtensionMaster::cExtension();
- cExtensionMaster::cExtensionMaster(Stream* _s): serialPort(_s){}
- //тут отрабатываем прием сообщений передаем обработку в объект устройства, пусть оно разбирается что к чему
- void cExtensionMaster::process()
- {
- //запилим буфер на 300 байт - максимальный размер сообщения, которое может прилететь
- char buff[300];
- int bytes=0;
- if (serialPort->available())
- {
- //создаем в памяти заголовок
- sHeader Header;
- sHeader * HeaderPtr = &Header;
- //получим данные с последовательного порта в буфер все что есть
- //bytes=serialPort->readBytes(buff,20);
- while(serialPort->available())
- {
- char b=(char) serialPort->peek();
- //если не нашли стартовую последовательность
- if(b!=0xBB)
- {//стираем байт за байтом из буфера
- buff[bytes] = (char) serialPort->read();
- }
- else
- {//нашли буквы BB, значит нашли заголовок
- //получим из буфера заголовок целиком
- serialPort->readBytes((char*)HeaderPtr, sizeof(sHeader)) == sizeof(sHeader);
- // PrintHeader("Header get",Header);
- break;
- }
- }
- // //выделим из буфера заголовок и данные
- // //!!Тут сразу можно проверить на наличие правильного стартового слова
- // uint8_t* ptr28 = (uint8_t* )&Header;
- // //если данных недостаточно хотя бы на хеадер, бросаем затею
- // Serial.print("Bytes: ");
- // Serial.println(bytes);
- // if(bytes < sizeof(Header))
- // return;
- // //переписываем хеадер в структуру
- // for(byte i=0; i<sizeof(Header);i++)
- // {
- // *ptr28=(uint8_t)buff[i];
- // ptr28++;
- // }
- // //тут наверное нужно определить целостность данных, пока не до этого
- PrintHeader("Process",Header);
- char Data[Header.Size];
- if(Header.Size>0)
- {
- //В хеадере хранится размер данных,
- //char * DataPtr = &Data;
- //получим из буфера остаток данных
- serialPort->readBytes(Data, sizeof(Data)) == sizeof(Data);
- }
- //вырезаем из буфера остаток данных
- //for(byte i=sizeof(Header); i<sizeof(Header)+Header.Size;i++)
- // Data[i-sizeof(Header)]=buff[i];
- //Посмотрим что в пакетах, может это нам нужно для работы
- //если пакет предназначен для центрального контроллера и при этом не исходит от него
- //(кстати сквозное прохождение пакета можно рассматривать как успешную доставку)
- if(Header.Dst==0xFF && Header.Src !=0xFF)
- {
- //обслуживание discovery пакетов
- if(Header.Func==0x00)
- {
- //если устройство типа 0х10
- if(Header.Type==0x10)
- {
- Serial.print("Dev10Count: ");
- Serial.println(Dev10Count);
- Serial.print("Header.Src: ");
- Serial.println(Header.Src);
- //проверим превышение количества устройств типа 10.
- if(Dev10Count < EXTDEV_TYPE_10_MAXCOUNT)
- //создаем экземпляр объекта устройства типа 10 и передаем указатель на этот объект для правильной работы
- //cExtensionDevice10 * ptrdev = new cExtensionDevice10(Header.Src,this);
- //cExtensionDevice10 * ptrdev = &dev;
- //this->Dev10[Dev10Count] = ptrdev;
- this->Dev10[Dev10Count] = new cExtensionDevice10(Header.Src,this);
- Serial.println("####### ++++++ #######");
- if(this->Dev10[Dev10Count]==NULL)
- Serial.println("####### NULLNULL #######");
- Dev10Count++;
- Serial.println("####### Header.Type==0x10 #######");
- }
- if(Header.Type!=0x10)
- {
- //заглушка для устройств других типов
- }
- //вызовем обработчик функции обнаружения устроств (зачем?)
- //RecieveHandler(Header);
- }
- //передаем обработку пакетов устройства типа 10 в соответствующий метод
- //попутно проверим чтоб диапазон адреса не выходил за максимальное количество устройств этого типа на шине
- if(Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT)
- {
- Serial.print("Header.Src: ");
- Serial.println(Header.Src);
- this->Dev10[Header.Src]->onRecieve(Header.Src, Header.Type, Header.Func, Header.Size, Data);
- Serial.println("####### Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT #######");
- }
- }
- //передаем полученный пакет в обработчик девайса с номером порта
- //Serial.println("Handler... ");
- // ;
- }
- }
- //передача сформированного пакета данных
- //параметры: адрес, тип устройства, функция,длинна данных, данные
- void cExtensionMaster::transmit(byte vAddr, byte vType, byte vFunc, byte vSize, uint8_t *buf)
- {
- //инкремент номера транзакции
- this->Transaction++;
- //подготовим заголовок
- sHeader Header;
- //указатель на заголовок
- sHeader * pHeader = &Header;
- //заполняем поля заголовка
- Header.Src=0xFF;
- Header.Dst=vAddr;
- Header.Type=vType;
- Header.Func=vFunc;
- Header.Size=vSize;
- Header.Trans=Transaction;
- Header.CRC = 0x0000; //на всякий случай ;)
- //Header.Data = buf;
- //сериализуем заголовок
- const uint8_t * ptr = (const uint8_t *) &Header;
- //буфер размером со структуру плюс размер буфера
- uint8_t HeaderBuf[sizeof(Header)+vSize];
- //записываем все байты в массив буфера
- for(int i=1;i<sizeof(Header);i++)
- {
- HeaderBuf[i]=*ptr++;
- //Serial.print(*ptr,HEX);
- }
- //дописываем данные в пакет
- for(int i=sizeof(Header);i<sizeof(Header)+vSize;i++)
- {
- HeaderBuf[i]=*buf++;
- //Serial.print(*ptr,HEX);
- }
- //посчитаем и запишем контрольную сумму
- //!!!! нужно переделать, неверно это. Отправлять будем буфер
- Header.CRC = CRC16.ccitt(HeaderBuf, sizeof(HeaderBuf));
- //отправляем пакет в порт
- serialPort->write((const char*)HeaderBuf, sizeof(HeaderBuf));
- PrintHeader("transmit",Header);
- }
- //передача стандартного пакета с данными нулевой длинны. по сути только заголовок передаем
- void cExtensionMaster::transmitStd(sHeader Header)
- {
- unsigned int crc=0;
- //инкремент номера транзакции
- this->Transaction++;
- Header.Trans=this->Transaction;
- sHeader* HeaderPtr = &Header;
- //посчитаем контрольную сумму
- Header.CRC=0; //на всякий случай обнулим ее
- //делаем указатель на переменную типа uint8_t для побайтового перевода в массив байтов
- const uint8_t * ptr = (const uint8_t *) &Header;
- //буфер размером со структуру
- uint8_t buf[sizeof(Header)];
- //записываем все байты в массив буфера
- for(int i=1;i<sizeof(Header);i++)
- {
- buf[i]=*ptr++;
- Serial.print(*ptr,HEX);
- }
- //считаем контрольную сумму
- crc=CRC16.ccitt(buf, sizeof(buf));
- //пишем получившуюся контрольную сумму в пакет
- Header.CRC=crc;
- //отправляем пакет в порт
- serialPort->write((const char*)HeaderPtr, sizeof(sHeader));
- PrintHeader("transmitStd",Header);
- }
- //запустить процедуру обнаружения устройств
- //передаем в нее функцию в которая будет вызвана когда что-то найдено
- //в нее будет передано количество обнаруженных устройств.
- void cExtensionMaster::discovery(PHandlerByte h)
- {
- Serial.println("Discovery");
- //ставим обработчик
- if(!h)
- return;
- //в переменной объекта запоминаем указатель на обработчик события обнаружения устройств
- DiscoveryHandler = (PHandlerByte)h;
- //переменные для работы
- //увеличиваем номер транзакции на единицу
- transaction++;
- //сформируем пакет для транзакции, формируем из хеадера
- sHeader Header;
- Header.Start=MAGICHEAD; //магическое начало пакета
- Header.Src=0xFF; //запрос от контроллера
- Header.Dst=0xFF; //широковещательный запрос на все устройства
- Header.Type=0x00; //код функции 0х00 - определение устройств
- Header.Func=0x00;
- Header.Size=0x00;
- Header.Value=0x00000000;
- Header.Trans=transaction;
- Header.CRC=0x0000; //контрольная сумма считается в передающем блоке
- //передаем пакет. Транзакции пока не учитываем, очереди команд нету. Надеемся что все будет хорошо
- transmitStd(Header);
- }
- void cExtensionMaster::PrintHeader(String title, sHeader Header)
- {
- Serial.println();
- Serial.println(title);
- Serial.print("Start: ");
- Serial.println(Header.Start, HEX);
- Serial.print("Src: ");
- Serial.println(Header.Src, HEX);
- Serial.print("Dst: ");
- Serial.println(Header.Dst, HEX);
- Serial.print("Type: ");
- Serial.println(Header.Type, HEX);
- Serial.print("Func: ");
- Serial.println(Header.Func, HEX);
- Serial.print("Size: ");
- Serial.println(Header.Size, HEX);
- Serial.print("Trans: ");
- Serial.println(Header.Trans);
- Serial.print("CRC: ");
- Serial.println(Header.CRC, HEX);
- Serial.print("Value: ");
- Serial.println(Header.Value, HEX);
- }
- /////////////////////////////////////////////////////////////////////////////
- //Это откуда вызывается код
- #include <SoftwareSerial.h>
- //https://github.com/FrankBoesing/FastCRC
- //#include <FastCRC.h>
- #include <Ticker.h>
- #include "cExtensionMaster.h"
- #define STX 13 //scl
- #define SRX 12 //D6
- //rxPin, txPin, inverse_logic, buffer size
- SoftwareSerial extPort(SRX, STX, false, 128);
- Ticker Send;
- //передаем указатель на поток
- cExtensionMaster device(&extPort);
- //функция печати содержимого пакета
- void RecievePacket(sHeader Header)
- {
- device.PrintHeader("RecievePacket",Header);
- }
- void OnRecievePacket(byte count)
- {
- Serial.print("OnRecievePacket: ");
- Serial.println(count);
- }
- void SendPacket()
- {
- // device.send();
- device.discovery(OnRecievePacket);
- }
- void setup() {
- Serial.begin(115200);
- extPort.begin(115200); //Initialize software serial with baudrate of 115200
- // device.setup(RecievePacket,pack);
- //назначим отправку пакетов каждые 100 мсек
- Send.attach_ms(7000, SendPacket);
- }
- void loop()
- {
- device.process();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement