<< Click to Display Table of Contents >> Navigation: Modbus Universal MasterOPC Server > Руководство по языку Lua 5.1 > Библиотеки функций > Библиотека SERVER > Функции работы с портами |
server.SendAndReceiveDataByMask
Функции работы с портами могут использоваться в узлах типа COM и TCP.
Производит закрытие порта – закрывает соединение.
Совместно с функцией server.OpenConnection может использоваться для ручной реинициализации узла.
Функция должна находиться в устройстве или теге типа Program.
Пример
server.CloseConnection( );
Производит открытие порта – устанавливает соединение.
Совместно с функцией server.CloseConnection может использоваться для ручной реинициализации узла.
Функция должна находиться в устройстве или теге типа Program.
Пример
server.OpenConnection( );
Записывает в последовательный или TCP порт и принимает из порта данные согласно установкам узла.
Входные параметры: данные для передачи, длина данных в байтах, длина принимаемых данных. Также может быть 4, опциональный параметр - UDP сокет, на который нужно отправить данные. Этот параметр используется если функция применяется в режиме UDP Slave и необходимо отправить ответ после полученного ранее запроса.
Пример
err,buf,len,buftabl,s = server.SendAndReceiveData(srcbuf,srclen,dstlen)
err=TRUE при ошибке выполнения функции, buf – строка с принятыми данными (nil, если приема не было), len – длина buf, buftable - таблица принятых байт, s - сокет, с которого был получен ответ (для TCP - всегда 0).
Если длина принимаемых данных равна 0 , функция работает только на передачу.
После записи данных запускается таймаут ожидания приема. Если принят хотя бы один байт информации, запускается межсимвольный таймаут. Если межсимвольный таймаут закончился, и информации больше нет, функция завершает работу и передает на выход принятое количество байтов, иначе функция принимает то количество байтов, которое указано во входном параметре.
server.SendAndReceiveDataByMask
Посылает отформатированную последовательность байт в COM или TCP порт. В разделе Примеры есть несколько примеров реализации протоколов с использованием данной функции.
Входные аргументы:
1 – если число:
0 – без контрольной суммы;
1 – контрольная сумма DCON;
2 – контрольная сумма СRC16 (Modbus RTU).
3 – контрольная сумма LRC16 - при выборе данной функции происходит автоматическое формирование кадра Modbus ASCII. RTU байты конвертируются в символы ASCII, также добавляется символ "двоеточие" в начале пакета, контрольная сумма LRC и два символа окончания (CR и LF). Полученный от устройства пакет также конвертируется: контрольная сумма, символы окончания и двоеточие - отбрасываются, символы преобразуются в RTU фрейм. Таким образом при работе с Modbus ASCII формирование кадра происходит полностью идентично как и для Modbus RTU, а дальнейшее преобразование к правильном формату производится автоматически.
еcли символ или строка:
проверка принятой последовательности байтов на окончание этим символом или строкой. Для формирования строки из непечатаемых символов можно использовать функцию string.char;
Примечание. Контрольные суммы и символ окончания во входной буфер не передаются.
2 – количество элементов в исходной таблице масок форматирования - параметр 3 (если 0, функция работает только на прием, без передачи данных). Для определения длины можно использовать функцию table.maxn. Пример - table.maxn(sendmask).
3 – таблица масок форматирования;
4 – исходная таблица с отправляемыми данными. Количество элементов в отправляемой таблице должно быть равно количеству элементов в таблице масок форматирования.
5 – таблица масок принимаемых данных или nil;
6 – максимальное количество принимаемых байтов. Если количество принимаемых данных установлено равным 0 , то функция работает только на передачу.
Не обязательные параметры:
7 – строковое имя функции, которая будет вызвана перед отправкой запроса в прибор;
8 – строковое имя функции, которая будет вызвана после приема ответа из прибора;
Параметры 7 и 8 предназначены для вызова внешних функций обработки выходного и входного буфера. В качестве входного аргумента, вызываемый функции должны принимать таблицу байт, а также должны возвращать два параметра:
1 - количество сформированных байт, либо код ошибки - отрицательное число (кроме -1, так как это признак отсутствия ответа);
2 - обработанная таблица байт (например таблица с добавленной контрольной суммой).
Может применяться для вызова функций подсчета контрольной суммы (см. пример).
Формат маски выходных преобразований – String1:String2:String3, где String1 – формат данных, String2 – строка перестановки, String3 - количество передаваемых элементов. Форматы данных – string, byte, int16, uint16, int32, uint32, float, double. Форматы string и byte не требуют строки перестановки, для остальных форматов, ecли строка перестановки не введена, используется "10325476". Примеры формирования - "int16:10:4" (4 int16 с чередованием "старшим вперед"), "byte::2" (2 байта, чередование не используется).
Формат маски входных преобразований – String1:String2:String3, где String1 – формат данных, String2 – количество принимаемых чисел, String3 – строка перестановки байт (для форматов с префиксом s – количество байт для получения числа с указанным форматом). Форматы данных – string, byte, int16, uint16, int32, uint32, float, double, sint32, sdouble (форматы sint32 и sdouble требуют строки количества байт вместо строки перестановки байт).
Примечание. При задании маски типа string во входной таблице преобразований, следующие за ней маски форматирования игнорируются. Т.е., например, в маске ("byte", "int16:1:01","string","float:1:3210") маска "float:1:3210" будет проигнорирована, и байты данного элемента войдут в строку. Поэтому, если элементы типа string находятся в середине пакета, необходимо прочитать их как набор обычных байт, а затем преобразовать в строку с помощью функции string.char. Для таблицы масок выходных преобразований этого не требуется - преобразование ведется согласно маскам таблицы, не зависимо от типов данных масок.
Если маски преобразований не определены, то байты передаются из таблиц и принимаются в таблицы без преобразований.
Если маска входных преобразований исчерпана, а в приемном буфере еще есть байты, то оставшиеся байты преобразуются в одну символьную строку приемной таблицы.
Возвращаемые значения:
1 – ecли меньше 0 – код ошибки, если больше или равно 0 – количество принятых байтов;
2 – таблица, каждый элемент которой равен числу/строке в соответствии с маской преобразований или байту из приемного буфера (если маска преобразований не определена);
3 – количество элементов в таблице;
4 – строка, каждый символ которой равен байту из приемного буфера (независимо от использования маски). Данная строка необходима, если требуется произвести подсчет нестандартной контрольной суммы (первый входной параметр установлен равным 0) по каждому байту (см. пример 3). Если используется одна из стандартных контрольных сумм, то данный выходной параметр можно не использовать;
5 – количество принятых байт. Данный элемент необходим, если требуется знать количество принятых байт, например, для подсчета нестандартной контрольной суммы. Если используется одна из стандартных контрольных сумм, то данный выходной параметр можно не использовать.
Коды ошибок:
-1 – ошибка таймаута;
-11 – ошибка контрольной суммы или нет символа окончания;
-10 – мало байтов для контрольной суммы. При выборе варианта 3 (Modbus ASCII) - меньше 5 байт.
-12 – нет символов окончания CR и LF (для варианта 3 - Modbus ASCII).
Пример 1
Функция посылает строку байт в устройство MODBUS (считать 2 регистра с адреса 0):
01 03 00 00 00 02 C4 0B
принимает строку:
01 03 04 00 20 00 00 FB F9
и преобразует принятую строку в 2 числа int16.
--dest[1] - 1
--dest[2] - 3
--dest[3] - 4
--dest[4] – 32 регистр из адреса 0
--dest[4] – 0 регистр из адреса 1
local send={1,3,0,3};
local sendmask={"byte","byte","int16:10","int16:10"};
local dest={};
local destmask={"byte","byte","byte","int16:2:10"};
local err,len;
err,dest,len=server.SendAndReceiveDataByMask(2,4,sendmask,send,destmask,200);
if err<0 then
server.Message("err=",err);
else
server.Message("lenb=",err," lentabl=",len);
server.Message("dest[1]=",dest[1]," dest[2]=",dest[2]," dest[3]=",dest[3]);
server.Message("dest[4]=",dest[4]," dest[5]=",dest[5]);
end
Пример 2
Функции посылает запрос на I-7017:
#01\r
и получает значения каналов, представленные в символьном формате:
>+05.000+04.235+03.235+02.235+01.235+00.235+04.235+07.235\r
--dest[1] - '>'
--dest[2] - 5
--dest[3] - 4.235
--dest[9] - 7.237
--dest[10] - '\r'
local send={'#01\r'};
local sendmask={};
local dest={};
local destmask={"string:1","sdouble:8:7","byte"};
local err,len;
err,dest,len=server.SendAndReceiveDataByMask(1,1,nil,send,destmask,200);
if err<0 then
server.Message("err=",err);
else
server.Message("lenb=",err," lentabl=",len);
server.Message("dest[1]=",dest[1]," dest[2]=",dest[2]," dest[3]=",dest[3]);
end
Функция посылает в прибор Метакон-562 ( протокол Rnet ) запрос на чтение измеренного значения входа1. Детально пример разобран в отдельном разделе.
01 – адрес прибора;
00 – номер канала (нумерация идет с нуля);
01 – номер регистра измеренного значения;
00 – команда чтения;
CRC – контрольная сумма.
Ответ прибора:
01 – адрес прибора;
00 – номер канала;
01 – номер регистра;
00 – команда чтения;
TYP – поле типа данных;
DATA – данные. Принятое значение;
CRC – контрольная сумма.
Контрольная сумма считается по собственному алгоритму. При вызове функции server.SendAndReciveDataByMask также вызываются пользовательские функции SendCrc и GetCrc, которые обрабатывают входной и выходной буфер - вычисляют контрольную сумму, добавляют/убирают байт контрольной суммы.
Код:
--подсчет контрольной суммы
function CRCsum(Frame)
I,J=0; --Счетчики циклов
CRC=0; --Контрольная сумма
AUX,DAT=0; --Временные переменные
CRC = 255; --Инициализация контрольной суммы
local Length = table.maxn(Frame); --Длина сообщения (без контрольной суммы!)
for I= 1,Length,1 do --Цикл по длине сообщения
DAT = Frame[I];
for J= 0, 7,1 do
AUX = bit.BitAnd(bit.BitXor(DAT,CRC),1 );
if AUX == 1 then CRC = bit.BitXor(CRC,24);
end;
CRC = bit.BitRshift(CRC,1 );
CRC = bit.BitOr(CRC,bit.BitLshift(AUX,7 ) );
DAT =bit.BitRshift(DAT,1 );
end;
end;
return CRC;
end
--функция вызываемая перед отправкой в прибор
function SendCrc(SendTable)
Byte1=CRCsum(SendTable);
table.insert(SendTable,Byte1);
--возвращаем количество байт и измененную таблицу
return table.maxn(SendTable),SendTable;
end
--функция вызываемая после приема ответа
function GetCrc(GetTable)
GetByte1=table.remove(GetTable); --удаляем последний и сохраняем в GetByte
CalcByte1=ModbusCRC(GetTable);
if GetByte1~=CalcByte1 then
return -10,GetTable; --возвращаем ошибку контрольной суммы
end
--возвращаем количество байт и измененную таблицу
return table.maxn(GetTable),GetTable;
end
-- обработка
function OnRead()
local Addr=server.GetCurrentDeviceAddress( );
local send = {Addr,1,1,0}; --кадр запроса чтения без контрольной суммы
local sendmask={"byte","byte","byte","byte"}; --маска запроса
local dest={}; --таблица принятых значений по маске
local destmask={"byte","byte","byte","byte","byte","int16:1:01"}; --маска ответа
--дополнительные переменные: ошибка,количество элементов в таблице dest, количество принятых байт
local err,len;
local n=0; --количество попыток запроса
--выполняем запросы в цикле
repeat
--запрос к устройству с вызовом функций подсчета контрольной суммы
err,dest,len=server.SendAndReceiveDataByMask(0,5,sendmask,send,destmask,200,"SendCrc","GetCrc");
if err==-1 then --нет ответа от устройства
break; --выходим из опроса
end
--проверяем что совпадает адрес прибора, номер канал и номер регистра
if dest[1]~=send[1] or dest[2]~=send[2] or dest[3]~=send[3] then
err=-2; --ошибка
end
n=n+1;
--выход из цикла - корректный прием или превышение количества попыток
until err>=0 or n>=server.GetCurrentDeviceRetry( );
if err<0 then
--данные не приняты или данные некорректы. Устанавливаем плохой признак качества
server.WriteCurrentTag(0,OPC_QUALITY_BAD); --
else
--Записываем в тег принятое значение
server.WriteCurrentTag(dest[len-1],OPC_QUALITY_GOOD);
end;
end
Управляет сигналом DTR. В качестве аргумента в функцию передается состояние, в которое нужно установить выход порта.
Функция работает только в переменных узла типа COM.
Пример
server.SetDTR(true);
Примечание. Для корректной работы данной функции необходимо чтобы порт был заранее открыт. Функции server.SendAndReciveDataByMask и server.SendAndReciveData открывают порт при их первом вызове, поэтому порт необходимо открыть заранее с помощью функции server.OpenConnection
Управляет сигналом RTS. В качестве аргумента в функцию передается состояние, в которое нужно установить выход порта.
Функция работает только в переменных узла типа COM.
Пример
server.SetRTS(true);
Примечание. Для корректной работы данной функции необходимо чтобы порт был заранее открыт. Функции server.SendAndReciveDataByMask и server.SendAndReciveData открывают порт при их первом вызове, поэтому порт необходимо открыть заранее с помощью функции server.OpenConnection