TS101 rework for Miniware DFU (#44)

* Refactor output to allow turning hex duplication on/off

* Rough out being able to merge image files & firmware files

* Update output_hex.py

* Update TS101 to require merge

* Remove TS101 from CI

* .

* add py3-intelhex

* Update img2logo.py
This commit is contained in:
Ben V. Brown
2024-08-22 12:08:36 +10:00
committed by GitHub
parent 853b20eabc
commit d695535fd4
6 changed files with 229 additions and 144 deletions

View File

@@ -14,13 +14,12 @@ jobs:
- model: "pinecilv1" - model: "pinecilv1"
- model: "pinecilv2" - model: "pinecilv2"
- model: "mhp30" - model: "mhp30"
- model: "ts101"
- model: "s60" - model: "s60"
fail-fast: true fail-fast: true
steps: steps:
- name: Install dependencies (apk) - name: Install dependencies (apk)
run: apk add --no-cache git python3 py3-pip zlib py3-pillow run: apk add --no-cache git python3 py3-pip zlib py3-pillow py3-intelhex
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:

View File

@@ -1,69 +1,63 @@
--- ---
name: "release" name: "release"
on: on:
push: push:
branches: branches:
- "main" - "main"
jobs: jobs:
release: release:
name: "Release" name: "Release"
runs-on: "ubuntu-22.04" runs-on: "ubuntu-22.04"
steps: steps:
- name: Install dependencies (apk) - name: Install dependencies (apk)
run: sudo apt update && sudo apt-get install -y git python3 python3-pillow run: sudo apt update && sudo apt-get install -y git python3 python3-pillow py3-intelhex
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: prep - name: prep
run: | run: |
mkdir -p /tmp/pinecilv1 && \ mkdir -p /tmp/pinecilv1 && \
mkdir -p /tmp/pinecilv2 && \ mkdir -p /tmp/pinecilv2 && \
mkdir -p /tmp/miniware && \ mkdir -p /tmp/miniware && \
mkdir -p /tmp/ts101 && \ mkdir -p /tmp/mhp30 && \
mkdir -p /tmp/mhp30 && \ mkdir -p /tmp/s60
mkdir -p /tmp/s60
- name: build all files for the device - name: build all files for the device
run: | run: |
cd Bootup\ Logos && \ cd Bootup\ Logos && \
./run.sh /tmp/pinecilv1/ -m pinecilv1 && \ ./run.sh /tmp/pinecilv1/ -m pinecilv1 && \
./run.sh /tmp/pinecilv2/ -m pinecilv2 && \ ./run.sh /tmp/pinecilv2/ -m pinecilv2 && \
./run.sh /tmp/miniware/ -m miniware && \ ./run.sh /tmp/miniware/ -m miniware && \
./run.sh /tmp/ts101/ -m ts101 && \ ./run.sh /tmp/mhp30/ -m mhp30 && \
./run.sh /tmp/mhp30/ -m mhp30 && \ ./run.sh /tmp/s60/ -m s60
./run.sh /tmp/s60/ -m s60
- name: build logo erase file - name: build logo erase file
run: | run: |
cd Bootup\ Logos && \ cd Bootup\ Logos && \
python3 img2logo.py -E erase_stored_image /tmp/pinecilv1/ -m pinecilv1 && \ python3 img2logo.py -E erase_stored_image /tmp/pinecilv1/ -m pinecilv1 && \
python3 img2logo.py -E erase_stored_image /tmp/pinecilv2/ -m pinecilv2 && \ python3 img2logo.py -E erase_stored_image /tmp/pinecilv2/ -m pinecilv2 && \
python3 img2logo.py -E erase_stored_image /tmp/miniware/ -m miniware && \ python3 img2logo.py -E erase_stored_image /tmp/miniware/ -m miniware && \
python3 img2logo.py -E erase_stored_image /tmp/ts101/ -m ts101 && \ python3 img2logo.py -E erase_stored_image /tmp/mhp30/ -m mhp30 && \
python3 img2logo.py -E erase_stored_image /tmp/mhp30/ -m mhp30 && \ python3 img2logo.py -E erase_stored_image /tmp/s60/ -m s60
python3 img2logo.py -E erase_stored_image /tmp/s60/ -m s60
- name: compress logo files
run: |
zip -rj pinecilv1.zip /tmp/pinecilv1/* && \
zip -rj miniware.zip /tmp/miniware/* && \
zip -rj pinecilv2.zip /tmp/pinecilv2/* && \
zip -rj mhp30.zip /tmp/mhp30/* && \
zip -rj s60_s60p.zip /tmp/s60/*
- name: compress logo files - uses: "marvinpinto/action-automatic-releases@latest"
run: | with:
zip -rj pinecilv1.zip /tmp/pinecilv1/* && \ repo_token: "${{ secrets.GITHUB_TOKEN }}"
zip -rj miniware.zip /tmp/miniware/* && \ automatic_release_tag: "latest"
zip -rj pinecilv2.zip /tmp/pinecilv2/* && \ prerelease: false
zip -rj ts101.zip /tmp/ts101/* && \ title: "Release"
zip -rj mhp30.zip /tmp/mhp30/* && \ files: |
zip -rj s60_s60p.zip /tmp/s60/* *.zip
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: false
title: "Release"
files: |
*.zip

View File

@@ -4,14 +4,19 @@ from __future__ import division
import argparse import argparse
import copy import copy
import os, sys import os, sys
from typing import Optional
from intelhex import IntelHex
from output_hex import HexOutput from output_hex import HexOutput
from output_dfu import DFUOutput from output_dfu import DFUOutput
try: try:
from PIL import Image, ImageOps from PIL import Image, ImageOps
except ImportError as error: except ImportError as error:
raise ImportError("{}: {} requres Python Imaging Library (PIL). " "Install with `pip` (pip3 install pillow) or OS-specific package " "management tool.".format(error, sys.argv[0])) raise ImportError(
"{}: {} requres Python Imaging Library (PIL). "
"Install with `pip` (pip3 install pillow) or OS-specific package "
"management tool.".format(error, sys.argv[0])
)
VERSION_STRING = "1.0" VERSION_STRING = "1.0"
@@ -22,58 +27,73 @@ LCD_PAGE_SIZE = 1024
DATA_PROGRAMMED_MARKER = 0xAA DATA_PROGRAMMED_MARKER = 0xAA
FULL_FRAME_MARKER = 0xFF FULL_FRAME_MARKER = 0xFF
EMPTY_FRAME_MARKER = 0xFE # If this marker is used to start a frame, the frame is a 0-length delta frame EMPTY_FRAME_MARKER = (
0xFE # If this marker is used to start a frame, the frame is a 0-length delta frame
)
class MiniwareSettings: class MiniwareSettings:
IMAGE_ADDRESS = 0x0800F800 IMAGE_ADDRESS = 0x0800F800
DFU_TARGET_NAME = b"IronOS-dfu" DFU_TARGET_NAME = b"IronOS-dfu"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x1209 DFU_VENDOR = 0x1209
DFU_PINECIL_PRODUCT = 0xDB42 DFU_PRODUCT = 0xDB42
MINIMUM_HEX_SIZE = 4096
class S60Settings: class S60Settings:
IMAGE_ADDRESS = 0x08000000 + (62 * 1024) IMAGE_ADDRESS = 0x08000000 + (62 * 1024)
DFU_TARGET_NAME = b"IronOS-dfu" DFU_TARGET_NAME = b"IronOS-dfu"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x1209 DFU_VENDOR = 0x1209
DFU_PINECIL_PRODUCT = 0xDB42 DFU_PRODUCT = 0xDB42
MINIMUM_HEX_SIZE = 1024
class TS101Settings: class TS101Settings:
IMAGE_ADDRESS = 0x08000000 + (126 * 1024) IMAGE_ADDRESS = 0x08000000 + (99 * 1024)
DFU_TARGET_NAME = b"IronOS-dfu" DFU_TARGET_NAME = b"IronOS-dfu"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x1209 DFU_VENDOR = 0x1209
DFU_PINECIL_PRODUCT = 0xDB42 DFU_PRODUCT = 0xDB42
MINIMUM_HEX_SIZE = 1024
class MHP30Settings: class MHP30Settings:
IMAGE_ADDRESS = 0x08000000 + (126 * 1024) IMAGE_ADDRESS = 0x08000000 + (126 * 1024)
DFU_TARGET_NAME = b"IronOS-dfu" DFU_TARGET_NAME = b"IronOS-dfu"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x1209 DFU_VENDOR = 0x1209
DFU_PINECIL_PRODUCT = 0xDB42 DFU_PRODUCT = 0xDB42
MINIMUM_HEX_SIZE = 4096
class PinecilSettings: class PinecilSettings:
IMAGE_ADDRESS = 0x0801F800 IMAGE_ADDRESS = 0x0801F800
DFU_TARGET_NAME = b"Pinecil" DFU_TARGET_NAME = b"Pinecil"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x28E9 DFU_VENDOR = 0x28E9
DFU_PINECIL_PRODUCT = 0x0189 DFU_PRODUCT = 0x0189
MINIMUM_HEX_SIZE = 1024
class Pinecilv2Settings:
IMAGE_ADDRESS = (1016 * 1024) # its 2 4k erase pages inset class Pinecilv2Settings:
IMAGE_ADDRESS = 1016 * 1024 # its 2 4k erase pages inset
DFU_TARGET_NAME = b"Pinecilv2" DFU_TARGET_NAME = b"Pinecilv2"
DFU_PINECIL_ALT = 0 DFU_ALT = 0
DFU_PINECIL_VENDOR = 0x28E9 # These are ignored by blisp so doesnt matter what we use DFU_VENDOR = 0x28E9 # These are ignored by blisp so doesnt matter what we use
DFU_PINECIL_PRODUCT = 0x0189 # These are ignored by blisp so doesnt matter what we use DFU_PRODUCT = 0x0189 # These are ignored by blisp so doesnt matter what we use
MINIMUM_HEX_SIZE = 1024
def still_image_to_bytes(image: Image, negative: bool, dither: bool, threshold: int, preview_filename): def still_image_to_bytes(
image: Image, negative: bool, dither: bool, threshold: int, preview_filename
):
# convert to luminance # convert to luminance
# do even if already black/white because PIL can't invert 1-bit so # do even if already black/white because PIL can't invert 1-bit so
# can't just pass thru in case --negative flag # can't just pass thru in case --negative flag
# also resizing works better in luminance than black/white # also resizing works better in luminance than black/white
# also no information loss converting black/white to grayscale # also no information loss converting black/white to greyscale
if image.mode != "L": if image.mode != "L":
image = image.convert("L") image = image.convert("L")
# Resize to lcd size using bicubic sampling # Resize to lcd size using bicubic sampling
@@ -144,7 +164,9 @@ def get_screen_blob(previous_frame: bytearray, this_frame: bytearray):
return outputData return outputData
def animated_image_to_bytes(imageIn: Image, negative: bool, dither: bool, threshold: int, flip_frames): def animated_image_to_bytes(
imageIn: Image, negative: bool, dither: bool, threshold: int, flip_frames
):
""" """
Convert the gif into our best effort startup animation Convert the gif into our best effort startup animation
We are delta-encoding on a byte by byte basis We are delta-encoding on a byte by byte basis
@@ -175,7 +197,9 @@ def animated_image_to_bytes(imageIn: Image, negative: bool, dither: bool, thresh
else: else:
delta = frameDuration_ms / frameTiming delta = frameDuration_ms / frameTiming
if delta > 1.05 or delta < 0.95: if delta > 1.05 or delta < 0.95:
print(f"ERROR: You have a frame that is different to the first frame time. Mixed rates are not supported") print(
f"ERROR: You have a frame that is different to the first frame time. Mixed rates are not supported"
)
sys.exit(-1) sys.exit(-1)
print(f"Found {len(frameData)} frames, interval {frameTiming}ms") print(f"Found {len(frameData)} frames, interval {frameTiming}ms")
frameTiming = frameTiming / 5 frameTiming = frameTiming / 5
@@ -183,7 +207,9 @@ def animated_image_to_bytes(imageIn: Image, negative: bool, dither: bool, thresh
newTiming = max(frameTiming, 1) newTiming = max(frameTiming, 1)
newTiming = min(newTiming, 254) newTiming = min(newTiming, 254)
print(f"Inter frame delay {frameTiming} is out of range, and is being adjusted to {newTiming*5}") print(
f"Inter frame delay {frameTiming} is out of range, and is being adjusted to {newTiming*5}"
)
frameTiming = newTiming frameTiming = newTiming
# We have now mangled the image into our framebuffers # We have now mangled the image into our framebuffers
@@ -217,7 +243,8 @@ def animated_image_to_bytes(imageIn: Image, negative: bool, dither: bool, thresh
def img2hex( def img2hex(
input_filename, input_filename,
device_model_name:str, device_model_name: str,
merge_hex_file: Optional[str],
preview_filename=None, preview_filename=None,
threshold=128, threshold=128,
dither=False, dither=False,
@@ -229,13 +256,13 @@ def img2hex(
""" """
Convert 'input_filename' image file into Intel hex format with data Convert 'input_filename' image file into Intel hex format with data
formatted for display on LCD and file object. formatted for display on LCD and file object.
Input image is converted from color or grayscale to black-and-white, Input image is converted from color or greyscale to black-and-white,
and resized to fit LCD screen as necessary. and resized to fit LCD screen as necessary.
Optionally write resized/thresholded/black-and-white preview image Optionally write resized/thresholded/black-and-white preview image
to file specified by name. to file specified by name.
Optional `threshold' argument 8 bit value; grayscale pixels greater than Optional `threshold' argument 8 bit value; greyscale pixels greater than
this become 1 (white) in output, less than become 0 (black). this become 1 (white) in output, less than become 0 (black).
Unless optional `dither', in which case PIL grayscale-to-black/white Unless optional `dither', in which case PIL greyscale-to-black/white
dithering algorithm used. dithering algorithm used.
Optional `negative' inverts black/white regardless of input image type Optional `negative' inverts black/white regardless of input image type
or other options. or other options.
@@ -249,13 +276,15 @@ def img2hex(
raise IOError('error reading image file "{}": {}'.format(input_filename, e)) raise IOError('error reading image file "{}": {}'.format(input_filename, e))
if getattr(image, "is_animated", False): if getattr(image, "is_animated", False):
data = animated_image_to_bytes(image, negative, dither, threshold,flip) data = animated_image_to_bytes(image, negative, dither, threshold, flip)
else: else:
if flip: if flip:
image = image.rotate(180) image = image.rotate(180)
# magic/required header # magic/required header
data = [DATA_PROGRAMMED_MARKER, 0x00] # Timing value of 0 data = [DATA_PROGRAMMED_MARKER, 0x00] # Timing value of 0
image_bytes = still_image_to_bytes(image, negative, dither, threshold, preview_filename) image_bytes = still_image_to_bytes(
image, negative, dither, threshold, preview_filename
)
data.extend(get_screen_blob([0] * LCD_NUM_BYTES, image_bytes)) data.extend(get_screen_blob([0] * LCD_NUM_BYTES, image_bytes))
# Pad up to the full page size # Pad up to the full page size
@@ -265,7 +294,12 @@ def img2hex(
# Set device settings depending on input `-m` argument # Set device settings depending on input `-m` argument
device_name = device_model_name.lower() device_name = device_model_name.lower()
if device_name == "miniware" or device_name == "ts100" or device_name == "ts80" or device_name == "ts80p": if (
device_name == "miniware"
or device_name == "ts100"
or device_name == "ts80"
or device_name == "ts80p"
):
deviceSettings = MiniwareSettings deviceSettings = MiniwareSettings
elif device_name == "pinecilv1" or device_name == "pinecil": elif device_name == "pinecilv1" or device_name == "pinecil":
deviceSettings = PinecilSettings deviceSettings = PinecilSettings
@@ -273,6 +307,11 @@ def img2hex(
deviceSettings = Pinecilv2Settings deviceSettings = Pinecilv2Settings
elif device_name == "ts101": elif device_name == "ts101":
deviceSettings = TS101Settings deviceSettings = TS101Settings
if merge_hex_file is None:
print(
"For the TS101 for compatibility with bugs in the Miniware Loader, you must merge the main firmware with the logo to flash it"
)
exit(1)
elif device_name == "s60": elif device_name == "s60":
deviceSettings = S60Settings deviceSettings = S60Settings
elif device_name == "mhp30": elif device_name == "mhp30":
@@ -282,25 +321,75 @@ def img2hex(
sys.exit(-1) sys.exit(-1)
# Split name from extension so we can mangle in the _L suffix for flipped images # Split name from extension so we can mangle in the _L suffix for flipped images
split_name = os.path.splitext( os.path.basename(input_filename)) split_name = os.path.splitext(os.path.basename(input_filename))
if flip: if flip:
base = split_name[0] base = split_name[0]
ext = split_name[1] ext = split_name[1]
base =base+"_L" base = base + "_L"
split_name = [base,ext] split_name = [base, ext]
output_name = output_filename_base +split_name[0] +split_name[1] output_name = output_filename_base + split_name[0] + split_name[1]
DFUOutput.writeFile( # If a file has been specified for merging, we want to splice our image data with it
output_name + ".dfu", if merge_hex_file is not None:
data, read_merge_write(merge_hex_file, data, deviceSettings, output_name)
deviceSettings.IMAGE_ADDRESS, else:
deviceSettings.DFU_TARGET_NAME, DFUOutput.writeFile(
deviceSettings.DFU_PINECIL_ALT, output_name + ".dfu",
deviceSettings.DFU_PINECIL_PRODUCT, data,
deviceSettings.DFU_PINECIL_VENDOR, deviceSettings.IMAGE_ADDRESS,
deviceSettings.DFU_TARGET_NAME,
deviceSettings.DFU_ALT,
deviceSettings.DFU_PRODUCT,
deviceSettings.DFU_VENDOR,
)
HexOutput.writeFile(
output_name + ".hex",
data,
deviceSettings.IMAGE_ADDRESS,
deviceSettings.MINIMUM_HEX_SIZE,
)
def read_merge_write(
merge_filename: str, image_data: list[int], deviceSettings, output_filename: str
):
"""
Reads in the merge filename as the base object, then inserts the image data.
Then pad-fills the empty space in the binary
"""
base_hex_file = IntelHex(merge_filename)
logo_hex_file = IntelHex()
logo_hex_file.frombytes(image_data, deviceSettings.IMAGE_ADDRESS)
# Merge in the image data, error if collision
base_hex_file.merge(logo_hex_file, overlap="error")
binary_base = base_hex_file.minaddr()
base_hex_file.padding = 0xFF
binary_blob = base_hex_file.tobinarray(start=binary_base)
print(
f"Post-merge output image starts at 0x{binary_base:x}, len {len(binary_blob)}"
) )
HexOutput.writeFile(output_name + ".hex", data, deviceSettings.IMAGE_ADDRESS) DFUOutput.writeFile(
output_filename + ".dfu",
binary_blob,
binary_base,
deviceSettings.DFU_TARGET_NAME,
deviceSettings.DFU_ALT,
deviceSettings.DFU_PRODUCT,
deviceSettings.DFU_VENDOR,
)
# Gap fill any missing segments
# This is required for the TS101 bootloader
segments = base_hex_file.segments()
for seg_pair in zip(segments, segments[1:]):
start = seg_pair[0][1]
end = seg_pair[1][0]
filler = [0xFE] * (end - start)
base_hex_file.frombytes(filler, start)
with open(output_filename + ".hex", "w") as output:
base_hex_file.write_hex_file(output, eolstyle="CRLF")
def parse_commandline(): def parse_commandline():
@@ -325,6 +414,12 @@ def parse_commandline():
help="filename of image preview", help="filename of image preview",
) )
parser.add_argument(
"-M",
"--merge",
help="filename of another hex file to merge with, creating a combined firmware",
)
parser.add_argument( parser.add_argument(
"-n", "-n",
"--negative", "--negative",
@@ -332,20 +427,21 @@ def parse_commandline():
help="photo negative: exchange black and white in output", help="photo negative: exchange black and white in output",
) )
parser.add_argument( parser.add_argument(
"-t", "-t",
"--threshold", "--threshold",
type=zero_to_255, type=zero_to_255,
default=128, default=128,
help="0 to 255: gray (or color converted to gray) " "above this becomes white, below becomes black; " "ignored if using --dither", help="0 to 255: grey (or color converted to grey) "
"above this becomes white, below becomes black; "
"ignored if using --dither",
) )
parser.add_argument( parser.add_argument(
"-d", "-d",
"--dither", "--dither",
action="store_true", action="store_true",
help="use dithering (speckling) to convert gray or " "color to black and white", help="use dithering (speckling) to convert grey or " "color to black and white",
) )
parser.add_argument( parser.add_argument(
@@ -355,7 +451,7 @@ def parse_commandline():
help="generate a logo erase file instead of a logo", help="generate a logo erase file instead of a logo",
) )
parser.add_argument("-m", "--model", help="device model name") parser.add_argument("-m", "--model", help="device model name")
parser.add_argument( parser.add_argument(
"-v", "-v",
"--version", "--version",
@@ -372,14 +468,16 @@ if __name__ == "__main__":
args = parse_commandline() args = parse_commandline()
if args.preview and os.path.exists(args.preview) and not args.force: if args.preview and os.path.exists(args.preview) and not args.force:
sys.stderr.write('Won\'t overwrite existing file "{}" (use --force ' "option to override)\n".format(args.preview)) sys.stderr.write(
'Won\'t overwrite existing file "{}" (use --force '
"option to override)\n".format(args.preview)
)
sys.exit(1) sys.exit(1)
print(f"Converting {args.input_filename} => {args.output_filename}") print(f"Converting {args.input_filename} => {args.output_filename}")
img2hex( img2hex(
merge_hex_file=args.merge,
input_filename=args.input_filename, input_filename=args.input_filename,
output_filename_base=args.output_filename, output_filename_base=args.output_filename,
device_model_name=args.model, device_model_name=args.model,
@@ -388,10 +486,11 @@ if __name__ == "__main__":
dither=args.dither, dither=args.dither,
negative=args.negative, negative=args.negative,
make_erase_image=args.erase, make_erase_image=args.erase,
flip = False, flip=False,
) )
img2hex( img2hex(
merge_hex_file=args.merge,
input_filename=args.input_filename, input_filename=args.input_filename,
output_filename_base=args.output_filename, output_filename_base=args.output_filename,
device_model_name=args.model, device_model_name=args.model,
@@ -400,5 +499,5 @@ if __name__ == "__main__":
dither=args.dither, dither=args.dither,
negative=args.negative, negative=args.negative,
make_erase_image=args.erase, make_erase_image=args.erase,
flip = True, flip=True,
) )

View File

@@ -10,7 +10,6 @@ class HexOutput:
INTELHEX_END_OF_FILE_RECORD = 0x01 INTELHEX_END_OF_FILE_RECORD = 0x01
INTELHEX_EXTENDED_LINEAR_ADDRESS_RECORD = 0x04 INTELHEX_EXTENDED_LINEAR_ADDRESS_RECORD = 0x04
INTELHEX_BYTES_PER_LINE = 16 INTELHEX_BYTES_PER_LINE = 16
INTELHEX_MINIMUM_SIZE = 4096
@classmethod @classmethod
def split16(cls, word): def split16(cls, word):
@@ -53,20 +52,19 @@ class HexOutput:
) # low 8 bits ) # low 8 bits
@classmethod @classmethod
def writeFile(cls, file_name: str, data: bytearray, data_address: int): def writeFile(
cls,
file_name: str,
data: bytearray,
data_address: int,
minimum_hex_file_size: int,
):
"""write block of data in Intel hex format""" """write block of data in Intel hex format"""
with open(file_name, "w", newline="\r\n") as output: with open(file_name, "w", newline="\r\n") as output:
def write(generator): def write(generator):
output.write("".join(generator)) output.write("".join(generator))
if len(data) % cls.INTELHEX_BYTES_PER_LINE != 0:
raise ValueError(
"Program error: Size of LCD data is not evenly divisible by {}".format(
cls.INTELHEX_BYTES_PER_LINE
)
)
address_lo = data_address & 0xFFFF address_lo = data_address & 0xFFFF
address_hi = (data_address >> 16) & 0xFFFF address_hi = (data_address >> 16) & 0xFFFF
@@ -79,7 +77,7 @@ class HexOutput:
) )
size_written = 0 size_written = 0
while size_written < cls.INTELHEX_MINIMUM_SIZE: while size_written < minimum_hex_file_size:
offset = address_lo offset = address_lo
for line_start in range(0, len(data), cls.INTELHEX_BYTES_PER_LINE): for line_start in range(0, len(data), cls.INTELHEX_BYTES_PER_LINE):
write( write(
@@ -90,8 +88,6 @@ class HexOutput:
) )
) )
size_written += cls.INTELHEX_BYTES_PER_LINE size_written += cls.INTELHEX_BYTES_PER_LINE
if size_written >= cls.INTELHEX_MINIMUM_SIZE:
break
offset += cls.INTELHEX_BYTES_PER_LINE offset += cls.INTELHEX_BYTES_PER_LINE
write(cls.intel_hex_line(cls.INTELHEX_END_OF_FILE_RECORD, 0, ())) write(cls.intel_hex_line(cls.INTELHEX_END_OF_FILE_RECORD, 0, ()))

View File

@@ -1 +0,0 @@

View File

@@ -7,7 +7,6 @@ This includes photographs of hardware, datasheets, schematics, original propriet
This repository uses github actions to automagically build the logos for each device. This repository uses github actions to automagically build the logos for each device.
Periodically a "release" will be tagged and pre-compiled logo's will be put there as well to make it easy. Periodically a "release" will be tagged and pre-compiled logo's will be put there as well to make it easy.
# Boot-Up Logos # Boot-Up Logos
The IronOS firmware supports a user created bootup logo. The IronOS firmware supports a user created bootup logo.
@@ -22,4 +21,3 @@ There are community logo's already converted and ready to use in [IronOS-Meta/re
Download the zip for Pinecil or Miniware and then install using the instructions on the [main IronOS documentation](https://ralim.github.io/IronOS/Logo/). Download the zip for Pinecil or Miniware and then install using the instructions on the [main IronOS documentation](https://ralim.github.io/IronOS/Logo/).
Alternatively if you want to make your own logo files, there is also documentation on how best to do this in the [main IronOS documentation](https://ralim.github.io/IronOS/Logo/). Alternatively if you want to make your own logo files, there is also documentation on how best to do this in the [main IronOS documentation](https://ralim.github.io/IronOS/Logo/).