• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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
С массивом теперь можно манипулировать как угодно, на данном этапе, можно сказать, что цель достигнута!
Большое спасибо форуму и всем участникам, без вас я бы не разобрался!
 
Сверху Снизу