Написал скрипт на Питоне для сабжа.
Подключаем выводы A, B и GND WirenBoard к контактам 9, 10 и 11 счетчика.
Для чтения данных запускаем скрипт из консоли без ключей или с ключом -r.
Для программирования запускаем с ключом -p.
Систему команд смотрим в инструкции к счетчику.
Протокол обмена данными: ГОСТ Р МЭК 61107-2001.
#!/usr/bin/python
# coding: utf-8
import sys, io, serial
# Если нет ключей, то режим чтения по умолчанию
# -r : чтение ограниченного набора параметров
# -p : режим программирования (отменяет -r)
# -s : "silent mode", только для -p, выводятся только данные
read_flag = '0'
if '-r' in sys.argv:
read_flag = '6'
if '-p' in sys.argv:
read_flag = '1'
silent = '-s' in sys.argv
# Параметры последовательного порта: 9600 бод, 7E1, таймаут 0.1 с
ser = serial.Serial('/dev/ttyNSC0', bytesize=serial.SEVENBITS, parity=serial.PARITY_EVEN, timeout = 0.1)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser), newline = '')
# Чтение посылки с проверкой LRC
def data_decode(sdata):
msg = dict()
msg['head'] = ''
msg['body'] = ''
msg['lrc'] = False
# Ничего не меняем, если пришли служебные символы (ACK, NAK)
if len(sdata) <= 1:
msg['body'] = sdata
msg['lrc'] = True
else:
lrc = 0x00
head_add = False
body_add = False
lrc_add = False
# Считаем LRC (Сложение всех байт после (SOH) или (STX), не включая,
# до (ETX) включительно по модулю 0x7f, одновременно читаем заголовок и данные
for i in range(0,len(sdata)-1):
# Обнаружен (SOH)
if sdata[i] == '\x01':
head_add = True
lrc_add = True
# Обнаружен (STX)
elif sdata[i] == '\x02':
head_add = False
body_add = True
if lrc_add:
lrc = (lrc + ord(sdata[i])) & 0x7f
else:
lrc_add = True
# Обнаружен (ETX)
elif sdata[i] == '\x03':
head_add = False
body_add = False
lrc_add = False
lrc = (lrc + ord(sdata[i])) & 0x7f
else:
if head_add:
msg['head'] += sdata[i]
elif body_add:
msg['body'] += sdata[i]
if lrc_add:
lrc = (lrc + ord(sdata[i])) & 0x7f
# Проверяем последний байт посылки на соответствие вычисленому LRC
msg['lrc'] = lrc == ord(sdata[len(sdata) - 1])
return msg
# Запись посылки в строку с добавлением вычисленного LRC
def data_encode(msg):
sdata = ''
if msg['head']:
sdata += '\x01' + msg['head']
if msg['body']:
sdata += '\x02' + msg['body']
sdata += '\x03'
# Вычисление LRC см. data_decode
lrc = 0x00
lrc_add = False
for i in range(0,len(sdata)):
if sdata[i] == '\x01':
lrc_add = True
elif sdata[i] == '\x02':
if lrc_add:
lrc = (lrc + ord(sdata[i])) & 0x7f
else:
lrc_add = True
elif sdata[i] == '\x03':
lrc_add = False
lrc = (lrc + ord(sdata[i])) & 0x7f
else:
if lrc_add:
lrc = (lrc + ord(sdata[i])) & 0x7f
# Добавление вычисленного LRC в строку посылки
sdata += chr(lrc)
return sdata
# Отправка посылки и чтение данных из последовательного порта
def send_read(sdata):
sio.write(unicode(sdata))
sio.flush()
return sio.read().encode('ascii')
# Пароль для режима программирования (заводской: 777777)
# Если не указан, будет запрошен
password = ''
# Завершаем предыдущий сеанс
send_read(data_encode({'head':'B0','body':''}))
# Получаем идентификационное сообщение в ответ на общий запрос
ident = send_read('/?!\r\n')
# Отправляем подтвеждение с выбором режима и получаем информационное сообщение
message = data_decode(send_read('\x060' + ident[4] + read_flag + '\r\n'))
# Продолжаем, пока не получено сообщение окончания сеанса (B0)
while message['head'] <> 'B0':
# Запрошен пароль для режима программирования
if message['head'] == 'P0':
if password == '':
try:
password = raw_input('' if silent else 'Enter password ('+ message['body'] + '): ')
except (EOFError):
send_read(data_encode({'head':'B0', 'body':''}))
exit()
message = data_decode(send_read(data_encode({'head':'P1', 'body': '(' + password + ')'})))
# Получен запрос повторения (NAK)
# Почему-то после этого счетчик не ждет повторения, а просто перестает отвечать
# Начинаем сначала
elif message['body'] == '\x15':
if not silent:
print '(NAK) received, restarting...'
send_read(data_encode({'head':'B0','body':''}))
ident = send_read('/?!\r\n')
message = data_decode(send_read('\x060' + ident[4] + read_flag + '\r\n'))
# Нет ответа - начинаем сначала
elif message['body'] == '':
if not silent:
print 'Timeout, restarting...'
send_read(data_encode({'head':'B0','body':''}))
ident = send_read('/?!\r\n')
message = data_decode(send_read('\x060' + ident[4] + read_flag + '\r\n'))
else:
# Получено сообщение подтверждения
if message['body'] == '\x06':
if not silent:
print '(ACK)'
else:
# Получено информационное сообщение
print message['body'] if message['lrc'] else 'Data is corrupt!'
# Если режим чтения, выходим
if not (read_flag == '1'):
exit()
# Ввод типа команды (чтение, запись или выход)
# Поддерживаются только R1, W1 и B0
try:
head = raw_input('' if silent else '(R)ead, (W)rite or e(X)it (default)? ')
except (EOFError):
send_read(data_encode({'head':'B0','body':''}))
exit()
# Ввод команды и отправка
if (head.upper() == 'R') or (head.upper() == 'W'):
try:
body = raw_input('' if silent else 'Enter command: ')
except (EOFError):
send_read(data_encode({'head':'B0','body':''}))
exit()
message = data_decode(send_read(data_encode({'head':head.upper()+'1','body':body})))
# Завершение сеанса
else:
send_read(data_encode({'head':'B0','body':''}))
exit()