From b065ea3a29dd376d95e4145faf96532e38d7be43 Mon Sep 17 00:00:00 2001 From: Furrtek Date: Sun, 3 Sep 2023 07:23:14 +0200 Subject: [PATCH] Simplified progress display Added note about corrupt red layer in bw mode --- README.md | 3 +++ hardware/esl_blaster/FW03/Src/ir.c | 16 ++++++++-------- images/152bwr.png | Bin 0 -> 848 bytes images/dm_128x64.png | Bin 1127 -> 803 bytes images/dm_64x64.png | Bin 0 -> 653 bytes images/pommes.bmp | Bin 69942 -> 0 bytes tools_python/flashtest.py | 10 ++++++++++ tools_python/img2dm.py | 21 +++++++++------------ tools_python/tx.py | 29 +++++++++++++++++++---------- 9 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 images/152bwr.png create mode 100644 images/dm_64x64.png delete mode 100644 images/pommes.bmp diff --git a/README.md b/README.md index 7731414..99c436d 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,6 @@ No. For two reasons: ***Is possession and use of such devices legal ?*** There's no cracking, exploit, patent or copyright infrigement going on so IMO it's safe to assume this is perfectly legal. Just don't try changing price displays so you can get discounts, the price in the store's database obviously remains unchanged so you'll end up having to pay the correct price anyways. + +***My tricolor-capable ESL shows red garbage after an image update*** +Transmit the image in tricolor mode. Transmitting black and white images to tricolor ESLs doesn't clear the red layer. diff --git a/hardware/esl_blaster/FW03/Src/ir.c b/hardware/esl_blaster/FW03/Src/ir.c index 61e0761..fcc7ff4 100644 --- a/hardware/esl_blaster/FW03/Src/ir.c +++ b/hardware/esl_blaster/FW03/Src/ir.c @@ -31,14 +31,14 @@ static const uint32_t pp4_errors[4] = { // 0101: 123us (TIM16 31*4=124 Err=1) // 0110: 139us (TIM16 35*4=140 Err=1) // 0111: 131us (TIM16 33*4=132 Err=1) -// 0100: 83us (TIM16 21*4=84 Err=1) -// 0101: 59us (TIM16 15*4=60 Err=1) -// 0110: 75us (TIM16 19*4=76 Err=1) -// 0111: 67us (TIM16 17*4=68 Err=1) -// 0100: 91us (TIM16 23*4=92 Err=1) -// 0101: 115us (TIM16 29*4=116 Err=1) -// 0110: 99us (TIM16 25*4=100 Err=1) -// 0111: 107us (TIM16 27*4=108 Err=1) +// 1100: 83us (TIM16 21*4=84 Err=1) +// 1101: 59us (TIM16 15*4=60 Err=1) +// 1110: 75us (TIM16 19*4=76 Err=1) +// 1111: 67us (TIM16 17*4=68 Err=1) +// 1100: 91us (TIM16 23*4=92 Err=1) +// 1101: 115us (TIM16 29*4=116 Err=1) +// 1110: 99us (TIM16 25*4=100 Err=1) +// 1111: 107us (TIM16 27*4=108 Err=1) // Burst: 21us (TIM16 5 *4=20 Err=-1) static const uint32_t pp16_steps[16] = { 7-2-1, 13-2-1, 9-2-1, 11-2-1, 37-2-1, 31-2-1, 35-2-1, 33-2-1, diff --git a/images/152bwr.png b/images/152bwr.png new file mode 100644 index 0000000000000000000000000000000000000000..9626d5b9d635918d6cbe70eff2fe21db8eac2f73 GIT binary patch literal 848 zcmeAS@N?(olHy`uVBq!ia0vp^GeDSw2}n*~u)PdOF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?%wnhBC`{TNTC{L0W zx26Ycb6erTgzl>fxf_4&{27H(1?r?a6#hd1c3g-7`#wm|Q{amzMM zXacDbTMaVirQaQetd;jqV_4;)`?dOI>LxR5nEj02<`4Q8Py4m^i&5lk*~dU~9C7nYzBWJpd&G~|tK}A-uYO$eKkIA6-_rip z{rg@S{@P>i_kF#Y?CUN5zv}d3@2>P;{L*K6?WOP4FJJl9O8KT+y`7v{|H^yrwdEH} zmR+`+`EB{WE17sCZ1uiY+)aM?aaX3**H>rz0{X84t*+RUH_LBt)n?@{$zOxsF2B3Q z9wc|6|El-a`DK^?U0H2zeW+v&*z|Ssv-qlRsRISSI$w75|Gnh>ccaSvD?dhn9W`^$ z{VNq~%xkNzCV#2SpYtw0*Xr7AyS-3kOce7eBZu*488oHYyU7D)&S-L22WQ% Jmvv4FO#nZueIx(? literal 0 HcmV?d00001 diff --git a/images/dm_128x64.png b/images/dm_128x64.png index 7de58356971db9d272d10675b828c50d0bcf3cfd..4c668856fbd8af3f3898a417571ccde4762107a1 100644 GIT binary patch delta 746 zcmaFPv6yXw%0xqzdZweEE{-7;ac?g^%sXtr!SZ0=fA8|1-Lak?mokD6PX1Bn@?*{w z5&JWrf6ht29W2_lQu9$wM5^E_+Gp)b7G7Yn7omjEf^eRSbD zQ&q;hVn*Ja7sZT!4SwxxV5=|uQp{+Z^KNx4LsZwg;=@~$OMd>-x-q@H?YY&J8BbV} z=Jupw0(-O#p#Dt+hyPxFt}m2W$8?tS z^2OA53vT5-0=f_6(p5K)JZJiq33TpNgOA6!Hwc%vD=~sX{0rZGyI-<;VFJ=x?|9s$ z*99Brzs_#Ymut(t(0ftn=<e)8`_^phUi)QY+xcSm|o=XcYLz)gLw7-7hch}AL zNV=+heQ}1L4^MLL1{SyH?-$=Y7^eO;@P2P!+ufj~f77k3PJ1t8-rAI|D$5(;cIQT( z;jKEk>}FMiTf1&(wc7DywJhdv^J8JFq(L4^%gkFRIN#H*E|DcHoEnz zcLjPCha0|1c;ROHDUkQFc}&05EQ@9N8)QliN__4s$hex6h_Lkh>GZx^prwCn~DfGym~)aSW-5dpqrI;THv-mdpOHJnh5%U+t{> zl=N1Kxyji4edG<}syd4e3U+0+lJ%(8|oVmv++q=_OR3p(#e2a6MhUen8`_>!vuu#-Rs6uV z&z(WL@i*r;X8#v^9W*0agW2r&pQt|azW)3X6TeeiCeQEB@5}Ldx1(i?ZS;2D1dG7u zF_sN3R*shop8Wopb3a^ZooqC7@odqQtByY_j;o%q%$GT^;oslJsRw@DX8UmM|AcPV zfT;T83^N#JoO+nVs8Ud2vcRH9;6TH!1!o*2+X^=_RNRSXpI|6@H}m>$RtA}wvi5vT z70>6_S9_jY6kNYIzQJtE+Y|Nd6U1KlPnv4Y9i!90Qgi>!{&gvuT8D$^+lW6)YPXE`8xRF#E}laE9B{z1}}w@~^(>WzGB$;d_7UR_+Um7e8(H z`22EXPigaBe`n#_ufN(q;-0@tIL-H!Xur{k;=Rls(XTe=)J!_m{;Nu2g|1^zrCil- z9zD~ilOpFH-OKS!xr%+lfn&Ga9y`CN?|=R{vHro``!;(PWTl_@@WNDY<+YO~$>f?wFEuE^G0G`O9{!TgMk# zD&x7^?0m4rzIkU>+zZ+j?@{J=&FsvPG_4~w9BcN;d%EpqzQI@0%CP2YXZ=YEUVKewZXshJ_e z<@+g#?5rM*L!Uo3+wbxz-@kXp?{9@X3I~0|SscWpW{dP~-!@Hj_fm=5&y%uVK0R1= z_r$q0>j1Xc7xR}F+wQul?Ehxpir-qT^?#-Ba!4KH)8|~k!k+T{@r~DeKkT0sadvb5 zme|d6f<^b2U7vTMaf@nnI=etmz-8qI)+x)Tzda!OLyl3$VeN6@-UFgvW2GDA4QvM$pxKJ=yYLIPx&tLU<~K-KEL^sDVuRccr}x0rz+WJ9jrm2RJSb6oXj~^= fAf-_7;Pq?ygyMw{{TTvn7=Xaj)z4*}Q$iB};Su`w diff --git a/images/dm_64x64.png b/images/dm_64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..25e964f4cb549bb808bed0eb8cc948f1b77b0ea8 GIT binary patch literal 653 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 0.1 and luma < 0.9 else 1) # 0 codes color (anything mid grey) else: pixels.append(0 if luma < 0.5 else 1) # 0 codes black - return pixels def record_run(run_count): @@ -28,7 +27,7 @@ def record_run(run_count): while run_count: bits.insert(0, run_count & 1) run_count >>= 1 - # Zero length coding + # Zero length coding - 1 for b in bits[1:]: compressed.append(0) if len(bits): @@ -40,7 +39,7 @@ def usage(): print("img2dm.py port image barcode (page color x y pp4)\n") print(" port: serial port name (0 for ESL Blaster)") print(" image: image file") - print(" barcode: 17-character barcode data") + print(" barcode: 17-character ESL barcode data") print(" page: page number to update (0~15), default: 0") print(" color: 0:Black and white only, 1:Color-capable ESL, default: 0") print(" x y: top-left position of image, default: 0 0") @@ -74,8 +73,6 @@ if (port == "0"): image = imread(sys.argv[2]) width = image.shape[1] height = image.shape[0] -# Medium size is 208*112 -print("Image is %i*%i, please make sure that this is equal or less than the ESL's display size." % (width, height)) # Get PLID from barcode string PLID = pr.get_plid(sys.argv[3]) @@ -86,16 +83,18 @@ pos_y = int(sys.argv[7]) if arg_count >= 8 else 0 if arg_count >= 9: if int(sys.argv[8]): pp16 = 0 + +# Medium size is 208*112 +print("Image is %i*%i in %s mode, please make sure that this suits your ESL's display." % (width, height, "color" if color_mode else "black and white")) # First pass for black and white pixels = image_convert(image, 0) if color_mode: - # Append second pass for color if needed + # Append second pass for color, if needed pixels += image_convert(image, 1) size_raw = len(pixels) -print("Compressing %i bits..." % size_raw) # First pixel bits = [] @@ -122,11 +121,11 @@ size_compressed = len(compressed) # Decide on compression or not # size_compressed = size_raw # Disable compression if size_compressed < size_raw: - print("Compression ratio: %.1f%%" % (100 - ((size_compressed * 100) / float(size_raw)))) + print("Compression ratio: %.1f%% (%d -> %d bytes)" % (100 - ((size_compressed * 100) / float(size_raw)), size_raw, size_compressed)) data = compressed compression_type = 2 else: - print("Compression ratio suxx, using raw data") + print("Compression ratio suxx, using raw data instead") data = pixels compression_type = 0 @@ -139,15 +138,13 @@ for b in range(0, padding): padded_data_size = len(data) frame_count = padded_data_size // bits_per_frame -print("Data size: %i (%i frames)" % (data_size, frame_count)) +#print("Data size: %i (%i frames)" % (data_size, frame_count)) frames = [] # Wake-up ping frame frames.append(pr.make_ping_frame(PLID, pp16, 400)) -print("Generating frames...") - # Parameters frame frame = pr.make_mcu_frame(PLID, 0x05) pr.append_word(frame, data_size // 8) # Total byte count for group diff --git a/tools_python/tx.py b/tools_python/tx.py index 3a8fd55..703477a 100644 --- a/tools_python/tx.py +++ b/tools_python/tx.py @@ -49,6 +49,12 @@ def search_esl_blaster(): result[0] = comport return result + +def show_progress(i, total, size, repeats, pp16): + if repeats > 100: + print("Transmitting wake-up frames, please wait...") # Lots of repeats certainly means this is a wake-up frame + else: + print("Transmitting frame %u/%u using %s, length %u, repeated %u times." % (i, total, "PP16" if pp16 else "PP4", size, repeats), end="\r", flush=True) def transmit_serial(frames, port): ser = serial.Serial(port, 57600, timeout = 10) # 10s timeout for read @@ -58,9 +64,9 @@ def transmit_serial(frames, port): for fr in frames: data_size = len(fr) - 2 repeats = fr[-2] + (fr[-1] * 256) - if repeats > 255: # Cap to one byte for the simple serial transmitter - repeats = 255 - print("Transmitting frame %u/%u, length %u, repeated %u times." % (i, frame_count, data_size, repeats)) + if repeats > 255: + repeats = 255 # Cap to one byte for the simple serial transmitter + show_progress(i, frame_count, data_size, repeats, 0) ba = bytearray() ba.append(data_size) @@ -72,7 +78,7 @@ def transmit_serial(frames, port): ser.flush() ser.read_until('A') i += 1 - + print("") ser.close() def transmit_esl_blaster(frames, pp16, port): @@ -88,10 +94,13 @@ def transmit_esl_blaster(frames, pp16, port): data_size = len(fr) - 2 repeats = fr[-2] + (fr[-1] * 256) - if repeats > 32767: # Cap to 15 bits because FW V2 uses bit 16 to indicate PP16 protocol - repeats = 32767 - - print("Transmitting frame %u/%u using %s, length %u, repeated %u times." % (i, frame_count, "PP16" if pp16 else "PP4", data_size, repeats)) + if repeats > 32767: + repeats = 32767 # Cap to 15 bits because FW V2 uses bit 16 to indicate PP16 protocol + #if repeats > 100: + # print("Transmitting wake-up frames, please wait...") # Lots of repeats certainly means this is a wake-up frame + #else: + # print("Transmitting frame %u/%u using %s, length %u, repeated %u times." % (i, frame_count, "PP16" if pp16 else "PP4", data_size, repeats), end="\r", flush=True) + show_progress(i, frame_count, data_size, repeats, pp16) if pp16: repeats |= 0x8000 @@ -99,7 +108,7 @@ def transmit_esl_blaster(frames, pp16, port): ba = bytearray() ba.append(76) # L:Load ba.append(data_size) - ba.append(30) # 30*50 = 1500 timer ticks between repeats + ba.append(10) # 30*50 = 1500 timer ticks between repeats ba.append(repeats & 255) ba.append((repeats // 256) & 255) for b in range(0, data_size): @@ -115,5 +124,5 @@ def transmit_esl_blaster(frames, pp16, port): ser.flush() ser.read_until(b'K') # Wait for transmit done i += 1 - + print("") ser.close()