mirror of
https://github.com/furrtek/PrecIR.git
synced 2026-05-14 18:25:09 +00:00
Moved files, added ESL Blaster protocol info
Removed line used for debug in ESL Blaster FW
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# Programs ESL Blaster remote mode data
|
||||
# 2019 furrtek - furrtek.org
|
||||
# See LICENSE
|
||||
|
||||
import pr
|
||||
import tx
|
||||
import sys
|
||||
import serial
|
||||
|
||||
# Search for connected ESL Blaster
|
||||
blaster_port = tx.search_esl_blaster()
|
||||
if (blaster_port == "0"):
|
||||
exit()
|
||||
|
||||
ser = serial.Serial(blaster_port, 57600, timeout = 5) # 5s timeout for read
|
||||
ser.reset_input_buffer()
|
||||
|
||||
frameA = [0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x09, 0x00, 0x00, 0xF2, 0xA7] # Segment change page
|
||||
frameB = [0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x06, 0x11, 0x00, 0x00, 0xEA, 0x80] # DM change page
|
||||
|
||||
data = []
|
||||
data.extend([0] * (1024 - len(data)))
|
||||
|
||||
data[0] = 2 # Frame count
|
||||
data[1] = 0
|
||||
data[2:2+len(frameA)] = frameA
|
||||
data[2+72:2+72+len(frameB)] = frameB
|
||||
|
||||
print(len(data))
|
||||
|
||||
ba = bytearray()
|
||||
ba.append('W')
|
||||
ser.write(ba)
|
||||
ser.flush()
|
||||
for p in range(0, 8):
|
||||
ba = bytearray()
|
||||
for b in range(0, 128):
|
||||
ba.append(data[p*128 + b])
|
||||
|
||||
ser.write(ba)
|
||||
ser.flush()
|
||||
ser.read_until('K')
|
||||
print("OK")
|
||||
|
||||
print(ser.read())
|
||||
|
||||
ser.close()
|
||||
|
||||
print("Done. Read flash to verify now.")
|
||||
@@ -0,0 +1,178 @@
|
||||
# Converts, compresses and transmits images to dot matrix ESLs
|
||||
# 2018 furrtek - furrtek.org
|
||||
# See LICENSE
|
||||
|
||||
import pr
|
||||
import tx
|
||||
from imageio import imread
|
||||
import sys
|
||||
|
||||
def record_run(run_count):
|
||||
# Convert to binary
|
||||
del bits[:]
|
||||
while run_count:
|
||||
bits.insert(0, run_count & 1)
|
||||
run_count >>= 1
|
||||
# Zero length coding
|
||||
for b in bits[1:]:
|
||||
compressed.append(0)
|
||||
if len(bits):
|
||||
compressed.extend(bits)
|
||||
|
||||
def usage():
|
||||
print("img2dm - Transmits image to Dot Matrix ESL\n")
|
||||
print("Usage:")
|
||||
print("img2dm.py port image barcode page (x y)\n")
|
||||
print(" port: serial port name (0 for ESL Blaster)")
|
||||
print(" image: image file")
|
||||
print(" barcode: 17-character barcode data")
|
||||
print(" page: page number to update (0~15)")
|
||||
print(" x y: top-left position of image, default: 0 0")
|
||||
exit()
|
||||
|
||||
arg_count = len(sys.argv)
|
||||
if arg_count < 5:
|
||||
usage()
|
||||
|
||||
port = sys.argv[1]
|
||||
|
||||
# Search for connected ESL Blaster if required
|
||||
if (port == "0"):
|
||||
blaster_port = tx.search_esl_blaster()
|
||||
if (blaster_port == "0"):
|
||||
exit()
|
||||
|
||||
# Open image file
|
||||
image = imread(sys.argv[2])
|
||||
width = image.shape[1]
|
||||
height = image.shape[0]
|
||||
if width > 208 or height > 112:
|
||||
print("Image should be 208*112 pixels or less.")
|
||||
exit()
|
||||
|
||||
# Get PLID from barcode string
|
||||
PLID = pr.get_plid(sys.argv[3])
|
||||
|
||||
page = int(sys.argv[4])
|
||||
if page < 0 or page > 15:
|
||||
print("Page can only be between 0 and 15.")
|
||||
exit()
|
||||
|
||||
if arg_count > 5:
|
||||
pos_x = int(sys.argv[5])
|
||||
else:
|
||||
pos_x = 0
|
||||
if arg_count > 6:
|
||||
pos_y = int(sys.argv[6])
|
||||
else:
|
||||
pos_y = 0
|
||||
|
||||
bits = []
|
||||
size_raw = width * height
|
||||
|
||||
# Convert image to 1-bit
|
||||
pixels = []
|
||||
for row in image:
|
||||
for rgb in row:
|
||||
pixels.append(int(round((0.21 * rgb[0] + 0.72 * rgb[1] + 0.07 * rgb[2]) / 255)))
|
||||
|
||||
print("Compressing %i pixels..." % size_raw)
|
||||
|
||||
# First pixel
|
||||
compressed = []
|
||||
run_pixel = pixels[0]
|
||||
run_count = 1
|
||||
compressed.append(run_pixel)
|
||||
for pixel in pixels[1:]:
|
||||
if pixel == run_pixel:
|
||||
# Add to run
|
||||
run_count += 1
|
||||
else:
|
||||
# Record run
|
||||
record_run(run_count)
|
||||
run_count = 1
|
||||
run_pixel = pixel
|
||||
|
||||
# Record last run
|
||||
if run_count > 1:
|
||||
record_run(run_count)
|
||||
|
||||
size_compressed = len(compressed)
|
||||
|
||||
# Decide on compression or not
|
||||
if size_compressed < size_raw:
|
||||
print("Compression ratio: %.1f%%" % (100 - ((size_compressed * 100) / float(size_raw))))
|
||||
data = compressed
|
||||
compression_type = 2
|
||||
else:
|
||||
print("Compression ratio suxx, using raw data")
|
||||
data = pixels
|
||||
compression_type = 0
|
||||
|
||||
# Pad data to multiple of bits_per_frame
|
||||
bits_per_frame = 20 * 8
|
||||
data_size = len(data)
|
||||
padding = bits_per_frame - (data_size % bits_per_frame)
|
||||
for b in range(0, padding):
|
||||
data.append(0)
|
||||
|
||||
padded_data_size = len(data)
|
||||
frame_count = padded_data_size // bits_per_frame
|
||||
|
||||
frames = []
|
||||
|
||||
# Ping frame
|
||||
frames.append(pr.make_ping_frame(PLID, 400))
|
||||
|
||||
print("Generating %i data frames..." % frame_count)
|
||||
|
||||
# Parameters frame
|
||||
frame = pr.make_mcu_frame(PLID, 0x05)
|
||||
pr.append_word(frame, data_size // 8) # Byte count
|
||||
frame.append(0x00) # Unused
|
||||
frame.append(compression_type)
|
||||
frame.append(page)
|
||||
pr.append_word(frame, width)
|
||||
pr.append_word(frame, height)
|
||||
pr.append_word(frame, pos_x)
|
||||
pr.append_word(frame, pos_y)
|
||||
pr.append_word(frame, 0x0000) # Keycode
|
||||
frame.append(0x88) # 0x80 = update, 0x08 = set base page
|
||||
pr.append_word(frame, 0x0000) # Enabled pages (bitmap)
|
||||
frame.extend([0x00, 0x00, 0x00, 0x00])
|
||||
pr.terminate_frame(frame, 1)
|
||||
frames.append(frame)
|
||||
|
||||
# Data frames
|
||||
i = 0
|
||||
for fr in range(0, frame_count):
|
||||
frame = pr.make_mcu_frame(PLID, 0x20)
|
||||
pr.append_word(frame, fr)
|
||||
for by in range(0, 20):
|
||||
v = 0
|
||||
# Bit string to byte
|
||||
for bi in range(0, 8):
|
||||
v <<= 1
|
||||
v += data[i + bi]
|
||||
frame.append(v)
|
||||
i += 8
|
||||
pr.terminate_frame(frame, 1)
|
||||
frames.append(frame)
|
||||
|
||||
# Refresh frame
|
||||
frames.append(pr.make_refresh_frame(PLID))
|
||||
|
||||
# DEBUG
|
||||
#f = open("out.txt", "w")
|
||||
#for fr in frames:
|
||||
# for b in fr:
|
||||
# f.write(format(b, '02X') + " ")
|
||||
# f.write("\n")
|
||||
#exit()
|
||||
|
||||
# Send data to IR transmitter
|
||||
if (port == "0"):
|
||||
tx.transmit_esl_blaster(frames, blaster_port)
|
||||
else:
|
||||
tx.transmit_serial(frames, port)
|
||||
print("Done. Please allow a few seconds for the ESL to refresh.")
|
||||
@@ -0,0 +1,63 @@
|
||||
# Collection of procedures related to ESLs
|
||||
# 2018 furrtek - furrtek.org
|
||||
# See LICENSE
|
||||
|
||||
def terminate_frame(frame, repeats):
|
||||
# Compute whole frame's CRC16
|
||||
result = 0x8408
|
||||
poly = 0x8408
|
||||
|
||||
for by in frame:
|
||||
result ^= by
|
||||
for bi in range(0, 8):
|
||||
if (result & 1):
|
||||
result >>= 1
|
||||
result ^= poly
|
||||
else:
|
||||
result >>= 1
|
||||
|
||||
frame.append(result & 255)
|
||||
frame.append((result // 256) & 255)
|
||||
frame.append(repeats & 255) # This is used by the transmitter, it's not part of the transmitted data
|
||||
frame.append((repeats // 256) & 255) # This is used by the transmitter, it's not part of the transmitted data
|
||||
|
||||
def make_raw_frame(protocol, PLID, cmd):
|
||||
frame = [protocol, PLID[3], PLID[2], PLID[1], PLID[0], cmd]
|
||||
return frame
|
||||
|
||||
def make_mcu_frame(PLID, cmd):
|
||||
frame = [0x85, PLID[3], PLID[2], PLID[1], PLID[0], 0x34, 0x00, 0x00, 0x00, cmd]
|
||||
return frame
|
||||
|
||||
def append_word(frame, value):
|
||||
frame.append(value // 256)
|
||||
frame.append(value & 255)
|
||||
|
||||
def get_plid(barcode):
|
||||
PLID = [0] * 4
|
||||
if len(barcode) != 17:
|
||||
return PLID
|
||||
id_value = int(barcode[2:7]) + (int(barcode[7:12]) << 16)
|
||||
PLID[0] = (id_value >> 8) & 0xFF
|
||||
PLID[1] = id_value & 0xFF
|
||||
PLID[2] = (id_value >> 24) & 0xFF
|
||||
PLID[3] = (id_value >> 16) & 0xFF
|
||||
return PLID
|
||||
|
||||
def make_ping_frame(PLID, repeats):
|
||||
frame = make_raw_frame(0x85, PLID, 0x17)
|
||||
frame.append(0x01)
|
||||
frame.append(0x00)
|
||||
frame.append(0x00)
|
||||
frame.append(0x00)
|
||||
for b in range(0, 22):
|
||||
frame.append(0x01)
|
||||
terminate_frame(frame, repeats)
|
||||
return frame
|
||||
|
||||
def make_refresh_frame(PLID):
|
||||
frame = make_mcu_frame(PLID, 0x01)
|
||||
for b in range(0, 22):
|
||||
frame.append(0x00)
|
||||
terminate_frame(frame, 1)
|
||||
return frame
|
||||
@@ -0,0 +1,55 @@
|
||||
# Allows transmitting raw frames to ESLs
|
||||
# 2018 furrtek - furrtek.org
|
||||
# See LICENSE
|
||||
|
||||
import pr
|
||||
import tx
|
||||
import sys
|
||||
|
||||
def usage():
|
||||
print("Usage:")
|
||||
print("rawcmd.py port barcode type hex count\n")
|
||||
print(" port: serial port name (0 for ESL Blaster)")
|
||||
print(" barcode: 17-character barcode data, or 0")
|
||||
print(" type: DM for graphic ESL, SEG for segment")
|
||||
print(" hex: frame data as hex string without CRC")
|
||||
print(" count: number of times the frame is transmitted")
|
||||
exit()
|
||||
|
||||
if len(sys.argv) != 6:
|
||||
usage()
|
||||
|
||||
port = sys.argv[1]
|
||||
|
||||
# Search for connected ESL Blaster if required
|
||||
if (port == "0"):
|
||||
blaster_port = tx.search_esl_blaster()
|
||||
if (blaster_port == "0"):
|
||||
exit()
|
||||
|
||||
# Get PLID from barcode string
|
||||
PLID = pr.get_plid(sys.argv[2])
|
||||
|
||||
ba = bytearray.fromhex(sys.argv[4])
|
||||
|
||||
frames = []
|
||||
|
||||
frame = pr.make_raw_frame(0x85 if (sys.argv[3] == "DM") else 0x84, PLID, ba[0])
|
||||
frame.extend(ba[1:])
|
||||
pr.terminate_frame(frame, int(sys.argv[5]))
|
||||
frames.append(frame)
|
||||
|
||||
# DEBUG
|
||||
#f = open("out.txt", "w")
|
||||
#for fr in frames:
|
||||
# for b in fr:
|
||||
# f.write(format(b, '02X') + " ")
|
||||
# f.write("\n")
|
||||
#exit()
|
||||
|
||||
# Send data to IR transmitter
|
||||
if (port == "0"):
|
||||
tx.transmit_esl_blaster(frames, blaster_port)
|
||||
else:
|
||||
tx.transmit_serial(frames, port)
|
||||
print("Done.")
|
||||
@@ -0,0 +1,82 @@
|
||||
# Procedures related to the IR transmitters only
|
||||
# 2019 furrtek - furrtek.org
|
||||
# See LICENSE
|
||||
|
||||
import serial
|
||||
|
||||
def search_esl_blaster():
|
||||
found = 0
|
||||
for n in range(1, 20):
|
||||
comport = "COM" + str(n)
|
||||
try:
|
||||
ser = serial.Serial(comport, 57600, timeout = 1) # 1s timeout for read
|
||||
ser.write("?".encode())
|
||||
ser.flush()
|
||||
test = len(ser.read_until("ESLBlaster"))
|
||||
ser.close()
|
||||
if (test == 10):
|
||||
print("Found ESL Blaster on " + comport)
|
||||
found = 1
|
||||
break
|
||||
else:
|
||||
print("Timeout on " + comport)
|
||||
except serial.SerialException:
|
||||
print("SerialException on " + comport)
|
||||
continue
|
||||
|
||||
if (found == 0):
|
||||
print("Could not find ESL Blaster.")
|
||||
return "0"
|
||||
else:
|
||||
return comport
|
||||
|
||||
def transmit_serial(frames, port):
|
||||
ser = serial.Serial(port, 57600, timeout = 10) # 10s timeout for read
|
||||
ser.reset_input_buffer()
|
||||
frame_count = len(frames)
|
||||
i = 1
|
||||
for fr in frames:
|
||||
data_size = len(fr) - 2
|
||||
repeats = fr[-2] + (fr[-1] * 256)
|
||||
if repeats > 255:
|
||||
repeats = 255
|
||||
print("Transmitting frame %u/%u, length %u, repeated %u times." % (i, frame_count, data_size, repeats))
|
||||
|
||||
ba = bytearray()
|
||||
ba.append(data_size)
|
||||
ba.append(repeats)
|
||||
for b in range(0, data_size):
|
||||
ba.append(fr[b])
|
||||
|
||||
ser.write(ba)
|
||||
ser.flush()
|
||||
ser.read_until('A')
|
||||
i += 1
|
||||
|
||||
ser.close()
|
||||
|
||||
def transmit_esl_blaster(frames, port):
|
||||
ser = serial.Serial(port, 57600, timeout = 10) # 10s timeout for read
|
||||
ser.reset_input_buffer()
|
||||
frame_count = len(frames)
|
||||
i = 1
|
||||
for fr in frames:
|
||||
data_size = len(fr) - 2
|
||||
repeats = fr[-2] + (fr[-1] * 256)
|
||||
print("Transmitting frame %u/%u, length %u, repeated %u times." % (i, frame_count, data_size, repeats))
|
||||
|
||||
ba = bytearray()
|
||||
ba.append('L')
|
||||
ba.append(data_size)
|
||||
ba.append(30) # 30*50 = 1500 timer ticks between repeats
|
||||
ba.append(repeats & 255)
|
||||
ba.append((repeats // 256) & 255)
|
||||
for b in range(0, len(fr) - 2):
|
||||
ba.append(fr[b])
|
||||
ba.append('T')
|
||||
ser.write(ba)
|
||||
ser.flush()
|
||||
ser.read_until('K')
|
||||
i += 1
|
||||
|
||||
ser.close()
|
||||
Reference in New Issue
Block a user