• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Решено NODEMCU прием и передача байтовой информации по TCP на LUA

kobb500

New member
Использую плату NODEMCU с LUA интерпритатором.
Решаю задачу принять от устройства которое передаёт по MODBUS TCP.
Нужно принять пакет и сформировать ответ.
Устройство передает такой пакет: 00 01 00 00 00 06 01 03 00 00 00 01
Ответ нужно сформировать такой:00 01 00 00 00 05 01 03 02 00 00
Ну это к примеру, если ответ будет правильным, то все гуд.
С самим приемом и передачей проблем нету, я пробовал отправить принятый пакет обратно, он проходит, только устройство ругается, что неправильный ответ, ну это понятно)
Вот например код, который это делает:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)

    sck:send(payload)

    end)

end)
Проверяю тип принятых данных, длину и например преобразовываю в байтовую информацию:
Код:
print(type(payload))
print(string.len(payload))
print(string.byte(payload, 1, string.len(payload)))
В терминале будет вывод будет такой:
Код:
string
12
0    1    0    0    0    6    1    3    0    0    0    1
Это соответствует первому переданному пакету от MODBUS TCP устройства: 00 01 00 00 00 06 01 03 00 00 00 01
Только вывод в десятичном виде, я думал этого мне достаточно, хотя можно и преобразовать в шестнадцатиричные числа другой функцией, с этим проблем нету.
Попробовал сформировать ответ в ручную, который тоже успешно прошел:
Код:
sck:send("\0\1\0\0\0\5\1\3\0\0\0")
Я уже обрадовался и хотел собрать такой пакет из переменных, но ничего не получилось. Даже если мне удаётся собрать такую строку из переменных или массива, при выводе в терминал все показывает правильно, но передаётся в таком же виде, то есть когда я смотрю в анализаторе пакетов, вместо нормального ответа передаётся "\0\1\0\0\0\5\1\3\0\0\0".
Если кто сталкивался с таким, буду очень благдарен за ответ, спасибо.
 

kobb500

New member
Сформулируйте вопрос.
Вопрос, как мне сформировать пакет типа: 00 01 00 00 00 05 01 03 02 00 00
Или "\0\1\0\0\0\5\1\3\0\0\0"
Чтобы передать его функцией sck:send()
Мне нужно менять числа в этой строке.
То есть эта строка должна составляться из переменных.
Я написал вот такой код:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
z1 = 0
z2 = 1
z3 = 0
z4 = 0
z5 = 0
z6 = 5
z7 = 1
z8 = 3
z9 = 0
z10 = 0
z11 = 0
qq = '"'
ss = [[\]]
zz = qq .. z1 .. ss .. z2 .. ss .. z3 .. ss .. z4 .. ss .. z5 .. ss .. z6 .. ss .. z7 .. ss .. z8 .. ss .. z9 .. ss .. z10 .. ss .. z11 .. qq
print (zz)
sck:send(zz)
    end)
end)
Он отправляет в ответ строку "0\1\0\0\0\5\1\3\0\0\0"
Вместо того чтобы отправлять 00 01 00 00 00 05 01 03 02 00 00
Если я напишу вот такой код:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
sck:send("\0\1\0\0\0\5\1\3\0\0\0\177")
    end)
end)
То все отправляется как надо.
В анализаторе пакетов видно что передалось 00 01 00 00 00 05 01 03 02 00 00 а не "0\1\0\0\0\5\1\3\0\0\0"
Ну не знаю еще как понятней объяснить?
Ну вот такая проблема у меня, как передать пакет в виде 00 01 00 00 00 05 01 03 02 00 00 ?
 

nikolz

Well-known member
Вопрос, как мне сформировать пакет типа: 00 01 00 00 00 05 01 03 02 00 00
Или "\0\1\0\0\0\5\1\3\0\0\0"
Чтобы передать его функцией sck:send()
Мне нужно менять числа в этой строке.
То есть эта строка должна составляться из переменных.
Я написал вот такой код:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
z1 = 0
z2 = 1
z3 = 0
z4 = 0
z5 = 0
z6 = 5
z7 = 1
z8 = 3
z9 = 0
z10 = 0
z11 = 0
qq = '"'
ss = [[\]]
zz = qq .. z1 .. ss .. z2 .. ss .. z3 .. ss .. z4 .. ss .. z5 .. ss .. z6 .. ss .. z7 .. ss .. z8 .. ss .. z9 .. ss .. z10 .. ss .. z11 .. qq
print (zz)
sck:send(zz)
    end)
end)
Он отправляет в ответ строку "0\1\0\0\0\5\1\3\0\0\0"
Вместо того чтобы отправлять 00 01 00 00 00 05 01 03 02 00 00
Если я напишу вот такой код:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
sck:send("\0\1\0\0\0\5\1\3\0\0\0\177")
    end)
end)
Ну вот такая проблема у меня, как передать пакет в виде 00 01 00 00 00 05 01 03 02 00 00 ?
если кратко -никак.
то что вы хотите отправить
не может быть представлена в виде одной алфавитно-цифровой строки
на самом деле вот эта последовательность
00 01 00 00 00 05 01 03 02 00 00
содержит 14 строк из которых 12 пустых.
а вот эта строка "0\1\0\0\0\5\1\3\0\0\0" - одна.
-------------------
отправить ваш код как бинарный тоже нельзя так как
в nodemcu нет возможности отправлять бинарную последовательность.
---------------------------------
поэтому есть два варианта решить вашу проблему
1) делать обмен алфавитно-цифровыми последовательностями и потом преобразовывать в нужный вид.
2) самому добавить в прошивку NODEMCU недостающие модули.
-----------------------------
 

kobb500

New member
если кратко -никак.
Ну я в принципе вас понял, да, я кстати добавил в прошивку на всякий случай модули: Struct Module, encoder Module, bit Module и 1-Wire Module.
Последний думал использовать для расчета контрольной суммы.
Но все равно как-то странно, если я могу преобразовать принятую информацию например:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, string.format('%X', string.byte(c)))
end)
print (table.concat(arr, " "))

    end)

end)
Вывод в терминале будет таким:
Код:
0 1 0 0 0 6 1 3 0 0 0 1
Если подождать немного, то можно увидеть что преобразовывается в шестнадцатеричные числа:
Код:
0 1D 0 0 0 6 1 3 0 0 0 1
0 1E 0 0 0 6 1 3 0 0 0 1
0 1F 0 0 0 6 1 3 0 0 0 1
0 20 0 0 0 6 1 3 0 0 0 1
Пробелы поставила функция table.concat(arr, " "), если без пробелов, то будет все слитно
Если убрать string.format, то будет в десятичном виде записываться в массив:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, string.byte(c))
end)
print (table.concat(arr, " "))

    end)

end)
Вывод в терминале будет такой:
Код:
0 1 0 0 0 6 1 3 0 0 0 1
И соответственно через тот-же период можно увидеть:
Код:
0 30 0 0 0 6 1 3 0 0 0 1
0 31 0 0 0 6 1 3 0 0 0 1
0 32 0 0 0 6 1 3 0 0 0 1
Если вообще убрать функции преобразования, то в терминале выводятся пустые строки:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, c)
end)
print (table.concat(arr, " "))

    end)

end)
Как-то странно, если можно преобразовать в строку, но нельзя преобразовать обратно, это странно.
Постараюсь найти скрипты работы с UART, может там найду решение или может быть в дополнительных модулях это есть.
Во всяком случае спасибо за ответ и подсказку.
 

nikolz

Well-known member
Ну я в принципе вас понял, да, я кстати добавил в прошивку на всякий случай модули: Struct Module, encoder Module, bit Module и 1-Wire Module.
Последний думал использовать для расчета контрольной суммы.
Но все равно как-то странно, если я могу преобразовать принятую информацию например:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, string.format('%X', string.byte(c)))
end)
print (table.concat(arr, " "))

    end)

end)
Вывод в терминале будет таким:
Код:
0 1 0 0 0 6 1 3 0 0 0 1
Если подождать немного, то можно увидеть что преобразовывается в шестнадцатеричные числа:
Код:
0 1D 0 0 0 6 1 3 0 0 0 1
0 1E 0 0 0 6 1 3 0 0 0 1
0 1F 0 0 0 6 1 3 0 0 0 1
0 20 0 0 0 6 1 3 0 0 0 1
Пробелы поставила функция table.concat(arr, " "), если без пробелов, то будет все слитно
Если убрать string.format, то будет в десятичном виде записываться в массив:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, string.byte(c))
end)
print (table.concat(arr, " "))

    end)

end)
Вывод в терминале будет такой:
Код:
0 1 0 0 0 6 1 3 0 0 0 1
И соответственно через тот-же период можно увидеть:
Код:
0 30 0 0 0 6 1 3 0 0 0 1
0 31 0 0 0 6 1 3 0 0 0 1
0 32 0 0 0 6 1 3 0 0 0 1
Если вообще убрать функции преобразования, то в терминале выводятся пустые строки:
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {}
payload:gsub(".", function(c)
table.insert(arr, c)
end)
print (table.concat(arr, " "))

    end)

end)
Как-то странно, если можно преобразовать в строку, но нельзя преобразовать обратно, это странно.
Постараюсь найти скрипты работы с UART, может там найду решение или может быть в дополнительных модулях это есть.
Во всяком случае спасибо за ответ и подсказку.
Передать двоичный код можно но сложно
попробую рассказать как это сделать на примере:
--------------------------------
Предположим надо передать последовательность бит 1011110011100
сначала надо эту последовательность представить в виде отдельных байт
в нашем примере это
b1= 00010111
b2= 10011100
После этого каждый байт надо записать как отдельный символ строки
local s=string.char(b1)...string.char(b2);
и эту строку уже можно передать
на приемном конце надо из строки выделить отдельные байты
local b1=string.byte(s,1)
local b2=string.byte(s,2)
и эти байты собрать в целое число
------------------------
примерно так
 

kobb500

New member
Передать двоичный код можно но сложно
попробую рассказать как это сделать на примере:
Большое спасибо вам, попробую разобраться с этим.
С приемным устройством нет проблем, потому что это может быть промышленный контроллер, modbus устройство или OPC сервер, который работает только по modbus и в общем-то с ним проблем нету, там все работает, мне нужно только отправить ему информацию в нужном для него виде, а что он там с ней делает меня мало интересует и это хорошо, потому что я знаю точно что modbus устройство 100% рабочее и работает корректно. Мне только нужно наладить все на стороне NODEMCU, все, чтобы принималось и передавалось как надо. Задача как по мне очень интересная, хотя можно было все реализовать на ARDUINO IDE, там есть все библиотеки и примеры и все работает, просто берешь прошиваешь и все работает, аж как-то не интересно. Но мне больше нравится NODEMCU в чистом виде, да пусть даже с его не совершенным встроенным интерпритатором LUA, задумка очень интересная, только вот мало кто в нем работает, тем более с modbus, в интернете я встретил только один проект где используется NODEMCU с modbus и 485 портом, но там запрос формируется уже заготовленной строкой, которая не меняется. Что собственно меня и побудило попробовать сделать полноценный интерфейс на LUA.
Еще раз огромное спасибо за помощь!
 

kobb500

New member
После этого каждый байт надо записать как отдельный символ строки
local s=string.char(b1)...string.char(b2);
и эту строку уже можно передать
Огромное вам спасибо, это то, что мне нужно было, все получилось, все передается!
Код:
srv = net.createServer(net.TCP)
srv:listen(502, function(conn)
    conn:on("receive", function(sck, payload)
arr = {0,1,0,0,0,6,1,3,0,0,0,1}
buff = ""
for i=1, #arr do
line = string.char(arr[i])
buff = buff .. line
end
sck:send(buff)
    end)
end)
Открыл анализатор пакетов, все передаётся как надо!
Отправленный массив: arr = {0,1,0,0,0,6,1,3,0,0,0,1}
Был передан как: 00 01 00 00 00 06 01 03 00 00 00 01
С массивом теперь можно манипулировать как угодно, на данном этапе, можно сказать, что цель достигнута!
Большое спасибо форуму и всем участникам, без вас я бы не разобрался!
 
Сверху Снизу