Advertisement
Guest User

Untitled

a guest
Jan 8th, 2019
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 42.96 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////
  2. //Это cExtensionMaster.cpp
  3.  
  4. // Протокол обмена данными между периферийными устройствами
  5.  
  6. // описание устройства типа 10
  7. //Взаимодействие классов:
  8. //Класс cExtensionMaster предназначен для взаимодействия с периферией,
  9. //он нумерует устройства и реализует функции отправки пакетов.
  10. //На каждое обнаруженное устройство создается элемент в массиве устройств типа cExtensionDevice10
  11. //В свою очередь каждое устройство этого типа имеет массив указателей на cExtensionPort
  12. //Передача данных происходит из класса cExtensionMaster, он формирует заголовок для пакета данных
  13. //В него другие классы передают адрес передачи, коды функций и сериализованные данные
  14. //Данные присоединяются к заголовку, снова сериализуются и отправляются в порт
  15. //Прием данных осуществляется в обратном порядке: декодируется стандартный заголовок, определяется
  16. //размер блока даныных и он передается в класс устройства, который будет его обрабатывать
  17. //Функция назначения определяется уже там, там же декодируется пакет данных и обрабатывается.
  18. //
  19. //про адресацию: проще сделать для каждого типа устройства свой массив
  20. //при этом получается что удобнее сделать для каждого типа устойств свою сквозную нумерацию, соответствующую индексам массива
  21. //нумерация адресов устройств начинается с нуля
  22.  
  23. #include <Arduino.h>
  24.  
  25.  
  26. //https://github.com/FrankBoesing/FastCRC
  27.  
  28. #include <FastCRC.h>
  29.  
  30. #define EXTDEV_TYPE_10_MAXCOUNT 8    //максимальное количество устройств типа 0х10
  31.  
  32.  
  33. struct sHeader
  34. {
  35.   uint16_t Start = 0x0000;//  Стартовая последовательность
  36.   byte Src = 0xFF;//  Адрес Мастер-девайса
  37.   byte Dst = 0x00;//  Адрес устройства куда направить пакет
  38.   byte Type = 0x00;  //  тип устройства
  39.   byte Func = 0x00;  //  функция
  40.   byte Size = 0x00;  //  Длинна блока данных, максимум 256 байт, должно хватить
  41.   unsigned long Trans = 0x00000000;  //  номер транзцакции
  42.   uint16_t CRC = 0x0000;  //  контрольная сумма
  43.   unsigned long Value; //Данные для простого обмена, например, для обслуживания протокола
  44. };
  45. //тип указатель на функцию c аргументом в виде пакета
  46. typedef void (*PHandlerPacket)(sHeader param);
  47.  
  48. //тип указатель на функцию c аргументом в виде байта
  49. typedef void (*PHandlerByte)(byte param);
  50.  
  51.  
  52. //#include "cExtensionMaster.h"
  53.  
  54. #define EXTDEV_TYPE_10 0x10    //код типа устройства 10
  55. #define EXTDEV_FUNC_SET 0x10    //установить значение порта
  56. #define EXTDEV_FUNC_GET 0x10    //событие получения состояния порта
  57. #define EXTDEV_FUNC_GETALL 0x29    //получить значение всех портов
  58. #define EXTDEV_FUNC_KEYREAD 0x50    //считан ключ iButton
  59.  
  60. //типы портов
  61. #define EXTDEV_INPUT 0    //Цифровой вход
  62. #define EXTDEV_OUTPUT 1   //Цифровой выход
  63. #define EXTDEV_COUNTER 2  //Счетчик импульсов
  64. #define EXTDEV_FREQ 3     //Генератор последовательности импульсов
  65. #define EXTDEV_PWM 4      //ШИМ выход
  66. #define EXTDEV_ANALOG 5   //Аналоговый вход
  67.  
  68. //типы триггеров
  69. #define EXTDEV_TRIGOFF 0   //Триггер не задан или нет возможности
  70. #define EXTDEV_TRIGNORM 1   //Значение вошло в норму
  71. #define EXTDEV_TRIGUP 2   //Значение превысило порог
  72. #define EXTDEV_TRIGDOWN 3   //Значение ниже заданного
  73.  
  74. //Состояние портов периферийного устройства, используется при получении пакетов
  75. //Эта структура используется для обмена данными по одному порту, в т.ч по событию
  76. struct PortState {
  77.   byte Num = 0;           //  Номер порта в устройстве
  78.   uint16_t Value = 0;     //  Значение в порту
  79.   byte TrigType = 0;       //  какой триггер сработал
  80.  
  81. };
  82. //значения портов периферийного устройства, используется при получении состояния всех портов
  83. //получить можно только состояние портов которые можно прочитать
  84. struct sPortsStateAll{
  85.   uint16_t Value4=0x0000;
  86.   uint16_t Value5=0x0000;
  87.   uint16_t Value6=0x0000;
  88.   uint16_t Value7=0x0000;
  89.   uint16_t Value8=0x0000;
  90.   uint16_t Value9=0x0000;
  91.   uint16_t Value10=0x0000;
  92.   uint16_t Value11=0x0000;
  93.   uint16_t Value12=0x0000;
  94.   uint16_t Value13=0x0000;
  95.   uint16_t Value14=0x0000;
  96.   uint16_t Value15=0x0000;
  97.   uint16_t Value16=0x0000;
  98.   uint16_t Value17=0x0000;
  99.   uint16_t Value18=0x0000;
  100.   uint16_t Value19=0x0000;
  101.   uint16_t Value20=0x0000;
  102. };
  103. //другой вариант - с массивом, чтоб можнобыло перебором определить что изменилось и вызвать обработчик
  104. //uint16_t PortsStateAll[17];
  105.  
  106. //тип указатель на функцию c аргументами номер порта, значение, тип триггера который сработал
  107. typedef void (*PHandlerPort)(byte port, long value, byte trigType);
  108. //тип указатель на функцию без аргументов
  109. typedef void (*PHandler)();
  110. //тип указатель на функцию аргументом-массивом для считывателя ключа
  111. typedef void (*PHandlerByteArr8)(char addr[8]);
  112.  
  113. //тип указатель на функцию c аргументом в виде пакета
  114. typedef void (*PHandlerPacket)(sHeader param);
  115.  
  116. class cExtensionMaster;
  117. class cExtensionDevice10;
  118.  
  119. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. //cExtensionPort
  121. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  122. //для каждого порта свой экземпляр класса
  123. class cExtensionPort
  124. {
  125.   private:
  126.  
  127.     //указатель на функцию в родительском классе, которая будет заниматься передачей данных
  128.     PHandlerPacket SendPacketFunction;
  129.     //указатель на объект девайса. нужен для доступа к параметрам передачи от имени порта
  130.     cExtensionDevice10 * ExtensionDevice;
  131.  
  132.    
  133.   public:
  134.     //внутри объекта храним указатель на функцию обратного вызова когда порт изменится
  135.     PHandlerPort OnChangeHandler = NULL;
  136.     //описание состояния порта
  137.     byte Num = 0;           //  Номер порта в устройстве
  138.     byte Type = 0;          //  Тип порта
  139.     uint16_t Value = 0;         //  Значение в порту
  140.     uint16_t TrigUp = 0;         //  триггер если больше чем это, 0 - отключить
  141.     uint16_t TrigDown = 0;       //  триггер если меньше чем это 0 - отключить
  142.  
  143.     //конструктор класса, передаем указатель на функцию, которая будет обрабатывать изменения в порту
  144.     cExtensionPort(byte vNum, byte vType, cExtensionDevice10 * pExtensionDevice );
  145.     //конструктор класса на тот случай когда ничего не надо делать
  146.     //cExtensionPort();
  147.     //задать значение порта
  148.     //Это чтоб делать так: device.ports[0].set(123).Send()
  149.     cExtensionPort Set(long vValue);
  150.     cExtensionPort Set(long vValue, long vTrigUp, long vTrigDown);
  151.    
  152.    
  153.     //Отправка состояния порта в периферию
  154.     cExtensionPort Send();
  155.     //получение состояния порта
  156.     cExtensionPort Get();
  157.     //метод вызывается из родительского класса и служит для вызова функции обработки
  158.     cExtensionPort OnChange(PHandlerPort h);
  159.    
  160. };
  161.  
  162. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. //cExtensionDevice10
  164. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  165.  
  166. //тип девайса 10
  167. class cExtensionDevice10
  168. {
  169.   private:
  170.  
  171.     //указатель на функцию которая будет вызвана когда значение портов прочитано
  172.     PHandler DigitalGetHandler;
  173.     //указатель на функцию, которая будет вызвана если ключ прочитан
  174.     PHandlerByteArr8 KeyReadHandler;
  175.    
  176.     //указатель на объект девайса. нужен для доступа к параметрам передачи от имени порта
  177.     cExtensionMaster * ExtensionMaster;
  178.    
  179.   public:
  180.     //описание девайса
  181.     static const byte PortCount = 21;
  182.     static const byte DigitalOutCount = 4;
  183.     static const byte DigitalInCount = 9;
  184.     static const byte AnalogOutCount = 0;
  185.     static const byte AnalogInCount = 8;
  186.  
  187.     //параметры найденного устройства
  188.     const byte Type=0x10;
  189.     byte Addr=0x00;
  190.  
  191.     cExtensionPort* Port[PortCount];
  192.  
  193.     //конструктор класса создает массив  объектов типа порт
  194.     //первый параметр - адрес девайса
  195.     cExtensionDevice10(byte vAddr, cExtensionMaster * pExtensionMaster);
  196.  
  197.     //Запоминаем обработчик события получения номера ключа
  198.     void OnKeyRead(PHandlerByteArr8 h);
  199.     //Отправка данных одного порта, обычно вызывается из объекта типа порт
  200.     void Set(byte vNum);
  201.     //Синхронизация состояния всех портов
  202.     void UpdateAll();
  203.     //отправка состояния всех портов
  204.     void SetAll();
  205.     //получение состояния всех портов
  206.     void GetAll();
  207.     //метод вызывается при получении пакета, анализируется и т.п.
  208.     //получает параметры: адрес устройства, тип устройства, код функции, размер данных, блок данных
  209.     //возвращает true если все хорошо
  210.     bool onRecieve(byte vAddr, byte vType, byte vFunc, byte vSize, char *buf);
  211. };
  212. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. //cExtensionMaster
  214. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  215. class cExtensionMaster
  216. {
  217.   private:
  218.     //указатель на последовательный порт
  219.     //порт может быть любым, аппаратным или программным
  220.     Stream* serialPort = NULL;
  221.     //внутри объекта храним указатель на функцию обратного вызова
  222.     PHandlerPacket RecieveHandler;
  223.     PHandlerByte DiscoveryHandler;
  224.  
  225.     FastCRC16 CRC16;
  226.     //номер транзакции
  227.     unsigned long transaction=0;
  228.     //магическое число начала пакета
  229.     #define MAGICHEAD 0xAABB
  230.     //номер транзакции
  231.     unsigned long Transaction=0;
  232.    
  233.   public:
  234.     //массив для устройств типа cExtensionDevice10, максимум 8 штук
  235.     cExtensionDevice10 * Dev10[EXTDEV_TYPE_10_MAXCOUNT];
  236.     byte Dev10Count=0;
  237.    
  238.     //конструктор класса, передаем указатель на последовательный порт
  239.     //и назначаем переменной объекта адрес этого порта
  240.     cExtensionMaster(Stream* _s);
  241.     //    void cExtension();
  242.  
  243.     //зададим функцию приема сообщения
  244.     //void setup(PHandlerPacket h, PacketStd p);
  245.  
  246.     //тут отрабатываем прием сообщений и вызов callback процедуры
  247.     void process();
  248.  
  249.     //передача сформированного пакета данных
  250.     //параметры: адрес, тип устройства, функция,длинна данных, данные
  251.     void transmit(byte vAddr, byte vType, byte vFunc, byte vSize, uint8_t *buf);
  252.  
  253.     //передача стандартного пакета
  254.     void transmitStd(sHeader Header);
  255.  
  256.     //запустить процедуру обнаружения устройств
  257.     //передаем в нее функцию в которая будет вызвана когда что-то найдено
  258.     //в нее будет передано количество обнаруженных устройств.
  259.     void discovery(PHandlerByte h);
  260.     void PrintHeader(String title, sHeader Header);
  261. };
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274. /////////////////////////////////////////////////////////////////////////////
  275. //Это cExtensionMaster.cpp
  276.  
  277. #include "cExtensionMaster.h"
  278.  
  279. /////////////////////////////////////////////////////////////////////////////
  280. //cExtensionPort
  281. /////////////////////////////////////////////////////////////////////////////
  282.  
  283.    
  284.     //первый параметр - номер порта, его нужно задать.
  285.     //второй параметр - тип порта
  286.     //третий параметр - указатель на родительский объект чтоб использовать его свойства и методы
  287.     cExtensionPort::cExtensionPort(byte vNum, byte vType, cExtensionDevice10 * pExtensionDevice )
  288.     {
  289.       if(!pExtensionDevice)
  290.         return;
  291.       //в переменной объекта запоминаем указатель функцию которая будет отсылать команды
  292.       //ей передается сформированный пакет
  293.       //this->SendPacketFunction = (PHandlerPacket)h;
  294.       //тут запоминаем указатель на объект устройства чтоб использовать его свойства и методы
  295.       this->ExtensionDevice = pExtensionDevice;
  296.       //запоминаем в свойстве объекта номер порта и тип
  297.       this->Num=vNum;
  298.       this->Type=vType;
  299.     }
  300.     //конструктор класса на тот случай когда ничего не надо делать
  301.     //cExtensionPort::cExtensionPort();
  302.    
  303.     //задать значение порта
  304.     //Это чтоб делать так: device.ports[0].set(123).Send()
  305.     cExtensionPort cExtensionPort::Set(long vValue)
  306.     {
  307.       this->Value=vValue;
  308.       return *this;
  309.     }
  310.     //задать значение порта и значения триггеров
  311.     cExtensionPort cExtensionPort::Set(long vValue, long vTrigUp, long vTrigDown)
  312.     {
  313.       this->Value=vValue;
  314.       this->TrigUp=vTrigUp;
  315.       this->TrigDown=vTrigDown;
  316.       return *this;
  317.     }
  318.    
  319.     //Отправка состояния порта в периферию
  320.     cExtensionPort cExtensionPort::Send()
  321.     {
  322.       //вызываем функцию отправки в родительском объекте и передаем номер, какой послать
  323.       this->ExtensionDevice->Set(this->Num);
  324.       return *this;
  325.     }
  326.     //получение состояния порта
  327.     //cExtensionPort cExtensionPort::Get();
  328.     //метод вызывается из родительского класса и служит для вызова функции обработки
  329.     //логика такая: прилетает событие изменения порта в объект cExtensionMaster, тот видит тип устройства 10
  330.     //передает пакет в объект cExtensionDevice10, тот видит номер порта и вызывает эту функцию
  331.     cExtensionPort cExtensionPort::OnChange(PHandlerPort h)
  332.     {    
  333.       if(!h)
  334.         return *this;
  335.       this->OnChangeHandler=h;
  336.     }
  337.    
  338.   //  void cExtensionPort::PrintPort(String title, byte vNum)
  339.   //  {};
  340.  
  341.    
  342. /////////////////////////////////////////////////////////////////////////////
  343. //cExtensionDevice10
  344. /////////////////////////////////////////////////////////////////////////////
  345.  
  346.     //конструктор класса создает массив  объектов типа порт
  347.     cExtensionDevice10::cExtensionDevice10(byte vAddr, cExtensionMaster * pExtensionMaster)
  348.     {
  349.      
  350.               Serial.print("cExtensionDevice10: vAddr ");
  351.               Serial.println(vAddr);
  352.               Serial.print("cExtensionDevice10: this->Addr ");
  353.               Serial.println(this->Addr);
  354.      
  355.       //сохраняем адрес устройства
  356.       this->Addr=vAddr;
  357.               Serial.print("cExtensionDevice10: this->Addr ");
  358.               Serial.println(this->Addr);
  359.       //сохраняем ссылку на класс ExtensionMaster для работы с его функциями
  360.       this->ExtensionMaster=pExtensionMaster;
  361.       //инициализируем порты
  362.         //порты-выходы идут первыми чтоб удобнее циклы делать
  363.         this->Port[0]= new cExtensionPort(0,EXTDEV_OUTPUT,this); // DO0   32    PD2   Выход сирены
  364.         this->Port[1]= new cExtensionPort(1,EXTDEV_OUTPUT,this); // DO1   1   PD3   Выход сигнальной лампы
  365.         this->Port[2]= new cExtensionPort(2,EXTDEV_OUTPUT,this); // DO2   2   PD4   Выход замка двери 1
  366.         this->Port[3]= new cExtensionPort(3,EXTDEV_OUTPUT,this); // DO3   9   PD5   Выход замка двери 2
  367.         //порты-входы идут последними
  368.         this->Port[4]= new cExtensionPort(4,EXTDEV_INPUT,this); // DI0    12    PB0   Пожарный шлейф 0
  369.         this->Port[5]= new cExtensionPort(5,EXTDEV_INPUT,this); // DI1    13    PB1   Пожарный шлейф 1
  370.         this->Port[6]= new cExtensionPort(6,EXTDEV_INPUT,this); // DI2    14    PB2   Пожарный шлейф 2
  371.         this->Port[7]= new cExtensionPort(7,EXTDEV_INPUT,this); // DI3    15    PB3   Пожарный шлейф 3
  372.         this->Port[8]= new cExtensionPort(8,EXTDEV_INPUT,this); // DI4    16    PB4   Пожарный шлейф 4
  373.         this->Port[9]= new cExtensionPort(9,EXTDEV_INPUT,this); // DI5    17    PB5   Пожарный шлейф 5
  374.         this->Port[10]= new cExtensionPort(10,EXTDEV_INPUT,this); // DI6    7   PB6   Пожарный шлейф 6
  375.         this->Port[11]= new cExtensionPort(11,EXTDEV_INPUT,this); // DI7    8   PB7   Пожарный шлейф 7
  376.         this->Port[12]= new cExtensionPort(12,EXTDEV_INPUT,this); // DI8    11    PD7   Открытие корпуса
  377.        
  378.         this->Port[13]= new cExtensionPort(13,EXTDEV_ANALOG,this); // AI0   23    PC0   Охранный шлейф 0
  379.         this->Port[14]= new cExtensionPort(14,EXTDEV_ANALOG,this); // AI1   24    PC1   Охранный шлейф 1
  380.         this->Port[15]= new cExtensionPort(15,EXTDEV_ANALOG,this); // AI2   25    PC2   Охранный шлейф 2
  381.         this->Port[16]= new cExtensionPort(16,EXTDEV_ANALOG,this); // AI3   26    PC3   Охранный шлейф 3
  382.         this->Port[17]= new cExtensionPort(17,EXTDEV_ANALOG,this); // AI4   27    PC4   Охранный шлейф 4
  383.         this->Port[18]= new cExtensionPort(18,EXTDEV_ANALOG,this); // AI5   28    PC5   Охранный шлейф 5
  384.         this->Port[19]= new cExtensionPort(19,EXTDEV_ANALOG,this); // AI6   19    ADC6  Охранный шлейф 6
  385.         this->Port[20]= new cExtensionPort(20,EXTDEV_ANALOG,this); // AI7   22    ADC7  Охранный шлейф 7
  386.    
  387.     }
  388.     //Запоминаем обработчик события получения номера ключа
  389.     void cExtensionDevice10::OnKeyRead(PHandlerByteArr8 h)
  390.     {
  391.       if(h)
  392.         this->KeyReadHandler=h;
  393.     }
  394.     //Отправка данных одного порта
  395.     void cExtensionDevice10::Set(byte vNum)  
  396.     {
  397.       //делаем указатель на переменную типа uint8_t для побайтового перевода в массив байтов
  398.       const uint8_t * ptr = (const uint8_t *) &(this->Port[vNum]);
  399.       //делаем буфер размером со структуру данных порта
  400.       uint8_t buf[sizeof(this->Port[vNum])];
  401.       //записываем все байты в массив буфера
  402.       for(byte  i=1;i<sizeof(this->Port[vNum]);i++)
  403.       {
  404.         buf[i]=*ptr++;
  405.         //Serial.print(*ptr,HEX);
  406.       }
  407.       //передача данных, параметры: адрес, тип устройства, функция,длинна данных, данные
  408.       this->ExtensionMaster->transmit(this->Addr,EXTDEV_TYPE_10,EXTDEV_FUNC_SET,sizeof(buf),buf);
  409.     }
  410.  
  411.     //Синхронизация состояния всех портов
  412.     void cExtensionDevice10::UpdateAll()
  413.     {
  414.       this->SetAll();
  415.       this->GetAll();
  416.     }
  417.     //отправка состояния всех портов
  418.     void cExtensionDevice10::SetAll()
  419.     {
  420.       //переберем все порты в цикле
  421.       for (byte i=0; i<this->PortCount; i++)
  422.       {
  423.         //если это порт-выход
  424.         if(this->Port[i]->Type==EXTDEV_OUTPUT)
  425.         {
  426.           //отправим команду с данными в порт
  427.           this->Set(i);
  428.         }
  429.       }
  430.     }
  431.     //получение состояния всех портов
  432.     void cExtensionDevice10::GetAll()
  433.     {
  434.       //для запроса состояния всех портов используем специальную функцию протокола 0х10
  435.       //массив с единственным нулем, просто так
  436.       uint8_t buf[1]={0x00};
  437.       //передача данных, параметры: адрес, тип устройства, функция,длинна данных, данные
  438.       this->ExtensionMaster->transmit(this->Addr,EXTDEV_TYPE_10,EXTDEV_FUNC_GETALL,sizeof(buf), buf);
  439.     }  
  440.     //метод вызывается при получении пакета, анализируется и т.п.
  441.     //получает параметры: адрес устройства, тип устройства, код функции, размер данных, блок данных
  442.     //возвращает true если все хорошо
  443.     bool cExtensionDevice10::onRecieve(byte vAddr, byte vType, byte vFunc, byte vSize, char buf[])
  444.     {
  445.               Serial.print("cExtensionDevice10::onRecieve: this->Addr ");
  446.               Serial.println(this->Addr);
  447.        
  448.       //если адрес на наш и тип устройства не подходит то ничего не делаем
  449.       if(vAddr != this->Addr || vType!= EXTDEV_TYPE_10)
  450.         return false;
  451.               Serial.print("cExtensionDevice10::onRecieve: ");
  452.               Serial.println(vAddr);
  453.         //смотрим на код функции и решаем что делать
  454.         switch(vFunc)
  455.         {
  456.           //прилетело состояние одного порта
  457.           case EXTDEV_FUNC_GET:
  458.           {
  459.               Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_GET");
  460.               Serial.println(vAddr);
  461.             //если данных меньше чем надо, возвращаем ошибку
  462.             if(vSize<sizeof(PortState))
  463.               return false;
  464.             //Эта структура используется для обмена данными по одному порту
  465.             PortState RXVals;
  466.             //указатель типа байт ссылается на структуру
  467.             uint8_t* pRXVals = (uint8_t*)&RXVals;
  468.             //последовательно примем все байты данных
  469.             for (byte i=0; i < vSize; i++)
  470.             {
  471.               *pRXVals++ = buf[i];
  472.             }
  473.             //проверяем номер порта, не должен быть больше чем у нас портов
  474.             if(RXVals.Num > this->PortCount || RXVals.Num < 0)
  475.               return false;
  476.              
  477.             //сравниваем данные что были и что получили и если установлен обработчик события
  478.             if(this->Port[RXVals.Num]->Value !=RXVals.Value && this->Port[RXVals.Num]->OnChangeHandler)
  479.               //если значение изменилось то вызываем функцию которую кто-то навесил
  480.               this->Port[RXVals.Num]->OnChangeHandler(RXVals.Num, RXVals.Value, RXVals.TrigType);
  481.            
  482.             //данные получены, пишем в состояние порта
  483.             this->Port[RXVals.Num]->Value = RXVals.Value;
  484.             break;
  485.           }
  486.           //прилетело состояние всех портов
  487.           case EXTDEV_FUNC_GETALL:
  488.           {
  489.               Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_GETALL");
  490.               Serial.println(vAddr);
  491.             //массив для данных о портах
  492.             uint8_t RXVals[17];
  493.             //если данных меньше чем надо, возвращаем ошибку
  494.             if(vSize<sizeof(RXVals))
  495.               return false;
  496.             //Эта структура используется для обмена данными по одному порту
  497.             //PortsStateAll RXVals; !у нас массивом захуярено
  498.          
  499.             //указатель типа байт ссылается на структуру
  500.             uint8_t* pRXVals = (uint8_t*)&RXVals;
  501.             //последовательно примем все байты данных
  502.             for (byte i=0; i < vSize; i++)
  503.             {
  504.               *pRXVals++ = buf[i];
  505.             }
  506.          
  507.             //данные получены, переберем все порты в пакете данных
  508.             for(byte i=0; i < 17; i++)
  509.             {
  510.               //номера портов ввода начинаются с четырех
  511.               byte currNum = i+4;
  512.               //сравниваем данные что были и что получили и если установлен обработчик события
  513.               if(this->Port[currNum]->Value !=RXVals[i] && this->Port[currNum]->OnChangeHandler)
  514.                 //если значение изменилось то вызываем функцию которую кто-то навесил
  515.                 this->Port[currNum]->OnChangeHandler(currNum, RXVals[i], EXTDEV_TRIGOFF);
  516.                
  517.               //пишем в состояние порта актуальное значение
  518.               this->Port[currNum]->Value = RXVals[i];
  519.             }
  520.             break;
  521.           }
  522.           //прилетело событие чтения ключа iButton
  523.           case EXTDEV_FUNC_KEYREAD:
  524.           {
  525.               Serial.print("cExtensionDevice10::onRecieve: EXTDEV_FUNC_KEYREAD ");
  526.               Serial.println(vAddr);
  527.             //если данных меньше чем надо, возвращаем ошибку
  528.             if(vSize<8)
  529.               return false;
  530.             //передаем массив функции, которая обрабатывает обнаруженные ключи
  531.             this->KeyReadHandler(buf);
  532.             break;
  533.           }
  534.         }
  535.         //если все нормально, вернем true
  536.         return true;
  537.     }
  538.    
  539. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  540. //cExtensionMaster
  541. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542.  
  543.     //конструктор класса, передаем указатель на последовательный порт
  544.     //и назначаем переменной объекта адрес этого порта
  545.  
  546.    // void cExtensionMaster::cExtension();
  547.     cExtensionMaster::cExtensionMaster(Stream* _s): serialPort(_s){}
  548.    
  549.    
  550.    
  551.     //тут отрабатываем прием сообщений передаем обработку в объект устройства, пусть оно разбирается что к чему
  552.     void cExtensionMaster::process()
  553.     {
  554.       //запилим буфер на 300 байт - максимальный размер сообщения, которое может прилететь
  555.       char buff[300];
  556.       int bytes=0;
  557.       if (serialPort->available())
  558.       {
  559.         //создаем в памяти заголовок
  560.         sHeader Header;
  561.         sHeader * HeaderPtr = &Header;
  562.         //получим данные с последовательного порта в буфер все что есть
  563.         //bytes=serialPort->readBytes(buff,20);
  564.  
  565.         while(serialPort->available())
  566.         {
  567.           char b=(char) serialPort->peek();
  568.           //если не нашли стартовую последовательность
  569.           if(b!=0xBB)
  570.           {//стираем байт за байтом из буфера
  571.             buff[bytes] = (char) serialPort->read();
  572.           }
  573.           else
  574.           {//нашли буквы BB, значит нашли заголовок
  575.             //получим из буфера заголовок целиком
  576.             serialPort->readBytes((char*)HeaderPtr, sizeof(sHeader)) == sizeof(sHeader);
  577.            
  578.             // PrintHeader("Header get",Header);
  579.              break;          
  580.           }
  581.    
  582.         }
  583.                      
  584. //        //выделим из буфера заголовок и данные
  585. //        //!!Тут сразу можно проверить на наличие правильного стартового слова
  586. //        uint8_t* ptr28 = (uint8_t* )&Header;
  587. //        //если данных недостаточно хотя бы на хеадер, бросаем затею
  588. //          Serial.print("Bytes: ");
  589. //          Serial.println(bytes);
  590. //        if(bytes < sizeof(Header))
  591. //          return;
  592. //        //переписываем хеадер в структуру
  593. //        for(byte i=0; i<sizeof(Header);i++)
  594. //        {
  595. //          *ptr28=(uint8_t)buff[i];
  596. //          ptr28++;
  597. //        }
  598. //        //тут наверное нужно определить целостность данных, пока не до этого
  599.  
  600.         PrintHeader("Process",Header);
  601.         char Data[Header.Size];
  602.         if(Header.Size>0)
  603.         {
  604.           //В хеадере хранится размер данных,
  605.           //char * DataPtr = &Data;
  606.           //получим из буфера остаток данных
  607.           serialPort->readBytes(Data, sizeof(Data)) == sizeof(Data);
  608.         }
  609.        
  610.         //вырезаем из буфера остаток данных
  611.         //for(byte i=sizeof(Header); i<sizeof(Header)+Header.Size;i++)
  612.         //  Data[i-sizeof(Header)]=buff[i];
  613.  
  614.         //Посмотрим что в пакетах, может это нам нужно для работы
  615.         //если пакет предназначен для центрального контроллера и при этом не исходит от него
  616.         //(кстати сквозное прохождение пакета можно рассматривать как успешную доставку)
  617.         if(Header.Dst==0xFF && Header.Src !=0xFF)
  618.         {
  619.           //обслуживание discovery пакетов
  620.           if(Header.Func==0x00)
  621.           {
  622.             //если устройство типа 0х10
  623.             if(Header.Type==0x10)
  624.             {
  625.               Serial.print("Dev10Count: ");
  626.               Serial.println(Dev10Count);
  627.               Serial.print("Header.Src: ");
  628.               Serial.println(Header.Src);
  629.               //проверим превышение количества устройств типа 10.
  630.               if(Dev10Count < EXTDEV_TYPE_10_MAXCOUNT)
  631.               //создаем экземпляр объекта устройства типа 10 и передаем указатель на этот объект для правильной работы
  632.               //cExtensionDevice10 * ptrdev = new cExtensionDevice10(Header.Src,this);
  633.               //cExtensionDevice10 * ptrdev = &dev;
  634.               //this->Dev10[Dev10Count] = ptrdev;
  635.               this->Dev10[Dev10Count] = new cExtensionDevice10(Header.Src,this);
  636.                     Serial.println("####### ++++++ #######");
  637.               if(this->Dev10[Dev10Count]==NULL)
  638.                     Serial.println("####### NULLNULL #######");
  639.            
  640.               Dev10Count++;
  641.               Serial.println("####### Header.Type==0x10 #######");
  642.             }
  643.             if(Header.Type!=0x10)
  644.             {
  645.               //заглушка для устройств других типов
  646.             }
  647.             //вызовем обработчик функции обнаружения устроств (зачем?)
  648.             //RecieveHandler(Header);
  649.           }
  650.           //передаем обработку пакетов устройства типа 10 в соответствующий метод
  651.           //попутно проверим чтоб диапазон адреса не выходил за максимальное количество устройств этого типа на шине
  652.           if(Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT)
  653.           {
  654.               Serial.print("Header.Src: ");
  655.               Serial.println(Header.Src);
  656.             this->Dev10[Header.Src]->onRecieve(Header.Src, Header.Type, Header.Func, Header.Size, Data);
  657.               Serial.println("####### Header.Type==0x10 && Header.Src < EXTDEV_TYPE_10_MAXCOUNT #######");
  658.           }
  659.         }
  660.         //передаем полученный пакет в обработчик девайса с номером порта
  661.        
  662.              
  663.       //Serial.println("Handler... ");
  664.  
  665.        //   ;
  666.       }
  667.     }  
  668.    
  669.     //передача сформированного пакета данных
  670.     //параметры: адрес, тип устройства, функция,длинна данных, данные
  671.     void cExtensionMaster::transmit(byte vAddr, byte vType, byte vFunc, byte vSize, uint8_t *buf)
  672.     {
  673.       //инкремент номера транзакции
  674.       this->Transaction++;
  675.       //подготовим заголовок
  676.       sHeader Header;
  677.       //указатель на заголовок
  678.       sHeader * pHeader  = &Header;
  679.       //заполняем поля заголовка
  680.       Header.Src=0xFF;
  681.       Header.Dst=vAddr;
  682.       Header.Type=vType;
  683.       Header.Func=vFunc;
  684.       Header.Size=vSize;
  685.       Header.Trans=Transaction;
  686.       Header.CRC = 0x0000; //на всякий случай ;)
  687.       //Header.Data = buf;
  688.  
  689.       //сериализуем заголовок
  690.       const uint8_t * ptr = (const uint8_t *) &Header;
  691.       //буфер размером со структуру плюс размер буфера
  692.       uint8_t HeaderBuf[sizeof(Header)+vSize];
  693.       //записываем все байты в массив буфера
  694.       for(int i=1;i<sizeof(Header);i++)
  695.       {
  696.         HeaderBuf[i]=*ptr++;
  697.         //Serial.print(*ptr,HEX);
  698.       }
  699.       //дописываем данные в пакет
  700.       for(int i=sizeof(Header);i<sizeof(Header)+vSize;i++)
  701.       {
  702.         HeaderBuf[i]=*buf++;
  703.         //Serial.print(*ptr,HEX);
  704.       }
  705.       //посчитаем и запишем контрольную сумму
  706.       //!!!! нужно переделать, неверно это. Отправлять будем буфер
  707.       Header.CRC = CRC16.ccitt(HeaderBuf, sizeof(HeaderBuf));
  708.       //отправляем пакет в порт
  709.       serialPort->write((const char*)HeaderBuf, sizeof(HeaderBuf));
  710.       PrintHeader("transmit",Header);
  711.     }
  712.    
  713.     //передача стандартного пакета с данными нулевой длинны. по сути только заголовок передаем
  714.     void cExtensionMaster::transmitStd(sHeader Header)
  715.     {
  716.       unsigned int crc=0;
  717.       //инкремент номера транзакции
  718.       this->Transaction++;
  719.       Header.Trans=this->Transaction;
  720.       sHeader* HeaderPtr = &Header;
  721.       //посчитаем контрольную сумму
  722.       Header.CRC=0; //на всякий случай обнулим ее
  723.       //делаем указатель на переменную типа uint8_t для побайтового перевода в массив байтов
  724.       const uint8_t * ptr = (const uint8_t *) &Header;
  725.       //буфер размером со структуру
  726.       uint8_t buf[sizeof(Header)];
  727.       //записываем все байты в массив буфера
  728.       for(int i=1;i<sizeof(Header);i++)
  729.       {
  730.         buf[i]=*ptr++;
  731.         Serial.print(*ptr,HEX);
  732.       }
  733.       //считаем контрольную сумму
  734.       crc=CRC16.ccitt(buf, sizeof(buf));
  735.       //пишем получившуюся контрольную сумму в пакет
  736.       Header.CRC=crc;
  737.       //отправляем пакет в порт
  738.       serialPort->write((const char*)HeaderPtr, sizeof(sHeader));
  739.      
  740.       PrintHeader("transmitStd",Header);
  741.     }
  742.  
  743.    
  744.     //запустить процедуру обнаружения устройств
  745.     //передаем в нее функцию в которая будет вызвана когда что-то найдено
  746.     //в нее будет передано количество обнаруженных устройств.
  747.     void cExtensionMaster::discovery(PHandlerByte h)
  748.     {
  749.       Serial.println("Discovery");
  750.       //ставим обработчик
  751.       if(!h)
  752.         return;
  753.       //в переменной объекта запоминаем указатель на обработчик события обнаружения устройств
  754.       DiscoveryHandler = (PHandlerByte)h;
  755.       //переменные для работы
  756.       //увеличиваем номер транзакции на единицу
  757.       transaction++;
  758.       //сформируем пакет для транзакции, формируем из хеадера
  759.       sHeader Header;
  760.       Header.Start=MAGICHEAD; //магическое начало пакета
  761.       Header.Src=0xFF; //запрос от контроллера
  762.       Header.Dst=0xFF; //широковещательный запрос на все устройства
  763.       Header.Type=0x00; //код функции 0х00 - определение устройств
  764.       Header.Func=0x00;
  765.       Header.Size=0x00;
  766.       Header.Value=0x00000000;
  767.       Header.Trans=transaction;
  768.       Header.CRC=0x0000; //контрольная сумма считается в передающем блоке
  769.       //передаем пакет. Транзакции пока не учитываем, очереди команд нету. Надеемся что все будет хорошо
  770.       transmitStd(Header);
  771.     }
  772.  
  773. void cExtensionMaster::PrintHeader(String title, sHeader Header)
  774. {
  775.  
  776.     Serial.println();
  777.     Serial.println(title);
  778.     Serial.print("Start: ");
  779.     Serial.println(Header.Start, HEX);
  780.     Serial.print("Src: ");
  781.     Serial.println(Header.Src, HEX);
  782.     Serial.print("Dst: ");
  783.     Serial.println(Header.Dst, HEX);
  784.     Serial.print("Type: ");
  785.     Serial.println(Header.Type, HEX);
  786.     Serial.print("Func: ");
  787.     Serial.println(Header.Func, HEX);
  788.     Serial.print("Size: ");
  789.     Serial.println(Header.Size, HEX);
  790.     Serial.print("Trans: ");
  791.     Serial.println(Header.Trans);
  792.     Serial.print("CRC: ");
  793.     Serial.println(Header.CRC, HEX);  
  794.     Serial.print("Value: ");
  795.     Serial.println(Header.Value, HEX);
  796. }
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.  
  810. /////////////////////////////////////////////////////////////////////////////
  811. //Это откуда вызывается код
  812.  
  813. #include <SoftwareSerial.h>
  814. //https://github.com/FrankBoesing/FastCRC
  815. //#include <FastCRC.h>
  816. #include <Ticker.h>
  817. #include "cExtensionMaster.h"
  818.  
  819. #define STX 13  //scl
  820. #define SRX 12 //D6
  821. //rxPin, txPin, inverse_logic, buffer size
  822.  
  823. SoftwareSerial extPort(SRX, STX, false, 128);
  824. Ticker Send;
  825.  
  826. //передаем указатель на поток
  827. cExtensionMaster device(&extPort);
  828.  
  829. //функция печати содержимого пакета
  830.  
  831. void RecievePacket(sHeader Header)
  832. {
  833.    device.PrintHeader("RecievePacket",Header);
  834. }
  835. void OnRecievePacket(byte count)
  836. {
  837.     Serial.print("OnRecievePacket: ");
  838.     Serial.println(count);  
  839. }
  840. void SendPacket()
  841. {
  842. // device.send();
  843.   device.discovery(OnRecievePacket);
  844. }
  845. void setup() {
  846.  
  847.   Serial.begin(115200);
  848.   extPort.begin(115200);    //Initialize software serial with baudrate of 115200
  849. //  device.setup(RecievePacket,pack);
  850.  
  851.   //назначим отправку пакетов каждые 100 мсек
  852.   Send.attach_ms(7000, SendPacket);
  853. }
  854.  
  855.  
  856. void loop()
  857. {
  858.   device.process();
  859. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement