Compare commits
19 Commits
Author | SHA1 | Date |
---|---|---|
Sylvain PILLOT | 883ca77167 | |
Sylvain PILLOT | 8574824b31 | |
Sylvain PILLOT | 45b207b150 | |
Sylvain PILLOT | a3aa537e84 | |
Lephenixnoir | 4c307af02b | |
Lephenixnoir | 2acc439ed4 | |
Lephenixnoir | 8030d6bdc6 | |
Lephenixnoir | 4a84bfdcd4 | |
Lephenixnoir | 6e62fb7d6d | |
Lephenixnoir | 975f29a471 | |
Lephenixnoir | da79a6a0e8 | |
Lephenixnoir | ecf04cb634 | |
Lephenixnoir | 45fd52444f | |
Lephenixnoir | 9f4d17ca4f | |
Lephenixnoir | 8f50f7694a | |
Lephenixnoir | 88235041a3 | |
Lephenixnoir | be8c1f0d94 | |
Lephenixnoir | 11e3b614c2 | |
Lephenixnoir | cf3ab5d5e0 |
|
@ -0,0 +1,4 @@
|
|||
PREFIX=$HOME/.local make -f giteapc.make configure
|
||||
sudo make -C build install
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ When TYPE is specified (one-shot conversion), it should be one of:
|
|||
--libimg-image Convert to the libimg image format
|
||||
--custom Use a custom converter; you might want to specify an explicit
|
||||
type by adding "custom-type:your_custom_type" (see below)
|
||||
Custom converters can be specified by:
|
||||
--converters Semicolon-separated list of custom converters (converters.py
|
||||
in the current directory is detected as one per legacy)
|
||||
|
||||
|
@ -31,8 +32,13 @@ syntax (names can contain dots). For example:
|
|||
fxconv -f myfont.png -o myfont.o charset:ascii grid.padding:1 height:7
|
||||
|
||||
Some formats differ between platforms so you should specify it when possible:
|
||||
--fx Casio fx-9860G family (black-and-white calculators)
|
||||
--cg Casio fx-CG 50 family (16-bit color calculators)
|
||||
--fx CASIO fx-9860G family (black-and-white calculators)
|
||||
--cg CASIO fx-CG 50 family (16-bit color calculators)
|
||||
|
||||
Finally, there is some support (non-final) for PythonExtra, in which case the
|
||||
output file is as Python file instead of an object file.
|
||||
--py Convert for PythonExtra (some types supported)
|
||||
--py-compact Use compact bytes notation (shorter, but non-printable)
|
||||
""".strip()
|
||||
|
||||
# Simple error-warnings system
|
||||
|
@ -60,6 +66,7 @@ def main():
|
|||
target = { 'toolchain': None, 'arch': None, 'section': None }
|
||||
use_custom = False
|
||||
converter_paths = []
|
||||
py = { 'enabled': False, 'compact': False }
|
||||
|
||||
# Parse command-line arguments
|
||||
|
||||
|
@ -69,7 +76,7 @@ def main():
|
|||
|
||||
try:
|
||||
longs = ["help", "output=", "toolchain=", "arch=", "section=", "fx",
|
||||
"cg", "converters="] + types.split()
|
||||
"cg", "converters=", "py", "py-compact"] + types.split()
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], "hsbifo:", longs)
|
||||
except getopt.GetoptError as error:
|
||||
return err(error)
|
||||
|
@ -94,6 +101,10 @@ def main():
|
|||
mode = "custom"
|
||||
elif name == "--converters":
|
||||
converter_paths = [path for path in value.split(";") if path]
|
||||
elif name == "--py":
|
||||
py['enabled'] = True
|
||||
elif name == "--py-compact":
|
||||
py['compact'] = True
|
||||
# Other names are modes
|
||||
else:
|
||||
mode = name[1] if len(name)==2 else name[2:]
|
||||
|
@ -144,6 +155,7 @@ def main():
|
|||
spec.loader.exec_module(module)
|
||||
converters.append(module.convert)
|
||||
|
||||
params["py"] = py
|
||||
fxconv.convert(input, params, target, output, model, converters)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
200
fxconv/fxconv.py
200
fxconv/fxconv.py
|
@ -15,7 +15,7 @@ __all__ = [
|
|||
# Color names
|
||||
"FX_BLACK", "FX_DARK", "FX_LIGHT", "FX_WHITE", "FX_ALPHA",
|
||||
# Conversion mechanisms
|
||||
"ObjectData", "u8", "u16", "u32", "ref", "sym",
|
||||
"ObjectData", "u8", "u16", "u32", "i8", "i16", "i32", "ref", "sym",
|
||||
# Functions
|
||||
"quantize", "convert", "elf",
|
||||
# Reusable classes
|
||||
|
@ -69,7 +69,7 @@ FX_PROFILES = [
|
|||
FxProfile(0x0, "mono", { FX_BLACK, FX_WHITE }, [
|
||||
lambda c: (c == FX_BLACK),
|
||||
]),
|
||||
# Black-and-white with transparency, equivalent of two bitmaps in ML
|
||||
# Black-and-white with transparency, equivalent of two bitmaps in ML
|
||||
FxProfile(0x1, "mono_alpha", { FX_BLACK, FX_WHITE, FX_ALPHA }, [
|
||||
lambda c: (c != FX_ALPHA),
|
||||
lambda c: (c == FX_BLACK),
|
||||
|
@ -159,7 +159,7 @@ FX_CHARSETS = {
|
|||
"ascii": [ (0x00, 128) ],
|
||||
# Custom Unicode block intervals
|
||||
"unicode": [],
|
||||
# Single block 0x00-0xff (does not imply single-byte encoding)
|
||||
# Single block 0x00-0xff (does not imply single-byte encoding)
|
||||
"256chars": [ (0x00, 256) ],
|
||||
}
|
||||
|
||||
|
@ -167,21 +167,40 @@ FX_CHARSETS = {
|
|||
# Conversion mechanisms
|
||||
#
|
||||
|
||||
def u8(x):
|
||||
return bytes([ x & 255 ])
|
||||
def u16(x):
|
||||
return bytes([ (x >> 8) & 255, x & 255 ])
|
||||
def u32(x):
|
||||
return bytes([ (x >> 24) & 255, (x >> 16) & 255, (x >> 8) & 255, x & 255 ])
|
||||
def u8(x, check=False):
|
||||
if check and not (0 <= x < 2**8):
|
||||
raise FxconvError(f"integer {x} out of range for u8")
|
||||
return bytes([ x & 255 ])
|
||||
def u16(x, check=False):
|
||||
if check and not (0 <= x < 2**16):
|
||||
raise FxconvError(f"integer {x} out of range for u16")
|
||||
return bytes([ (x >> 8) & 255, x & 255 ])
|
||||
def u32(x, check=False):
|
||||
if check and not (0 <= x < 2**32):
|
||||
raise FxconvError(f"integer {x} out of range for u32")
|
||||
return bytes([ (x >> 24) & 255, (x >> 16) & 255, (x >> 8) & 255, x & 255 ])
|
||||
|
||||
def ref(base, offset=None, padding=None, prefix_underscore=True):
|
||||
def i8(x, check=True):
|
||||
if check and not (-2**7 <= x < 2**7):
|
||||
raise FxconvError(f"integer {x} out of range for i8")
|
||||
return bytes([ x & 255 ])
|
||||
def i16(x, check=True):
|
||||
if check and not (-2**15 <= x < 2**15):
|
||||
raise FxconvError(f"integer {x} out of range for i16")
|
||||
return bytes([ (x >> 8) & 255, x & 255 ])
|
||||
def i32(x, check=True):
|
||||
if check and not (-2**31 <= x < 2**31):
|
||||
raise FxconvError(f"integer {x} out of range for i32")
|
||||
return bytes([ (x >> 24) & 255, (x >> 16) & 255, (x >> 8) & 255, x & 255 ])
|
||||
|
||||
def ref(base, offset=None, padding=None, prefix_underscore=True, align=None):
|
||||
if isinstance(base, bytes) or isinstance(base, bytearray):
|
||||
base = bytes(base)
|
||||
if offset is not None:
|
||||
raise FxconvError(f"reference to bytes does not allow offset")
|
||||
if padding and len(base) % padding != 0:
|
||||
base += bytes(padding - len(base) % padding)
|
||||
return Ref("bytes", base)
|
||||
return Ref("bytes", base, align or 4)
|
||||
|
||||
elif isinstance(base, str):
|
||||
if padding is not None:
|
||||
|
@ -191,19 +210,24 @@ def ref(base, offset=None, padding=None, prefix_underscore=True):
|
|||
if offset is not None:
|
||||
offset = int(offset)
|
||||
base = f"{base} + {offset}"
|
||||
return Ref("name", base)
|
||||
return Ref("name", base, align or 4)
|
||||
|
||||
elif isinstance(base, ObjectData):
|
||||
if offset is not None or padding is not None:
|
||||
raise FxconvError("reference to structure does not allow offset " +
|
||||
"or padding")
|
||||
return Ref("struct", base)
|
||||
if offset is not None:
|
||||
raise FxconvError("reference to structure does not allow offset")
|
||||
if padding is not None:
|
||||
raise FxconvError("reference to structure does not allow padding")
|
||||
# Allow over-aligning the structure (but not more than 4)
|
||||
align = max(base.alignment, align or 4)
|
||||
if align > 4:
|
||||
raise FxconvError(f"align {align} > 4 will not be honored (yet)")
|
||||
return Ref("struct", base, align)
|
||||
|
||||
else:
|
||||
raise FxconvError(f"invalid type {type(base)} for ref()")
|
||||
|
||||
def ptr(base):
|
||||
return ref(base)
|
||||
def ptr(*args, **kwargs):
|
||||
return ref(*args, **kwargs)
|
||||
|
||||
def chars(text, length, require_final_nul=True):
|
||||
btext = bytes(text, 'utf-8')
|
||||
|
@ -221,7 +245,7 @@ def sym(name):
|
|||
# "bytes" -> target is a bytes(), we point to that data
|
||||
# "name" -> target is an str like "_sym+2", we point to that
|
||||
# "struct" -> target is an ObjectData
|
||||
Ref = collections.namedtuple("Ref", ["kind", "target"])
|
||||
Ref = collections.namedtuple("Ref", ["kind", "target", "align"])
|
||||
|
||||
Sym = collections.namedtuple("Sym", ["name"])
|
||||
|
||||
|
@ -250,7 +274,7 @@ class ObjectData:
|
|||
elif isinstance(other, Sym):
|
||||
self.inner.append(other)
|
||||
elif isinstance(other, ObjectData):
|
||||
self.inner.append(other)
|
||||
self.inner += other.inner
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
|
@ -273,34 +297,23 @@ class ObjectData:
|
|||
return padding
|
||||
|
||||
def link(self, symbol):
|
||||
inner = []
|
||||
inner = self.inner
|
||||
outer = []
|
||||
elements = []
|
||||
size = 0
|
||||
|
||||
# First unfold all structures within [inner] as we accumulate the total
|
||||
# size of the inner data
|
||||
for el in self.inner:
|
||||
if isinstance(el, ObjectData):
|
||||
size += self.align(size, el.alignment, inner)
|
||||
code, code_size = el.link(f"{symbol} + {size}")
|
||||
inner.append((code, code_size))
|
||||
size += code_size
|
||||
else:
|
||||
inner.append(el)
|
||||
size += self.element_size(el)
|
||||
size = sum(self.element_size(el) for el in inner)
|
||||
|
||||
# Then replace complex references with unfolded data appended at the
|
||||
# end of the structure
|
||||
for el in inner:
|
||||
if isinstance(el, Ref) and el.kind == "bytes":
|
||||
elements.append(Ref("name", f"{symbol} + {size}"))
|
||||
size += self.align(size, el.align, outer)
|
||||
elements.append(Ref("name", f"{symbol} + {size}", None))
|
||||
outer.append(el.target)
|
||||
size += self.element_size(el.target)
|
||||
|
||||
elif isinstance(el, Ref) and el.kind == "struct":
|
||||
size += self.align(size, el.target.alignment, outer)
|
||||
elements.append(Ref("name", f"{symbol} + {size}"))
|
||||
elements.append(Ref("name", f"{symbol} + {size}", None))
|
||||
code, code_size = el.target.link(f"{symbol} + {size}")
|
||||
outer.append((code, code_size))
|
||||
size += code_size
|
||||
|
@ -500,8 +513,16 @@ def convert_bopti_fx(input, params):
|
|||
data[n] = layer[4 * longword + i]
|
||||
n += 1
|
||||
|
||||
if params["py"]["enabled"]:
|
||||
w, h = img.size
|
||||
return ["import gint\n",
|
||||
f"{params['name']} = gint.image({p.id}, {w}, {h}, ", data, ")\n"]
|
||||
|
||||
# Generate the object file
|
||||
return header + data
|
||||
o = ObjectData()
|
||||
o += header
|
||||
o += ptr(data)
|
||||
return o
|
||||
|
||||
def _image_project(img, f):
|
||||
# New width and height
|
||||
|
@ -581,6 +602,17 @@ def convert_image_cg(input, params):
|
|||
|
||||
data, stride, palette, color_count = image_encode(img, format)
|
||||
|
||||
if params["py"]["enabled"]:
|
||||
w, h = img.size
|
||||
return [
|
||||
"import gint\n",
|
||||
f"{params['name']} = gint.image({format.id}, {color_count}, ",
|
||||
f"{img.width}, {img.height}, {stride}, ",
|
||||
data,
|
||||
", ",
|
||||
"None" if palette is None else palette,
|
||||
")\n"]
|
||||
|
||||
o = ObjectData()
|
||||
o += u8(format.id)
|
||||
o += u8(3) # DATA_RO, PALETTE_RO
|
||||
|
@ -775,6 +807,19 @@ def convert_topti(input, params):
|
|||
# Object file generation
|
||||
#---
|
||||
|
||||
if params["py"]["enabled"]:
|
||||
l = [ "import gint\n",
|
||||
f"{params['name']} = gint.font({title or None}, {flags}, ",
|
||||
f"{line_height}, {grid.h}, {len(blocks)}, {glyph_count}, ",
|
||||
f"{char_spacing}, ",
|
||||
data_blocks,
|
||||
data_glyphs ]
|
||||
if proportional:
|
||||
l += [data_index, data_width]
|
||||
else:
|
||||
l += [f"{grid.w}, {(grid.w * grid.h + 31) >> 5}"]
|
||||
return l + [")\n"]
|
||||
|
||||
# Base data: always put the raw data and blocks first since they are
|
||||
# 4-aligned, to preserve alignment on the rest of the references.
|
||||
o = ObjectData()
|
||||
|
@ -1139,8 +1184,14 @@ def convert(input, params, target, output=None, model=None, custom=None):
|
|||
else:
|
||||
raise FxconvError(f'unknown resource type \'{t}\'')
|
||||
|
||||
# PythonExtra conversion: output a file
|
||||
if params["py"]["enabled"]:
|
||||
if isinstance(o, ObjectData):
|
||||
raise FxconvError(f'conversion doe not support Python output')
|
||||
pyout(o, output, params)
|
||||
# Standard conversions: save to ELF in the natural way
|
||||
elf(o, output, "_" + params["name"], **target)
|
||||
else:
|
||||
elf(o, output, "_" + params["name"], **target)
|
||||
|
||||
def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
||||
assembly=None):
|
||||
|
@ -1154,9 +1205,9 @@ def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
|||
The symbol name must have a leading underscore if it is to be declared and
|
||||
used from a C program.
|
||||
|
||||
The toolchain can be any target triplet for which the compiler is
|
||||
available. The architecture is deduced from some typical triplets;
|
||||
otherwise it can be set, usually as "sh3" or "sh4-nofpu". This affects the
|
||||
The toolchain can be any target triplet for which the compiler is
|
||||
available. The architecture is deduced from some typical triplets;
|
||||
otherwise it can be set, usually as "sh3" or "sh4-nofpu". This affects the
|
||||
--binary-architecture flag of objcopy. If arch is set to "fx" or "cg", this
|
||||
function tries to be smart and:
|
||||
|
||||
|
@ -1186,6 +1237,14 @@ def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
|||
Produces an output file and returns nothing.
|
||||
"""
|
||||
|
||||
# Unfold ObjectData into data and assembly
|
||||
if isinstance(data, ObjectData):
|
||||
assembly = f".global {symbol}\n" + \
|
||||
f"{symbol}:\n" + \
|
||||
data.link(symbol)[0] + \
|
||||
(assembly or "")
|
||||
data = None
|
||||
|
||||
# Toolchain parameters
|
||||
|
||||
if toolchain is None:
|
||||
|
@ -1206,16 +1265,9 @@ def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
|||
raise FxconvError(f"non-trivial architecture for {toolchain} must be "+
|
||||
"specified")
|
||||
|
||||
# Unfold ObjectData into data and assembly
|
||||
if isinstance(data, ObjectData):
|
||||
asm = ".section " + section.split(",",1)[0] + "\n"
|
||||
asm += f".global {symbol}\n"
|
||||
asm += f"{symbol}:\n"
|
||||
asm += data.link(symbol)[0]
|
||||
asm += (assembly or "")
|
||||
|
||||
data = None
|
||||
assembly = asm
|
||||
if assembly:
|
||||
sec = ".section " + section.split(",",1)[0]
|
||||
assembly = sec + "\n" + assembly
|
||||
|
||||
if data is None and assembly is None:
|
||||
raise FxconvError("elf() but no data and no assembly")
|
||||
|
@ -1275,6 +1327,52 @@ def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
|||
if assembly:
|
||||
fp_asm.close()
|
||||
|
||||
def elf_multi(vars, output, assembly=None, **kwargs):
|
||||
"""
|
||||
Like elf(), but instead of one symbol/data pair, allows defining multiple
|
||||
variables. vars should be a list [(symbol, ObjectData), ...]. Keyword
|
||||
arguments are passed to elf().
|
||||
"""
|
||||
|
||||
asm = ""
|
||||
for symbol, objdata in vars:
|
||||
asm += f".global {symbol}\n"
|
||||
asm += f"{symbol}:\n"
|
||||
asm += objdata.link(symbol)[0]
|
||||
asm += assembly or ""
|
||||
|
||||
return elf(None, output, None, assembly=asm, **kwargs)
|
||||
|
||||
def pyout(bits, output, params):
|
||||
# Compact into byte strings to avoid building tuples in the heap;
|
||||
# MicroPython allows basically anything in literal strings (including
|
||||
# NUL!), we just have to escape \, \n, \r, and ".
|
||||
def byteify(c):
|
||||
if c == ord('"'):
|
||||
return b'\\"'
|
||||
if c == ord('\n'):
|
||||
return b'\\n'
|
||||
if c == ord('\r'):
|
||||
return b'\\r'
|
||||
if c == ord('\\'):
|
||||
return b'\\\\'
|
||||
return bytes([c])
|
||||
|
||||
with open(output, "wb") as fp:
|
||||
for section in bits:
|
||||
if isinstance(section, bytearray):
|
||||
section = bytes(section)
|
||||
if isinstance(section, bytes):
|
||||
if params["py"]["compact"]:
|
||||
fp.write(b'b"')
|
||||
for byte in section:
|
||||
fp.write(byteify(byte))
|
||||
fp.write(b'"')
|
||||
else:
|
||||
fp.write(repr(section).encode("utf-8"))
|
||||
else:
|
||||
fp.write(section.encode("utf-8"))
|
||||
|
||||
#
|
||||
# Meta API
|
||||
#
|
||||
|
|
|
@ -28,7 +28,8 @@ int main_list(struct fxlink_filter *filter, delay_t *delay,
|
|||
int main_blocks(struct fxlink_filter *filter, delay_t *delay);
|
||||
|
||||
/* Main function for -s */
|
||||
int main_send(struct fxlink_filter *filter, delay_t *delay, char **files);
|
||||
int main_send(struct fxlink_filter *filter, delay_t *delay, char **files,
|
||||
char *outfolder);
|
||||
|
||||
/* Main function for -i */
|
||||
int main_interactive(struct fxlink_filter *filter, delay_t *delay,
|
||||
|
|
|
@ -20,7 +20,7 @@ static const char *help_string =
|
|||
"usage: %1$s (-l|-b|-t) [General options]\n"
|
||||
" %1$s -i [-r] [--fxlink-log[=<FILE>]] [General options]\n"
|
||||
" %1$s -p <FILE> [General options]\n"
|
||||
" %1$s -s <FILES>... [General options]\n"
|
||||
" %1$s -s <FILES>... [--folder=OUTFOLDER] [General options]\n"
|
||||
"\n"
|
||||
"fxlink interacts with CASIO calculators of the fx and fx-CG families over\n"
|
||||
"the USB port, using libusb. It can also transfer files for Mass Storage\n"
|
||||
|
@ -47,6 +47,7 @@ static const char *help_string =
|
|||
" --fxlink-log[=FILE] -i: Append fxlink text messages to FILE. Without\n"
|
||||
" argument, a unique name is generated.\n"
|
||||
" -r, --repeat -i: Reconnect if the calc disconnects (implies -w)\n"
|
||||
" --folder=FOLDER -s: Select destination folder for files\n"
|
||||
"\n"
|
||||
"Device filters:\n"
|
||||
" A device filter narrows down what devices we list or connect to by\n"
|
||||
|
@ -67,6 +68,7 @@ int main(int argc, char **argv)
|
|||
delay_t delay = delay_seconds(0);
|
||||
struct fxlink_filter *filter = NULL;
|
||||
bool repeat = false;
|
||||
char *outfolder = NULL;
|
||||
|
||||
options.log_file = NULL;
|
||||
options.verbose = false;
|
||||
|
@ -77,7 +79,7 @@ int main(int argc, char **argv)
|
|||
// Command-line argument parsing
|
||||
//---
|
||||
|
||||
enum { LIBUSB_LOG=1, LOG_TO_FILE=2 };
|
||||
enum { LIBUSB_LOG=1, LOG_TO_FILE=2, OUT_FOLDER=3 };
|
||||
const struct option longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "list", no_argument, NULL, 'l' },
|
||||
|
@ -90,6 +92,7 @@ int main(int argc, char **argv)
|
|||
{ "fxlink-log", optional_argument, NULL, LOG_TO_FILE },
|
||||
{ "repeat", no_argument, NULL, 'r' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "folder", required_argument, NULL, OUT_FOLDER },
|
||||
/* Deprecated options ignored for compatibility: */
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "unmount", no_argument, NULL, 'u' },
|
||||
|
@ -165,6 +168,9 @@ int main(int argc, char **argv)
|
|||
case 'f':
|
||||
filter = fxlink_filter_parse(optarg);
|
||||
break;
|
||||
case OUT_FOLDER:
|
||||
outfolder = strdup(optarg);
|
||||
break;
|
||||
case '?':
|
||||
error = 1;
|
||||
}
|
||||
|
@ -219,7 +225,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
else if(mode == 's') {
|
||||
#ifndef FXLINK_DISABLE_UDISKS2
|
||||
rc = main_send(filter, &delay, argv + optind);
|
||||
rc = main_send(filter, &delay, argv + optind, outfolder);
|
||||
#else
|
||||
rc = elog("this fxlink was built without UDisks2; -s is disabled");
|
||||
#endif
|
||||
|
|
|
@ -44,11 +44,13 @@ static void handle_new_message(struct fxlink_device *fdev,
|
|||
if(options.verbose)
|
||||
printf("------------------\n");
|
||||
fwrite(str, 1, msg->size, stdout);
|
||||
#if 0
|
||||
if(str[msg->size - 1] != '\n') {
|
||||
if(!options.verbose)
|
||||
printf("\e[30;47m%%\e[0m");
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
if(options.verbose) {
|
||||
printf("------------------\n");
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main_send(struct fxlink_filter *filter, delay_t *delay, char **files)
|
||||
int main_send(struct fxlink_filter *filter, delay_t *delay, char **files,
|
||||
char *outfolder)
|
||||
{
|
||||
fxlink_filter_clean_udisks2(filter);
|
||||
GError *error = NULL;
|
||||
|
@ -53,10 +54,14 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files)
|
|||
printf("Mounted %s to %s.\n", dev, folder);
|
||||
}
|
||||
else {
|
||||
folder = strdup(mount_points[0]);
|
||||
folder = mount_points[0];
|
||||
printf("Already mounted at %s.\n", folder);
|
||||
}
|
||||
|
||||
gchar *outpath = folder;
|
||||
if(outfolder)
|
||||
asprintf(&outpath, "%s/%s/", folder, outfolder);
|
||||
|
||||
/* Copy files with external cp(1) */
|
||||
int file_count = 0;
|
||||
while(files[file_count]) file_count++;
|
||||
|
@ -69,7 +74,7 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files)
|
|||
argv[0] = "cp";
|
||||
for(int i = 0; files[i]; i++)
|
||||
argv[i+1] = files[i];
|
||||
argv[file_count+1] = folder;
|
||||
argv[file_count+1] = outpath;
|
||||
argv[file_count+2] = NULL;
|
||||
|
||||
/* Print command */
|
||||
|
@ -97,6 +102,9 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files)
|
|||
}
|
||||
}
|
||||
|
||||
if(outfolder)
|
||||
free(outpath);
|
||||
|
||||
/* Unmount the filesystem and eject the device */
|
||||
GVariant *args = g_variant_new("a{sv}", NULL);
|
||||
udisks_filesystem_call_unmount_sync(fs, args, NULL, &error);
|
||||
|
@ -113,7 +121,6 @@ int main_send(struct fxlink_filter *filter, delay_t *delay, char **files)
|
|||
printf("Ejected %s.\n", dev);
|
||||
|
||||
end:
|
||||
free(folder);
|
||||
if(argv) free(argv);
|
||||
if(fs) g_object_unref(fs);
|
||||
if(drive) g_object_unref(drive);
|
||||
|
|
|
@ -46,18 +46,31 @@ static void quit(void)
|
|||
|
||||
/* Generate an RGB888 surface from image data. */
|
||||
static SDL_Surface *surface_for_image(uint8_t **RGB888_rows, int width,
|
||||
int height)
|
||||
int height, int scale)
|
||||
{
|
||||
/* Little endian setup for RGB */
|
||||
SDL_Surface *s = SDL_CreateRGBSurface(0, width, height, 24,
|
||||
SDL_Surface *s = SDL_CreateRGBSurface(0, width*scale, height*scale, 24,
|
||||
0x000000ff, 0x0000ff00, 0x0000ff00, 0);
|
||||
if(!s) {
|
||||
elog("cannot create surface for image\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(int i = 0; i < height; i++)
|
||||
memcpy(s->pixels + i * s->pitch, RGB888_rows[i], width * 3);
|
||||
for(int y = 0; y < height; y++) {
|
||||
for(int dy = 0; dy < scale; dy++) {
|
||||
uint8_t *src = RGB888_rows[y];
|
||||
uint8_t *dst = s->pixels + (y*scale+dy) * s->pitch;
|
||||
for(int x = 0; x < width; x++) {
|
||||
for(int dx = 0; dx < scale; dx++) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst += 3;
|
||||
}
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -68,11 +81,14 @@ void fxlink_sdl2_display_raw(struct fxlink_message_image_raw const *raw)
|
|||
return;
|
||||
|
||||
int current_w, current_h;
|
||||
SDL_GetWindowSize(window, ¤t_w, ¤t_h);
|
||||
if(current_w != raw->width || current_h != raw->height)
|
||||
SDL_SetWindowSize(window, raw->width, raw->height);
|
||||
int scale = 1;
|
||||
|
||||
SDL_Surface *src = surface_for_image(raw->data, raw->width, raw->height);
|
||||
SDL_GetWindowSize(window, ¤t_w, ¤t_h);
|
||||
if(current_w != raw->width * scale || current_h != raw->height * scale)
|
||||
SDL_SetWindowSize(window, raw->width * scale, raw->height * scale);
|
||||
|
||||
SDL_Surface *src =
|
||||
surface_for_image(raw->data, raw->width, raw->height, scale);
|
||||
if(!src)
|
||||
return;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
|||
|
||||
add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(myaddin PRIVATE -Wall -Wextra -Os)
|
||||
target_link_options(myaddin PRIVATE -Wl,-Map=Build_Addin.map -Wl,--print-memory-usage)
|
||||
target_link_libraries(myaddin Gint::Gint)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
|
@ -38,4 +39,7 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
|||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
generate_g3a(TARGET myaddin OUTPUT "MyAddin.g3a"
|
||||
NAME "MyAddin" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_AS_CG)
|
||||
generate_g3a(TARGET myaddin OUTPUT "MyAddin.g3a"
|
||||
NAME "MyAddin" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# fxSDK toolchain file for Casio graphing calculators
|
||||
# Models: Prizm fx-CG 10, fx-CG 20, fx-CG 50, fx-CG 50 emulator
|
||||
# Target triplet: sh-elf (custom sh3eb-elf supporting sh3 and sh4-nofpu)
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_VERSION 1)
|
||||
set(CMAKE_SYSTEM_PROCESSOR sh)
|
||||
|
||||
# Base plateform is fx to pick the assets for the fx9860G
|
||||
set(FXSDK_PLATFORM fx)
|
||||
# the long name is change to be able to separate in CMakeLists.txt the different targets
|
||||
set(FXSDK_PLATFORM_LONG fx9860G_AS_CG)
|
||||
|
||||
set(FXSDK_TOOLCHAIN sh-elf-)
|
||||
set(CMAKE_C_COMPILER sh-elf-gcc)
|
||||
set(CMAKE_CXX_COMPILER sh-elf-g++)
|
||||
|
||||
set(CMAKE_C_FLAGS_INIT "")
|
||||
set(CMAKE_CXX_FLAGS_INIT "")
|
||||
|
||||
add_compile_options(-m4-nofpu -mb -ffreestanding -nostdlib -Wa,--dsp -DFXCG50)
|
||||
add_link_options(-nostdlib -Wl,--no-warn-rwx-segments)
|
||||
link_libraries(-lgcc)
|
||||
add_compile_definitions(TARGET_FXCG50)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
set(FXSDK_CMAKE_MODULE_PATH "${FXSDK_CMAKE_MODULE_PATH}")
|
||||
|
||||
# Add the fxSDK prefix path to the search
|
||||
set(FXSDK_PREFIX "$ENV{FXSDK_PREFIX}")
|
||||
foreach(DIR IN LISTS FXSDK_PREFIX)
|
||||
include_directories("${DIR}/include")
|
||||
link_directories("${DIR}/lib")
|
||||
endforeach()
|
||||
|
||||
# Determine compiler install path
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} --print-file-name=.
|
||||
OUTPUT_VARIABLE FXSDK_COMPILER_INSTALL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
# Provide fxSDK sysroot and standard install folders
|
||||
execute_process(
|
||||
COMMAND fxsdk path sysroot
|
||||
OUTPUT_VARIABLE FXSDK_SYSROOT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND fxsdk path include
|
||||
OUTPUT_VARIABLE FXSDK_INCLUDE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND fxsdk path lib
|
||||
OUTPUT_VARIABLE FXSDK_LIB
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
@ -21,6 +21,10 @@ add_link_options(-nostdlib -Wl,--no-warn-rwx-segments)
|
|||
link_libraries(-lgcc)
|
||||
add_compile_definitions(TARGET_FXCG50)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL FastLoad)
|
||||
add_compile_definitions(TARGET_FXCG50_FASTLOAD)
|
||||
endif()
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
|
|
@ -41,6 +41,14 @@ ${R}fxsdk${n} ${R}build-cg-push${n} [${R}-c${n}] [${R}-s${n}] [${R}--${n}] \
|
|||
are identical to other build commands. Typical workflows will always set -s
|
||||
(which requires libusb support in fxlink).
|
||||
|
||||
${R}fxsdk${n} ${R}build-fxascg${n} [${R}-c${n}] [${R}-s${n}] [${R}--${n}] \
|
||||
[${g}<ARGS>${n}...]
|
||||
Builds the current project for fx-CG 50 from a code source initially
|
||||
targetting the fx-9860G(II). It will generate a .g3a add-in in lieu of a .g1a
|
||||
add-in. Upscaling of the screen will be performed to accomodate the higher
|
||||
resolution of the screen of the fx-CG 50 (396x224px) instead of one of the
|
||||
fx-9860G (128x64px).
|
||||
|
||||
${R}fxsdk${n} (${R}send${n}|${R}send-fx${n}|${R}send-cg${n})
|
||||
Sends the target file to the calculator. Uses p7 (which must be installed
|
||||
externally) for the fx-9860G, and fxlink for the fx-CG. For the G-III series,
|
||||
|
@ -127,7 +135,10 @@ fxsdk_new_project() {
|
|||
cp "$assets"/icon-cg-sel.png "$1"/assets-cg/icon-sel.png
|
||||
|
||||
echo "Created a new project $NAME (build system: $generator)."
|
||||
echo "Type 'fxsdk build-fx' or 'fxsdk build-cg' to compile the program."
|
||||
echo "Type 'fxsdk build-fx' or 'fxsdk build-cg' or 'fxsdk build-fxascg'"
|
||||
echo "to compile the program."
|
||||
echo "Type 'fxsdk build-cg-push' to compile a bin to be send to"
|
||||
echo "Add-In Push by circuit10"
|
||||
}
|
||||
|
||||
fxsdk_load_config() {
|
||||
|
@ -138,7 +149,7 @@ fxsdk_load_config() {
|
|||
|
||||
|
||||
fxsdk_build() {
|
||||
[[ ! -e build-fx && ! -e build-cg ]]
|
||||
[[ ! -e build-fx && ! -e build-cg && ! -e build-fxascg ]]
|
||||
none_exists=$?
|
||||
|
||||
if [[ -e build-fx || $none_exists == 0 ]]; then
|
||||
|
@ -150,6 +161,11 @@ fxsdk_build() {
|
|||
echo "$TAG Making into build-cg"
|
||||
fxsdk_build_cg "$@"
|
||||
fi
|
||||
|
||||
if [[ -e build-fxascg || $none_exists == 0 ]]; then
|
||||
echo "$TAG Making into build-fxascg"
|
||||
fxsdk_build_fxascg "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
fxsdk_build_fx() {
|
||||
|
@ -161,6 +177,9 @@ fxsdk_build_cg() {
|
|||
fxsdk_build_cg_push() {
|
||||
fxsdk_build_in "cg-push" "FXCG50" "$@"
|
||||
}
|
||||
fxsdk_build_fxascg() {
|
||||
fxsdk_build_in "fxascg" "FX9860G_AS_CG" "$@"
|
||||
}
|
||||
|
||||
fxsdk_build_in() {
|
||||
platform="$1"
|
||||
|
@ -222,16 +241,20 @@ fxsdk_build_in() {
|
|||
}
|
||||
|
||||
fxsdk_send() {
|
||||
if [[ -e "build-fx" && ! -e "build-cg" ]]; then
|
||||
if [[ -e "build-fx" && ! -e "build-cg" && ! -e "build-fxascg" ]]; then
|
||||
fxsdk_send_fx
|
||||
fi
|
||||
|
||||
if [[ -e "build-cg" && ! -e "build-fx" ]]; then
|
||||
if [[ -e "build-cg" && ! -e "build-fx" && ! -e "build-fxascg" ]]; then
|
||||
fxsdk_send_cg
|
||||
fi
|
||||
|
||||
if [[ -e "build-fxascg" && ! -e "build-fx" && ! -e "build-cg" ]]; then
|
||||
fxsdk_send_fxascg
|
||||
fi
|
||||
|
||||
echo "either no or several platforms are targeted, use 'fxsdk send-fx' or"
|
||||
echo "fxsdk 'send-cg' to specify which calculator to send to."
|
||||
echo "'fxsdk send-cg' or 'fxsdk send-fxascg' to specify which calculator to send to."
|
||||
}
|
||||
|
||||
fxsdk_send_fx() {
|
||||
|
@ -267,6 +290,18 @@ fxsdk_send_cg-push() {
|
|||
fxlink -pw ${bin_files}
|
||||
}
|
||||
|
||||
fxsdk_send_fxascg() {
|
||||
echo "$TAG Installing for fx-CG using fxlink"
|
||||
if ! command -v fxlink >/dev/null 2>&1; then
|
||||
echo "error: fxlink is not installed or not available"
|
||||
return 1
|
||||
fi
|
||||
g3a_files=$(find -maxdepth 1 -name '*.g3a')
|
||||
echo "$TAG Running: fxlink -sw ${g3a_files}"
|
||||
fxlink -sw ${g3a_files}
|
||||
}
|
||||
|
||||
|
||||
fxsdk_path() {
|
||||
case "$1" in
|
||||
"sysroot")
|
||||
|
@ -300,6 +335,8 @@ case "$1" in
|
|||
fxsdk_build_cg "${@:2}";;
|
||||
"build-cg-push"|"bcgp")
|
||||
fxsdk_build_cg_push "${@:2}";;
|
||||
"build-fxascg"|"bfxcg"|"bfcg")
|
||||
fxsdk_build_fxascg "${@:2}";;
|
||||
|
||||
# Install
|
||||
"send"|"s")
|
||||
|
@ -308,6 +345,8 @@ case "$1" in
|
|||
fxsdk_send_fx;;
|
||||
"send-cg"|"sc"|"scg")
|
||||
fxsdk_send_cg;;
|
||||
"send-fxascg"|"sfxcg"|"sfcg")
|
||||
fxsdk_send_fxascg;;
|
||||
|
||||
# Utilities
|
||||
"path")
|
||||
|
|
Loading…
Reference in New Issue