A1210/Core/Src/modbus.c

547 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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 *) &currentData.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&&currentData.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&&currentData.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;
}
}
}
}
}