/* * modbus.c * * Created on: 28 пїЅпїЅпїЅ 2018 пїЅ. * Author: Shukov */ // Includes -------------------------------------------------------------------- #include "modbus.h" #include "my.h" #include "usart.h" #include "main.h" // External function ----------------------------------------------------------- // External variables ---------------------------------------------------------- extern __IO UserData_TypeDef currentData; #define LO(x) ((uint8_t) ((x) & 0xff)) #define HI(x) ((uint8_t) (((x) >> 8) & 0xff)) //extern __IO uint32_t STATUS; // Global variables ------------------------------------------------------------ uint8_t iobuf[256]; uint8_t tx[256]; uint8_t timeout; uint16_t lastbyte; //последний байт в сообщении uint16_t lastbyteToSend; //последний байт на отправку uint16_t iolen = 0; // счетчик для буфера uint8_t ioa; //ваще не шарю нахуя bool sendreq = false; //влаг готовности к отправке bool setbaud = false; //при смене скорости условие для переинициализации уарта extern char pString[16]; // палки шишки - без этого не копирует floatToAscII extern uint8_t buff[16]; extern int reload_flag; //флаг перегрузки bool send = true; __IO uint16_t delayREDE; __IO bool needSave = false; __IO bool needParam = false; __IO bool needReset = false; __IO bool POVERKA = false; __IO bool needPoverka = false; __IO bool needFactory = false; const int8_t inversely[] = {3, 1, -1,-3}; void StartTransfer(void) //todo жесько отключаю прерывания это неправильно { int a = delayREDE; while(a) { a--; a++; a--; a++; a--; } HAL_GPIO_WritePin(USART1_RE_GPIO_Port, USART1_RE_Pin, GPIO_PIN_SET); //todo это нужно только п//это ужасная вещь - но обеспечивает постоянный прием //HAL_UART_Transmit_IT(&huart1, tx, lastbyte); __disable_irq(); HAL_UART_Transmit(&huart1, tx, lastbyteToSend,100);// возможно не отправит из за того что приемник в прерывании memset(tx,0,sizeof(tx)); __enable_irq(); HAL_GPIO_WritePin(USART1_RE_GPIO_Port, USART1_RE_Pin, GPIO_PIN_RESET); Transfer_Complete(); } void strtOut(uint16_t n) { uint16_t crc; if(tx[0]) // если на отправку что то есть то { lastbyteToSend = n + 2; // добавляем 2 байта под CRC crc = Crc16_TX(n); tx[n] = LO(crc); tx[n + 1] = HI(crc); //todo: Внимание костыль & 0xFF!!!! // Добавляем контрольную сумму sendreq = true; //Устанавливаем флаг требования отправки } iolen = 0; // сбрасываем длинну сообщения } uint16_t Crc16(uint16_t len) { uint16_t i; uint16_t crc = 0xFFFF; for(i = 0; i < len; i++) { crc = (crc >> 8) ^ Crc16Table[(crc & 0xFF) ^ iobuf[i]]; } return crc; } uint16_t Crc16_TX(uint16_t len) { uint16_t i; uint16_t crc = 0xFFFF; for(i = 0; i < len; i++) { crc = (crc >> 8) ^ Crc16Table[(crc & 0xFF) ^ tx[i]]; } return crc; } //----------------------------------------- // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ-пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ //----------------------------------------- void SetBaudRate(){ //todo: сделать установку скорости timeout = time35[currentData.BAUD]; delayREDE = sendtime[currentData.BAUD]; MX_USART1_UART_DeInit(); MX_USART1_UART_Init(); } //float32_t tmpf; uint16_t hp16; void Transfer_Complete(void) { __IO uint16_t a; a = delayREDE; while(a) { a--; a++; a--; a++; a--; // какая то задержка пусть будет } if(setbaud) // наверное нужно для применения новых настроек скорости { setbaud = 0; needSave = true; SetBaudRate(); } //__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC); HAL_GPIO_WritePin(USART1_RE_GPIO_Port, USART1_RE_Pin, GPIO_PIN_RESET); } void Receive_Complete(void){ //я сейчас попробую раскоментировать тебя // не забывай что команды подаются little endian формате. /// перенес в надежде на чудо uint16_t j; uint8_t *pch; usshort crc, addr, regs; usfloat f; uint8_t tmp, tmp1; /// timeout = time35[currentData.BAUD]; // какие то мутные таймауты от скорости всегда двойки((( iobuf[iolen++] = buff[0]; //iobuf[iolen++] = (uint8_t) (USART1->DR & 0xff); // прибывший байт принимаем в из регистра в буфер if((iobuf[0] == currentData.OWN) || (!iobuf[0])) //если нулевая посылка совпадает с адресом устройства или не равен себе { if(iolen > 1) { if(iolen == 2) // если длинна сообщения 2 { switch(iobuf[1]) // смотрим на команды { case 0x03: //команда на чтение lastbyte = 7; //последний байт в сообщении будет 7 break; case 0x10: lastbyte = 6; // если на запись то 6 break; default: lastbyte = 3; // если не то не то то 3 tx[0] = iobuf[0]; //в отправку заряжаем принятый адрес tx[1] = (iobuf[1] | 0x80); //берем прешедшую команду и обвосьмериваем - помечаем как ошибку tx[2] = 0x01; // принятый код функции не может быть обработан strtOut(3); // на отправку break; } } if(iolen > lastbyte) //если длинна принятой строки больше чем последний байт { switch(iobuf[1]) //смотрим на командц { case 0x03: // если команда на чтение iolen = 0; // ставим счетчик буфера на 0 crc.ch[0] = iobuf[6]; // берем из буфера CRC crc.ch[1] = iobuf[7]; if(Crc16(6) == crc.sh) // Проверяем её { addr.ch[1] = iobuf[2]; //адрес первого регистра hi addr.ch[0] = iobuf[3]; //lo regs.ch[1] = iobuf[4]; //колличество регистров hi regs.ch[0] = iobuf[5]; //колличесво регистров lo switch(addr.sh) // здесь union { case 5001: // 5001 //тип заряда ACP= case 5002: // 5002 //фильтр верхних частот case 5003: // 5003 //нижних case 5004: //IKU 5004 //Коэф усиления case 5005: //IKE 5005 // Legacy a141 case 5006: //IKD 5006 // Legacy a141 case 5007: //IKS 5007 // Legacy a141 case 5008: //IPZ 5008 // признак плав земли case 5009: //OPZ 5009 // Legacy a141 case 5010: //UNIT 5010 // Значения case 5011: //OVERLOAD 5011 // Использую для передачи перегрузки if(regs.ch[0] > (5012 - addr.sh)) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else { tx[0] = iobuf[0]; tx[1] = iobuf[1]; tx[2] = regs.ch[0] << 1; pch = (uint8_t *) ¤tData.IIN + ((addr.sh - 5001) << 1); for(j = 0; j < tx[2]; j++) tx[j + 3] = *(pch + (j ^ 1)); strtOut(3 + tx[2]); } break; case 7004: // Sens case 7502: tmp = 2; tx[0] = iobuf[0]; tx[1] = iobuf[1]; tx[2] = regs.ch[0] << 2; if(addr.sh == 7004) { tmp <<= 1; tx[2] >>= 1; } if(regs.ch[0] > tmp) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else { f.fl = currentData.SENS; tx[3] = f.ch[3]; tx[4] = f.ch[2]; tx[5] = f.ch[1]; tx[6] = f.ch[0]; strtOut(3 + tx[2]); } break; default: tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x02; strtOut(3); break; } } break; case 0x10: // //запрос на запись addr.ch[1] = iobuf[2]; addr.ch[0] = iobuf[3]; regs.ch[1] = iobuf[4]; regs.ch[0] = iobuf[5]; switch(addr.sh) // Запись pardata { case 4001: // 4001 //тип заряда ACP= case 4002: // 4002 //фильтр верхних частот case 4003: // 4003 //нижних { if((regs.ch[0] > (4004 - addr.sh)) || (iobuf[6] != (regs.ch[0] << 1))) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else { j = 8 + iobuf[6]; if(iolen > j) { iolen = 0; crc.ch[0] = iobuf[j - 1]; crc.ch[1] = iobuf[j]; if(crc.sh == Crc16(j - 1)) { UserData_TypeDef recivedData =currentData; pch = (uint8_t *) &recivedData.OWN + ((addr.sh - 4001) << 1); for(j = 0; j < iobuf[6]; j++) *(pch + (j ^ 1)) = iobuf[j + 7]; if((recivedData.OWN > 247) || (recivedData.BAUD > 9) || (recivedData.INFB > 2)) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else //если значения корректны { currentData=recivedData; //Пишем значения в рабочую структуру if(!iobuf[0]) //если широковешательная то не отвечаем { setbaud = false; // снимаем флаг следующей смены needSave = true; // ставим флаг надобности сохранения SetBaudRate(); // устанавливаем свойства связи } else { setbaud = true; // по колбеку ТХ переинициализируем УАРТ for(j = 0; j < 6; j++) { tx[j] = iobuf[j]; } strtOut(6); } } } } } } break; case 5001: // 5001 //тип заряда ACP= case 5002: // 5002 //фильтр верхних частот case 5003: // 5003 //нижних case 5004: //IKU 5004 //Коэф усиления case 5005: //IKE 5005 // Legacy a141 case 5006: //IKD 5006 // Legacy a141 case 5007: //IKS 5007 // Legacy a141 case 5008: //IPZ 5008 // признак плав земли case 5009: //OPZ 5009 // Legacy a141 case 5010: //UNIT 5010 // Значения if((regs.ch[0] > (5011 - addr.sh)) || (iobuf[6] != (regs.ch[0] << 1))) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else { j = 8 + iobuf[6]; if(iolen > j) { iolen = 0; crc.ch[0] = iobuf[j - 1]; crc.ch[1] = iobuf[j]; if(crc.sh == Crc16(j - 1)) { UserData_TypeDef recivedData =currentData; // должно работать как копирование pch = (uint8_t *) &recivedData.IIN + ((addr.sh - 5001) << 1); for(j = 0; j < iobuf[6]; j++) *(pch + (j ^ 1)) = iobuf[j + 7]; if((recivedData.IIN > 0) || (recivedData.IKU > Ku1000) || (recivedData.IFV > Hp10) || (recivedData.IFN > Lp100000) || (recivedData.UNIT > H) || (recivedData.IPZ > 1)|| (recivedData.OVERLOAD > 1)) { tx[0] = iobuf[0]; tx[1] = (iobuf[1] | 0x80); tx[2] = 0x03; strtOut(3); } else { currentData=recivedData; // значения правильные копируем в рабочую структуру needSave = true; if(iobuf[0]) //если адрес не широковещательный отвечаем { for(j = 0; j < 6; j++) { tx[j] = iobuf[j]; } strtOut(6); } } } } } break; case 7004: // Запись Sens case 7502: tmp = 2; tmp1 = 2; if(addr.sh == 7004) { tmp <<= 1; tmp1 = 1; } if((regs.ch[0] > tmp) || (iobuf[6] != (regs.ch[0] << tmp1))) { tx[0] = iobuf[0]; tx[1] |= 0x80; //модификация кода функции на ошибку tx[2] = 0x03; //Адрес данных указанный в запросе не доступен strtOut(3); } else { j = 8 + iobuf[6]; if(iolen > j) { crc.ch[0] = iobuf[j - 1]; crc.ch[1] = iobuf[j]; if(crc.sh == Crc16(j - 1)) { if(iobuf[6] == 4) { for(j = 0; j < 4; j++) f.ch[3 - j] = iobuf[7 + j]; //ввести проверку и прочую чепуху currentData.SENS = f.fl; if(currentData.SENS==1000) { currentData.IK0=1; currentData.IK1=0; currentData.IK2=0; currentData.IK3=0; currentData.IK4='~'; currentData.IK5=0; } else if(currentData.SENS<1000&¤tData.SENS>=100) { char str[20] = {0}; strcpy(str, FloatToASCII(currentData.SENS, -2)); currentData.IK0=str[0]-48; currentData.IK1=str[1]-48; currentData.IK2=str[2]-48; currentData.IK3='~';//str[3]; currentData.IK4=str[4]-48; currentData.IK5=str[5]-48; } else if(currentData.SENS<100&¤tData.SENS>=10) { char str[20] = {0}; strcpy(str, FloatToASCII(currentData.SENS, -3)); currentData.IK0=str[0]-48; currentData.IK1=str[1]-48; currentData.IK2=str[2]; currentData.IK3=str[3]-48; currentData.IK4=str[4]-48; currentData.IK5=str[5]-48; } else //if(currentData.SENS<10); { char str[20] = {0}; strcpy(str, FloatToASCII(currentData.SENS, -4)); currentData.IK0=str[0]-48; currentData.IK1=str[1]; currentData.IK2=str[2]-48; currentData.IK3=str[3]-48; currentData.IK4=str[4]-48; currentData.IK5=str[5]-48; } needSave = true; strtOut(6); } else if(iobuf[6] == 8) { for(j = 0; j < 4; j++) f.ch[3 - j] = iobuf[7 + j]; currentData.ACCEL = f.fl; needSave = true; strtOut(6); } else { tx[0] = iobuf[0]; tx[1] |= 0x80; //модификация кода функции на ошибку tx[2] = 0x03; //Адрес данных указанный в запросе не доступен strtOut(3); } } } } break; default://Команда неопознана tx[0] = iobuf[0]; tx[1] |= 0x80; //модификация кода функции на ошибку tx[2] = 0x02; //Адрес данных указанный в запросе не доступен strtOut(3); break; } break; } } } } }