PDA

Просмотр полной версии : Запрос по маске в MasterOPC Server



fizhimik
21.07.2021, 17:37
Добрый день! Попытался реализовать протокол для устройства в MasterOPC Server согласно инструкции для функции Modbus Function Code 23 (0x17) Read/Write Multiple Registers https://insat.ru/products/Universal_MasterOPC/MU_MasterOPC_Server_API_UG.pdf, но что то пошло не так.
Запрос по маске сделал на основе скрипта первого примера для датчика температуры и влажности МАВ-ТС100 фирмы «Микрофор». Решил начать с самого простого старт/остановка устройства, старт запись в 0x000C значения 0x0001, стоп запись 0x0000 соответственно. Скрипт из примера для теста обрезал по максимуму для своих тестов.
561495615056151
function Start_Chill(num_reg)
local send={}; --массив отправляемых чисел
local Addr=server.GetCurrentDeviceAddress( );--получения адреса устройства
table.insert(send,Addr); --добавляем в таблицу первый элемент - адрес
table.insert(send,0x17); --добавляем в таблицу второй элемент - идентификатор команды
table.insert(send,0x0000); --добавляем в таблицу третий Read Address Hi Lo
table.insert(send,0x0000); --добавляем в таблицу четвертый Quantity to Read Hi Lo
table.insert(send,0x000C); --добавляем в таблицу пятый Write Address Hi Lo
table.insert(send,0x01); --добавляем в таблицу шестой Quantity to Write
table.insert(send,0x02); --добавляем в таблицу седьмой Byte Count
table.insert(send,num_reg); --добавляем в таблицу восьмой Значение на запись
local sendmask={"byte","byte","int16:10","int16:10","int16:10","int16:10","byte","int16:10"}; --маска отправляемого запроса
local dest={}; --массив полученных чисел
local destmask={"byte","byte","byte","int16:10"}; --маска принимаемого запроса
local err,len;
local n=0;
repeat
--посылка и получение запроса в устройство
err,dest,len=server.SendAndReceiveDataByMask(3,8,s endmask,send,destmask,20);
n=n+1;
--условие выхода - корректный ответ или превышение запросов
until err>=0 or n>=server.GetCurrentDeviceRetry()
--обрабатываем полученные данные
if err>=0 then
--запрос выполнен корректно
if dest[2]==0x17 then
return true,dest[3]; --возвращаем флаг что запрос корректен и значение
else
server.Message("Неизвестная функция"); --пишем сообщение в лог
return false,0; --запрос некорректен
end;
else
return false,0; --запрос некорректен, возвращаем соответсвующий флаг
end;
end;
-- Initialization
function OnInit()
end
-- Uninitialization
function OnClose()
end
-- Processing
function OnWrite()
if server.ReadCurrentTag()==true
then noerr,RegH=Start_Chill(0x0001)
else noerr,RegH=Start_Chill(0x0000)
end;
end

Формируемая маска запроса в MasterOPC Server 21-07-2021 17:36:51.224 SMS HRZ::Chiller:(COM5) Tx: [0014] 01 17 00 00 00 00 00 0C 00 01 02 D9 0D 0A , причем я сделал логическое переключение для старта и остановки устройства, но при задании true либо false маска запроса никак не изменяется. Я ожидал получить такую маску : 01 17 00 00 00 00 00 0C 00 01 02 00 01 LRC 0D 0A

fizhimik
22.07.2021, 17:49
Я еще тут поэкспериментировал немного с устройством, даже такая сформированная маска не подходит, нужно маску :01 17 00 00 00 00 00 0C 00 01 02 00 01 LRC сформировать без пробелов и передать в ASCII кодировке. Как это можно сделать в MasterOPC Server? Вернее эта маска должна быть без пробелов :011700000000000C0001020001LRC[CR][LF]

fizhimik
23.07.2021, 14:44
Я немного разобрался, мне подошел второй пример из https://insat.ru/products/Universal_MasterOPC/MU_MasterOPC_Server_API_UG.pdf, но затем при попытке повторить запрос в устройство как в примере из мануала к устройству, я понял что расчет LRC в функции server.SendAndReceiveDataByMask мне не подходит. Можете подсказать как это можно реализовать?
56205

fizhimik
04.08.2021, 12:29
Добрый день! Забросил пока этот прибор, решил попробовать подключить другой, без контрольной суммы, но не могу конвертировать получаемые ASCII символы.
Запрос на измерение выглядит так Tx: [0017] 3A 30 36 30 33 30 34 32 31 34 30 32 31 34 30 0D 0A, ответ от прибора Rx: [0021] 3A 30 38 30 33 30 32 32 31 34 30 30 30 30 30 30 30 30 30 0D 0A. В выделенных символах находится измеряемое число (оно на данный момент 0). В маске получаемых данных я прописал destmask={"string:32","string:23","string:6"}; --маска принимаемого запроса. Так правильно, стоит ли считать пробелы? В Справке к Master OPC описан пример пересчета значения в FLOAT, но я не понимаю как перейти от получаемых ASCII к значению, которое можно подставить в пример для пересчета. Можете подсказать?

SCADAMaster
04.08.2021, 13:29
Вы можете получить как строку, а потом с помощью стандартной функции tonumber (описание в справке) привезти к числу
Либо вы можете сразу получать как sdouble - посмотрите пример DCON в инструкции

fizhimik
04.08.2021, 14:50
Вы можете получить как строку, а потом с помощью стандартной функции tonumber (описание в справке) привезти к числу
Либо вы можете сразу получать как sdouble - посмотрите пример DCON в инструкции
Спасибо.
Но к сожалению, я что то делаю не так. Ни одним из способов преобразовать данные не получилось. Вот конец кода, функция ToFloat из справки.
local dest={}; --массив полученных чисел
local destmask={"string:32","sdouble:1:8","string:6"}; --маска принимаемого запроса
local err,len;
local n=0;
local list={};
local val;
err,dest,len=server.SendAndReceiveDataByMask(0,tab le.maxn(send),sendmask,send,destmask,200);

server.WriteCurrentTag(ToFloat(dest[2]));
04-08-2021 14:48:30.885 Measure:Node1.Device1.Measure >> [string "--[[(R)Node1.Device1.Measure]]-- Initializati..."]:3: bad argument #1 to 'BitAnd' (number expected, got string)
stack traceback:
[C]: at 0x00873ad0
[C]: in function 'BitAnd'
[string "--[[(R)Node1.Device1.Measure]]-- Initializati..."]:3: in function 'ToFloat'
[string "--[[(R)Node1.Device1.Measure]]-- Initializati..."]:44: in function <[string "--[[(R)Node1.Device1.Measure]]-- Initializati..."]:23>

SCADAMaster
04.08.2021, 15:03
Что за tofloat? Нет такой функции - есть функция tonumber. Посмотрите ее описание в справке

fizhimik
04.08.2021, 15:11
Что за tofloat? Нет такой функции - есть функция tonumber. Посмотрите ее описание в справке
Пример функции

function ToFloat(register)

local fraction=bit.BitAnd(register,0x7FFFFF); --маскируем 23 бита - получем мантиссу

local exp=bit.BitRshift(register,23); --смещаемся вправо на 23 бита - получаем экспоненту

local exp=bit.BitAnd(exp,0xFF); --маскируем биты экспоненты

local sign=bit.BitFromData(register,31); --выделяем бит знака

local float=2^(exp-127)*(1+fraction/2^23); --вычисляем число

if sign==true then float=float*(-1); end; --проверяем знак

return float;

end

Пример вызова функции.

val=1042284544;

FloatNumber=ToFloat(val);

Может я совсем не правильно делаю, ведь пробел это то же символ и это надо учитывать?
Либо извлекаемую строку с данными обработать string.split, получив таблицу с отдельными ASCII символами, преобразовать таблицу получив значения HEX(тут я могу ошибаться в терминологии) и затем как то совместить значения из таблицы получив одно число, которое потом сконвертировать во Float?

SCADAMaster
04.08.2021, 15:49
Ну так там ToFloat это пользовательская функция и делает она не это.
Посмотрите описание tonumber
И где вы пробел увидели? У пробела ASCII код - 0x20

fizhimik
04.08.2021, 16:02
Ну так там ToFloat это пользовательская функция и делает она не это.
Посмотрите описание tonumber
И где вы пробел увидели? У пробела ASCII код - 0x20
Пробел между символами 30 30...
Я решил перепроверить работу tonumber в Lua, вот результат
56381
Если пробелы убрать то функция работает. Что я делаю не так?

SCADAMaster
04.08.2021, 19:04
Уже даже не знаю как это комментировать...
Никакого пробела нет - его добавляет сервер в лог, чтобы визуально различать байты.
Конвертировать 30 30 30 ... в число смысла нет - потому что это не число. Вам с помощью маски нужно преобразование в строку, а уже полученную строку преобразовывать в число функцией tonumber.

fizhimik
05.08.2021, 11:13
Уже даже не знаю как это комментировать...
Никакого пробела нет - его добавляет сервер в лог, чтобы визуально различать байты.
Конвертировать 30 30 30 ... в число смысла нет - потому что это не число. Вам с помощью маски нужно преобразование в строку, а уже полученную строку преобразовывать в число функцией tonumber.
Спасибо! Я теперь знаю, что пробела нет, для меня это было вообще не очевидно, так как при опросе по стандартным функциям в логе Запроса команда идет без пробела, это меня и смущало. Подобной задачей я занимаюсь первый раз и открываю для себя много нового, поэтому не удивляйтесь подобным вопросам.
Тогда получается для ответа от сервера в виде 3A 30 38 30 33 30 32 32 31 34 30 30 30 30 30 30 30 30 30 0D 0A, маска должна быть destmask={"string:22","string:16","string:4"}; --маска принимаемого запроса
UPD.
Я тут наугад попробовал поменять маску destmask={"string:11","string:8","string:2"}; обработал tonumber, затем в функцию приведенную для примера в справке ToFloat и заработало.
Оказывается, для меня было не очевидно, что string:11 это количество элементов, а не количество символов. В самом первом примере Руководства было string:1 и там был только один символ для инициализации команды, это меня и спутало. В руководстве это описано на странице 57 для int16, но эту информацию я как то упустил.
Спасибо большое за поддержку!

fizhimik
10.08.2021, 12:35
Добрый день! Появилась задача записи float числа в прибор. В справке приведен пример перевода через server.SendAndReceiveDataByMask и результатом в виде таблицы. Как следует поступить дальше с таблицей? Для теста обработал результат таблицы tostring и в сервере установил тип данных string и записал результат в тег. Результатом после запуска сервера для числа 12.3 стало table: 0x0ab31c60, причем последние три символа постоянно меняются. Кроме того если воспользоваться онлайн калькулятором то число 12.3 будет 0x4144cccd. Подскажите как дальше быть.

SCADAMaster
10.08.2021, 13:01
А зачем так делать? Вы можете просто маску указать и все ОРС - сам преобразует как надо.
Если вам это нужно сделать для подсчета контрольной суммы, то лучше просто сделать для этого внешнюю функцию которая вызывается с помощью 7 и 8 аргумента функции SendAndReciveDataByMask (посмотрите справку - там это описано)

fizhimik
10.08.2021, 13:10
А зачем так делать? Вы можете просто маску указать и все ОРС - сам преобразует как надо.
Если вам это нужно сделать для подсчета контрольной суммы, то лучше просто сделать для этого внешнюю функцию которая вызывается с помощью 7 и 8 аргумента функции SendAndReciveDataByMask (посмотрите справку - там это описано)

То есть достаточно указать маску "float" в маске отправляемого запроса? Просто в таблицу добавляются такого формата данные для преобразования в ASCII символы
send[2] = string.format ("%02X",0x08) и я думал что мое float число должно быть так добавлено
send[7]= string.format ("%08X",число на запись);

SCADAMaster
10.08.2021, 13:28
Насчет ASCII - пока не будут преобразовываться. Как раз это мы сейчас исправляем. Как исправим - да, будет нормально.

fizhimik
10.08.2021, 13:58
Насчет ASCII - пока не будут преобразовываться. Как раз это мы сейчас исправляем. Как исправим - да, будет нормально.

Понятно, спасибо. Может есть какой иной пример перевода float to hex на языке Lua? То что я нашел используют функции math.floor, math.mod но ОРС сервер их видимо не использует и выдает ошибку скрипта. https://coderoad.ru/18886447/%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D 0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D0%BA%D0%B0-IEEE-754-float-%D0%B2-%D1%88%D0%B5%D1%81%D1%82%D0%BD%D0%B0%D0%B4%D1%86%D 0%B0%D1%82%D0%B5%D1%80%D0%B8%D1%87%D0%BD%D0%BE%D0% B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D 0%BB%D0%B5%D0%BD%D0%B8%D0%B5

fizhimik
10.08.2021, 14:15
У меня в принципе получилось по первому коду в ссылке (функция function float2hex (n)), далее string.format("%x",float2hex(12.3)), результат 4144cccс что соответствует 12.2999992

fizhimik
12.08.2021, 12:23
Добрый день! Существует ли возможность опроса устройства при подачи питания на него, если ОРС сервер уже запущен? То есть ОРС сервер работает, опрашивает датчики, и тут мы решаем без перезапуска сервера задействовать еще устройства, теги которых опрашиваются в сервере. У меня в итоге ОРС сервер останавливается из за ошибок с криптах 12-08-2021 12:04:42.760 Max capacity:BronkHorst.Device1.Max capacity >> [string "--[[(R)BronkHorst.Device1.Max capacity]]-- In..."]:3: bad argument #1 to 'BitAnd' (number expected, got nil)
stack traceback:
[C]: at 0x00873ad0
[C]: in function 'BitAnd'
[string "--[[(R)BronkHorst.Device1.Max capacity]]-- In..."]:3: in function 'ToFloat'
[string "--[[(R)BronkHorst.Device1.Max capacity]]-- In..."]:42: in function <[string "--[[(R)BronkHorst.Device1.Max capacity]]-- In..."]:18>
12-08-2021 12:04:42.155 Measure:BronkHorst.Device1.Measure >> [string "--[[(R)BronkHorst.Device1.Measure]]-- Initial..."]:3: bad argument #1 to 'BitAnd' (number expected, got nil)
stack traceback:
[C]: at 0x00873ad0
[C]: in function 'BitAnd'
[string "--[[(R)BronkHorst.Device1.Measure]]-- Initial..."]:3: in function 'ToFloat'
[string "--[[(R)BronkHorst.Device1.Measure]]-- Initial..."]:42: in function <[string "--[[(R)BronkHorst.Device1.Measure]]-- Initial..."]:18>
А само устройство отвечает подобным образом 12-08-2021 12:04:42.760 BronkHorst::Device1:(COM6) Rx: [0067] 0D 0A 0D 0A 2A 2A 2A 2A 2A 20 42 48 54 20 4D 42 43 33 43 20 45 4C 20 50 52 45 53 54 49 47 45 20 56 32 2E 30 32 62 20 4E 6F 76 20 31 35 20 32 30 31 38 20 31 32 3A 30 31 3A 30 37 20 2A 2A 2A 2A 2A 0D 0A
12-08-2021 12:04:42.156 BronkHorst::Device1:(COM6) Tx: [0017] 3A 30 36 30 33 30 34 30 31 34 44 30 31 34 44 0D 0A
12-08-2021 12:04:42.155 BronkHorst::Device1:(COM6) Rx: [0001] 00
12-08-2021 12:04:41.766 BronkHorst::Device1:(COM6) Tx: [0017] 3A 30 36 30 33 30 34 32 31 34 30 32 31 34 30 0D 0A
Ответ устройства ***** BHT MBC3C EL PRESTIGE V2.02b Nov 15 2018 12:01:07 - очевидно его модель, прошивка и текущее время.
Если сымитировать обрыв провода данных - вытащить преобразователь USB-RS232 из компьютера, то проблем нет, данные затем снова начинают приходить (повторен цикл опроса устройства как в руководстве).
Спасибо.

SCADAMaster
12.08.2021, 13:37
Если у вас скрипт не упадет, то все будет работать.
Нужно тщательно обрабатывать принимаемые данные - убеждаться что верная контрольная сумма, что в таблице столько элементов сколько ожидается, что при преобразовании из строки в число не получился nil и т.д.

fizhimik
12.08.2021, 15:41
Если у вас скрипт не упадет, то все будет работать.
Нужно тщательно обрабатывать принимаемые данные - убеждаться что верная контрольная сумма, что в таблице столько элементов сколько ожидается, что при преобразовании из строки в число не получился nil и т.д.

Спасибо! Взял пример из руководства по RNet, добавил условий если при преобразовании из строки в число получился nil и скрипты перестали падать.

fizhimik
13.08.2021, 14:20
В итоге такой получился узел для BRONKHORST RS232 interface with ProPar protocol for digital multibus Mass Flow / Pressure instruments с минимально необходимой поддержкой вывода данных