/*
Пример программы для подключения к облачному комплексу DispSky
При возникновении вопросов по работе программы и всего комплекса в целом, вы можете обратиться в службу технической поддержки: 
http://dispsky.ru/podderzhka/tehpodderzhka/
*/

#include <Ethernet.h>

#define HEART_BEAT_TIME 30

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

//IPAddress serverDispSky { 192, 168, 34, 220 };
char serverDispSky [] = "s1.dispsky.ru"; //Адрес сервера DispSky
const int port = 5010;                   //Порт сервера DispSky
char* heartbeat = "ARDUINO_0001"; //Код для подключения, необходимо придумать свой уникальный и указать такой же в личном кабинете DispSky
uint8_t bufferModbus[256];
int lenBufIn, lenBufOut;
unsigned long timerHeartBeat, timerSend;

/*
 Массивы регистров Modbus, установите необходимое количество 
 Обратите внимание, что адресация в личном кабинете DispSky будет отличаться на + 1
*/
unsigned int ModbusHR [130];  //Holding Register 

//В случае, если вы используете массивы регистров Input Register, Input Status и Coil Status уберите комментирование следующих строк:
/*
unsigned int ModbusIR [130];  //Input Register 
uint8_t ModbusCS [200];       //Input Status
uint8_t ModbusIS [200];       //Coil Status
*/

EthernetClient DispSkyClient;

void setup() {
  
    Ethernet.begin(mac);
 
    if(DispSkyClient.connect(serverDispSky, port)) DispSkyClient.write(heartbeat, 12);
   
    start_modbus();
    
}

void loop() {

    CloudDispSky();
      
}

void start_modbus() //Первоначальные установки регистров Modbus, используется для примера и проверки
{
    ModbusHR[5] = 1212;
    ModbusHR[6] = 3434;
    ModbusHR[18] = 5656;
    ModbusHR[55] = 7878;
    ModbusHR[56] = 9090;
    ModbusHR[100] = 11111;
    ModbusHR[101] = 22222;
    ModbusHR[102] = 33333;
    ModbusHR[103] = 44444;
    
//В случае, если вы используете массивы регистров Input Register, Input Status и Coil Status уберите комментирование следующих строк:    
/* 
    ModbusCS[0] = 1;
    ModbusCS[1] = 0;
    ModbusCS[2] = 1;
    ModbusCS[5] = 1;
    ModbusCS[19] = 1;
    ModbusCS[25] = 1;
    ModbusCS[140] = 1;
    ModbusCS[142] = 1;
    ModbusCS[146] = 1;
    
    ModbusIS[22] = 1;  
    ModbusIS[23] = 1;
    ModbusIS[47] = 1;
    ModbusIS[54] = 1;
    ModbusIS[99] = 1;
    ModbusIS[123] = 1;
    ModbusIS[140] = 1;
    ModbusIS[142] = 1;
    ModbusIS[163] = 1;         
        
    ModbusIR[17] = 2257;
    ModbusIR[18] = 3780;
    ModbusIR[19] = 421;
    ModbusIR[63] = 7528;
    ModbusIR[77] = 5282;
    ModbusIR[112] = 9321;
    ModbusIR[113] = 100;
    ModbusIR[114] = 4216;
    ModbusIR[115] = 12345; 
*/
}

void CloudDispSky()
{     
    unsigned int numberOfRegisters;  
    unsigned int firstRegisterAddress;
    unsigned int counterRegisters;
    unsigned int numberOfFunction;
    unsigned int lenghtData; 
    unsigned int countOfByte; 
    unsigned int valueData;
    
    lenBufIn = DispSkyClient.available();
    
    if (millis() - timerHeartBeat > (unsigned long) HEART_BEAT_TIME * 1000 ) {
        timerHeartBeat = millis();
        DispSkyClient.stop();
        DispSkyClient.connect(serverDispSky, port);
        DispSkyClient.write(heartbeat, 12);
    }

    if (lenBufOut > 0 && millis() - timerSend > 100) 
    {
        DispSkyClient.write(bufferModbus, lenBufOut);
        lenBufOut = 0;     
    }

    if (lenBufIn > 0) 
    {   
        timerHeartBeat = millis();
        timerSend = millis();      
        DispSkyClient.read(bufferModbus, lenBufIn);
        numberOfFunction = bufferModbus[7];
        numberOfRegisters = (bufferModbus[10]<<8)|bufferModbus[11];
        firstRegisterAddress = (bufferModbus[8]<<8)|bufferModbus[9];
        switch (numberOfFunction) 
        {
           case 0x03:
                lenghtData = numberOfRegisters*2 + 3;
                bufferModbus[4] = (lenghtData>>8) & 0xFF;
                bufferModbus[5] = lenghtData & 0xFF;
                counterRegisters = 9;
                for (int i = firstRegisterAddress; i <= firstRegisterAddress + numberOfRegisters - 1; i++) 
                { 
                    bufferModbus[counterRegisters] = (ModbusHR[i]>>8) & 0xFF;
                    bufferModbus[counterRegisters + 1] = ModbusHR[i] & 0xFF;
                    counterRegisters += 2;
                }
                bufferModbus[8] = numberOfRegisters*2;
                lenBufOut = numberOfRegisters*2 + 9;
            break;
            case 0x10:  
                for (int i = 13; i < numberOfRegisters*2 + 13; i = i + 2) 
                { 
                    valueData = (bufferModbus[i]<<8)|bufferModbus[i + 1];
                    ModbusHR[firstRegisterAddress] = valueData;
                    firstRegisterAddress++;
                }
                bufferModbus[5] = 6;
                lenBufOut = 12;
            break;
            
//В случае, если вы используете массивы регистров Input Register, Input Status и Coil Status уберите комментирование следующих строк:
/*
            case 0x01: 
                countOfByte = (numberOfRegisters - 1)/8 + 1;  
                lenghtData = 4 + (numberOfRegisters - 1)/8;
                bufferModbus[4] = (lenghtData>>8) & 0xFF;
                bufferModbus[5] = lenghtData & 0xFF;
                bufferModbus[8] = countOfByte;
                counterRegisters = 9;
                bufferModbus[9] = 0;
                for (int i = 0; i < numberOfRegisters; i++) 
                { 
                    bufferModbus[counterRegisters] |=  ((ModbusCS[i+firstRegisterAddress]&1)<<(i%8));
                    if((i+1)%8 == 0 && i != numberOfRegisters - 1) 
                    {
                        counterRegisters++;
                        bufferModbus[counterRegisters] = 0;
                    }   
                }
                lenBufOut = counterRegisters + 1;
            break;
            case 0x02: 
                countOfByte = (numberOfRegisters - 1)/8 + 1;  
                lenghtData = 4 + (numberOfRegisters - 1)/8;
                bufferModbus[4] = (lenghtData>>8) & 0xFF;
                bufferModbus[5] = lenghtData & 0xFF;
                bufferModbus[8] = countOfByte;
                counterRegisters = 9;
                bufferModbus[9] = 0;
                for (int i = 0; i < numberOfRegisters; i++) 
                { 
                    bufferModbus[counterRegisters] |=  ((ModbusIS[i+firstRegisterAddress]&1)<<(i%8));
                    if((i+1)%8 == 0 && i != numberOfRegisters - 1) 
                    {
                        counterRegisters++;
                        bufferModbus[counterRegisters] = 0;
                    }   
                }
                lenBufOut = counterRegisters + 1;
            break;
            case 0x04:
                lenghtData = numberOfRegisters*2 + 3;
                bufferModbus[4] = (lenghtData>>8) & 0xFF;
                bufferModbus[5] = lenghtData & 0xFF;
                counterRegisters = 9;
                for (int i = firstRegisterAddress; i <= firstRegisterAddress + numberOfRegisters - 1; i++) 
                { 
                    bufferModbus[counterRegisters] = (ModbusIR[i]>>8) & 0xFF;
                    bufferModbus[counterRegisters + 1] = ModbusIR[i] & 0xFF;
                    counterRegisters += 2;
                }
                bufferModbus[8] = numberOfRegisters*2;
                lenBufOut = numberOfRegisters*2 + 9;   
            break;
            case 0x05: 
                valueData = bufferModbus[10];
                ModbusCS[firstRegisterAddress] = valueData & 1;
                lenBufOut = 12;
            break;
*/            
        } 
    }                
}
