First commit : p7utils-v3.0.0
|
@ -0,0 +1,2 @@
|
|||
# p7utils authors
|
||||
Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <<thomas@touhey.fr>>
|
|
@ -0,0 +1,336 @@
|
|||
GNU General Public License
|
||||
==========================
|
||||
|
||||
_Version 2, June 1991_
|
||||
_Copyright © 1989, 1991 Free Software Foundation, Inc.,_
|
||||
_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
### Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: **(1)** copyright the software, and
|
||||
**(2)** offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
**0.** This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The “Program”, below,
|
||||
refers to any such program or work, and a “work based on the Program”
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term “modification”.) Each licensee is addressed as “you”.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
**1.** You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
**2.** You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
* **a)** You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
* **b)** You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
* **c)** If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
**3.** You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
* **a)** Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
* **b)** Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
* **c)** Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
**4.** You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
**5.** You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
**6.** Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
**7.** If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
**8.** If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
**9.** The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and “any
|
||||
later version”, you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
**10.** If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
### NO WARRANTY
|
||||
|
||||
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
### How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the “copyright” line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w` and `show c` should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w` and `show c`; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a “copyright disclaimer” for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,243 @@
|
|||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Include variables and message subsystem #
|
||||
#******************************************************************************#
|
||||
include Makefile.vars Makefile.msg
|
||||
|
||||
# Check if we're a git repository
|
||||
ISGIT := $(shell test -e .git && echo y)
|
||||
|
||||
#******************************************************************************#
|
||||
# General targets #
|
||||
#******************************************************************************#
|
||||
# Make it all
|
||||
all: all-bins
|
||||
|
||||
# Mostly clean
|
||||
mostlyclean: mostlyclean-bins
|
||||
mclean: mostlyclean
|
||||
|
||||
# Clean it all
|
||||
clean: clean-bins clean-doc
|
||||
fclean: clean
|
||||
|
||||
# Clean it entirely
|
||||
mrproper: clean
|
||||
$(call rmsg,Removing configuration.)
|
||||
$(call qcmd,$(RM) Makefile.cfg)
|
||||
$(call qcmd,$(RM) $(NAME)-*)
|
||||
|
||||
# Remake it all
|
||||
re: clean all
|
||||
|
||||
# Install it all
|
||||
install: install-bins
|
||||
|
||||
# Uninstall it all
|
||||
uninstall: uninstall-bins
|
||||
|
||||
# Reinstall it all
|
||||
reinstall: uninstall install
|
||||
|
||||
# Make dist
|
||||
dist: mrproper $(if $(ISGIT),reinit-gitmodules)
|
||||
$(call bcmd,mkdir,$(NAME)-$(VERSION),\
|
||||
$(MD) .dist)
|
||||
$(call bcmd,cp,* $(NAME)-$(VERSION),\
|
||||
cp -R * .dist)
|
||||
$(call qcmd,\
|
||||
mv .dist $(NAME)-$(VERSION))
|
||||
$(call bcmd,tarball,$(NAME)-$(VERSION),\
|
||||
tar czf $(NAME)-$(VERSION).tar.gz \
|
||||
--exclude .git $(NAME)-$(VERSION))
|
||||
$(call qcmd,$(RM) -r $(NAME)-$(VERSION))
|
||||
|
||||
.PHONY: all mostlyclean mclean clean fclean mrproper re
|
||||
.PHONY: dist install uninstall reinstall
|
||||
#******************************************************************************#
|
||||
# Git submodules #
|
||||
#******************************************************************************#
|
||||
# Main rule.
|
||||
reinit-gitmodules:
|
||||
$(call qcmd,git submodule deinit -- \
|
||||
$(shell grep path .gitmodules | sed 's/.*= //'))
|
||||
$(call qcmd,git submodule update --init --recursive)
|
||||
|
||||
# Initialize one module
|
||||
ifeq ($(ISGIT),y)
|
||||
define check-gitmodule
|
||||
-$(call qcmd,git submodule update --init --quiet $1)
|
||||
endef
|
||||
else
|
||||
define check-gitmodule
|
||||
@true
|
||||
endef
|
||||
endif
|
||||
|
||||
.PHONY: reinit-gitmodules
|
||||
#******************************************************************************#
|
||||
# Configuration (version) checking dependencies #
|
||||
#******************************************************************************#
|
||||
# Define the dependencies.
|
||||
CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \
|
||||
$(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \
|
||||
check-config-version))
|
||||
|
||||
# Define the rules.
|
||||
check-config:
|
||||
@printf "\033[1;31mNo configuration file found!\n"
|
||||
@printf "You should configure before re-running this target.\033[0m\n"
|
||||
@false
|
||||
check-config-version:
|
||||
@printf "\033[1;31mConfiguration version is incorrect!\n"
|
||||
@printf "You should re-configure before re-running this target.\033[0m\n"
|
||||
@false
|
||||
|
||||
.PHONY: check-config check-config-version
|
||||
#******************************************************************************#
|
||||
# Information getting from the Makefile variables #
|
||||
#******************************************************************************#
|
||||
# Get the project name.
|
||||
getname:
|
||||
@echo "$(NAME)"
|
||||
|
||||
# Get the project version.
|
||||
getversion:
|
||||
@echo "$(VERSION)"
|
||||
|
||||
# Get the project author.
|
||||
getmaintainer:
|
||||
@echo "$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>"
|
||||
|
||||
.PHONY: getname getmaintainer getversion
|
||||
#******************************************************************************#
|
||||
# Binaries-specific targets #
|
||||
#******************************************************************************#
|
||||
# Make the binaries.
|
||||
all-bins: $(CHECKCFG) $(DEFAULT_BINARIES:%=all-%)
|
||||
|
||||
# Make a binary object directory.
|
||||
$(BINARIES:%=$(OBJDIR)/%):
|
||||
$(call bcmd,mkdir,$@,$(MD) $@)
|
||||
|
||||
# Make an object out of a source file/directory.
|
||||
define make-binaryobj-rule
|
||||
ifeq ($(shell test -f $(SRCDIR)/$1/$2.c && echo y),y)
|
||||
# - Out of a C source file
|
||||
$(OBJDIR)/$1/$2.o: $(SRCDIR)/$1/$2.c | $(OBJDIR)/$1
|
||||
$(call bcmd,cc,$$@,$(CC) -c -o $$@ $$< $(CFLAGS_$1))
|
||||
else
|
||||
# - Out of an update.exe project
|
||||
$(SRCDIR)/$1/$2.exe/$2.exe.bin:| $(SRCDIR)/$1/$2.exe
|
||||
$(call check-gitmodule,$(SRCDIR)/$1/$2.exe)
|
||||
$(if $(shell test -f $(SRCDIR)/$1/$2.exe/configure \
|
||||
&& test -x $(SRCDIR)/$1/$2.exe/configure && echo y), \
|
||||
$(call qcmd,cd $(SRCDIR)/$1/$2.exe && ./configure 1>/dev/null))
|
||||
$(call bcmd,make,$2.exe,$(MAKE) -C $(SRCDIR)/$1/$2.exe $2.exe.bin \
|
||||
| sed -e 's/^/ /')
|
||||
|
||||
$(OBJDIR)/$1/$2.o: $(SRCDIR)/$1/$2.exe/$2.exe.bin | $(OBJDIR)/$1
|
||||
$(call bcmd,ld -r,$$@,cd $(SRCDIR)/$1/$2.exe && \
|
||||
$(LDR) -o ../../../$$@ -b binary $2.exe.bin)
|
||||
endif
|
||||
endef
|
||||
$(foreach bin,$(BINARIES),\
|
||||
$(foreach obj,$(SRC_$(bin)),\
|
||||
$(eval $(call make-binaryobj-rule,$(bin),$(obj)))))
|
||||
|
||||
# Make a binary
|
||||
define make-binary-rules
|
||||
$1$(if $(FOR_WINDOWS),.exe): $(SRC_$1:%=$(OBJDIR)/$1/%.o) | $(OBJDIR)/$1
|
||||
$(call bcmd,ld,$$@,$(LD) -o $$@ $$^ $(LDFLAGS_$1))
|
||||
all-$1 all-$1.exe: $(CHECKCFG) $1$(if $(FOR_WINDOWS),.exe) all-doc-$1
|
||||
|
||||
clean-$1 clean-$1.exe:
|
||||
$(call rmsg,Removing $1 and its objects directory.)
|
||||
$(call qcmd,$(RM) -r $(OBJDIR)/$1)
|
||||
$(call qcmd,$(RM) $1$(if $(FOR_WINDOWS),.exe))
|
||||
re-$1 re-$1.exe: clean-$1 all-$1
|
||||
endef
|
||||
$(foreach bin,$(BINARIES),\
|
||||
$(eval $(call make-binary-rules,$(bin))))
|
||||
|
||||
# Remove object files.
|
||||
mostlyclean-bins:
|
||||
$(call rmsg,Removing objects directory.)
|
||||
$(call qcmd,$(RM) -r $(OBJDIR))
|
||||
mclean-bins: mostlyclean-bins
|
||||
|
||||
# Clean and remove binaries.
|
||||
clean-bins: mostlyclean-bins
|
||||
$(call rmsg,Removing binaries.)
|
||||
$(call qcmd,$(RM) $(BINARIES:%=%*))
|
||||
|
||||
# Remake binaries
|
||||
re-bins: clean-bins all-bins
|
||||
|
||||
# Install a binary
|
||||
define make-installbinary-rule
|
||||
install-$1 install-$1.exe: $(CHECKCFG) \
|
||||
all-$1 $(if $(INSTALL_MANPAGES),install-doc-$1)
|
||||
$(call imsg,Installing $1$(if $(FOR_WINDOWS),.exe).)
|
||||
$(call qcmd,$(INSTALL) -m 755 -d "$(IBINDIR)")
|
||||
$(call qcmd,$(INSTALL) -m 755 -t "$(IBINDIR)" $1$(if $(FOR_WINDOWS),.exe))
|
||||
|
||||
uninstall-$1 uninstall-$1.exe: $(CHECKCFG) uninstall-doc-$1
|
||||
$(call rmsg,Uninstalling $1)
|
||||
$(call qcmd,$(RM) "$(IBINDIR)/$1"{,.exe})
|
||||
endef
|
||||
$(foreach bin,$(BINARIES),\
|
||||
$(eval $(call make-installbinary-rule,$(bin))))
|
||||
|
||||
# Install binaries
|
||||
install-bins: $(DEFAULT_BINARIES:%=install-%)
|
||||
|
||||
# Uninstall binaries
|
||||
uninstall-bins: $(BINARIES:%=uninstall-%)
|
||||
|
||||
.PHONY: all-bins mostlyclean-bins mclean-bins clean-bins re-bins
|
||||
.PHONY: install-bins uninstall-bins
|
||||
.PHONY: $(foreach b,$(BINARIES),all-$(b) all-$(b).exe \
|
||||
clean-$(b) clean-$(b).exe re-$(b) re-$(b).exe \
|
||||
install-$(b) install-$(b).exe uninstall-$(b) uninstall-$(b).exe)
|
||||
#******************************************************************************#
|
||||
# Documentation-related #
|
||||
#******************************************************************************#
|
||||
# Make manpages directories
|
||||
$(MANDIR)/man1:
|
||||
$(call bcmd,mkdir,$@,$(MD) $@)
|
||||
|
||||
# Make-A-Manpage
|
||||
define make-manpage-rule
|
||||
$(MANDIR)/man1/$1.%: $(DOCDIR)/$1.1.txt | $(MANDIR)/man1
|
||||
$(call bcmd,a2x,$$<,$(A2X) -f manpage -D $$| $$< 2>/dev/null)
|
||||
|
||||
all-doc-$1: $(MANDIR)/man1/$1.1
|
||||
endef
|
||||
$(foreach bin,$(BINARIES),\
|
||||
$(eval $(call make-manpage-rule,$(bin))))
|
||||
|
||||
# Remove all manpages
|
||||
clean-doc:
|
||||
$(call rmsg,Removing manpages directory.)
|
||||
$(call qcmd,$(RM) -r $(MANDIR))
|
||||
|
||||
# Install a manpage.
|
||||
define make-install-manpage-rule
|
||||
install-doc-$1: $(MANDIR)/man1/$1.1
|
||||
$(call imsg,Installing $1 manpage)
|
||||
$(call qcmd,$(INSTALL) -m 755 -d "$(IMANDIR)/man1")
|
||||
$(call qcmd,$(INSTALL) -m 644 -t "$(IMANDIR)/man1" \
|
||||
$(MANDIR)/man1/$1.1)
|
||||
$(call qcmd,$(GZIP) "$(IMANDIR)/man1/$1.1")
|
||||
|
||||
uninstall-doc-$1:
|
||||
$(call rmsg,Removing $1 manpage)
|
||||
$(call qcmd,$(RM) "$(IMANDIR)/man1/$1.1*")
|
||||
endef
|
||||
$(foreach bin,$(BINARIES), \
|
||||
$(eval $(call make-install-manpage-rule,$(bin))))
|
||||
|
||||
.PHONY: $(foreach bin,$(BINARIES),all-doc-$(bin)) clean-doc
|
||||
.PHONY: $(foreach bin,$(BINARIES),install-doc-$(bin) uninstall-doc-$(bin))
|
||||
# End of file.
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/make -f
|
||||
# The Makefile message subsystem.
|
||||
# For nice logs. 5 dollars per log only.
|
||||
#******************************************************************************#
|
||||
# Colors and misc #
|
||||
#******************************************************************************#
|
||||
# Used colors ANSI modifiers escape codes
|
||||
color_green := 32
|
||||
color_red := 31
|
||||
color_yellow := 33
|
||||
|
||||
# Newline - comes handy in some situations
|
||||
define \n
|
||||
|
||||
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# General messages #
|
||||
#******************************************************************************#
|
||||
# Command message - display basic info about the command, and run it.
|
||||
define cmd
|
||||
@$(if $(MAKE_FULL_LOG),,printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";)
|
||||
$(if $(MAKE_FULL_LOG),,@)$3
|
||||
endef
|
||||
|
||||
# Quiet command - make it non-quiet if full log is enabled.
|
||||
define qcmd
|
||||
$(if $(MAKE_FULL_LOG),,@)$1
|
||||
endef
|
||||
|
||||
# Normal message - display it.
|
||||
define msg
|
||||
$(if $(MAKE_FULL_LOG),,@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1")
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# Commands #
|
||||
#******************************************************************************#
|
||||
# Build command
|
||||
define bcmd
|
||||
$(call cmd,$1,$2,$3,$(color_green))
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# Messages #
|
||||
#******************************************************************************#
|
||||
# Remove message
|
||||
define rmsg
|
||||
$(call msg,$1,$(color_red))
|
||||
endef
|
||||
|
||||
# Install message
|
||||
define imsg
|
||||
$(call msg,$1,$(color_yellow))
|
||||
endef
|
||||
|
||||
# End of file
|
|
@ -0,0 +1,155 @@
|
|||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Include configuration #
|
||||
#******************************************************************************#
|
||||
-include Makefile.cfg
|
||||
|
||||
# Correct target
|
||||
TARGET := $(if $(TARGET),$(TARGET)-)
|
||||
|
||||
#******************************************************************************#
|
||||
# Project main information #
|
||||
#******************************************************************************#
|
||||
# Project name.
|
||||
NAME := p7utils
|
||||
|
||||
# Author information.
|
||||
MAINTAINER_NAME := Thomas \"Cakeisalie5\" Touhey
|
||||
MAINTAINER_MAIL := thomas@touhey.fr
|
||||
|
||||
# Project license.
|
||||
LICENSE := GPLv2
|
||||
|
||||
# Project version.
|
||||
MAJOR := 3
|
||||
MINOR := 0
|
||||
INDEV :=
|
||||
|
||||
# Project version string.
|
||||
VERSION := $(MAJOR).$(MINOR)$(if $(INDEV),-indev)
|
||||
|
||||
#******************************************************************************#
|
||||
# Project directories #
|
||||
#******************************************************************************#
|
||||
# Sources directory
|
||||
SRCDIR := ./src
|
||||
|
||||
# Objects directory
|
||||
OBJDIR := ./obj
|
||||
|
||||
# Manpages sources directory
|
||||
DOCDIR := ./doc
|
||||
|
||||
# Manpages directory
|
||||
MANDIR := ./man
|
||||
|
||||
#******************************************************************************#
|
||||
# Binary utilities #
|
||||
#******************************************************************************#
|
||||
# Package configuration
|
||||
PKGCONFIG := $(TARGET)pkg-config
|
||||
|
||||
# C Compiler
|
||||
CC := $(TARGET)gcc
|
||||
# - Check flags (enable warnings)
|
||||
CWARN := -Wall -Wextra -Wno-unused-macros -Wno-vla
|
||||
# - Maintainer flags
|
||||
ifdef MORE_WARNINGS
|
||||
CWERROR := shadow write-strings redundant-decls format format-nonliteral \
|
||||
format-security implicit-function-declaration \
|
||||
date-time missing-prototypes return-type pointer-arith
|
||||
CWARN += $(CWERROR:%=-W%) -Wstack-protector -Wno-unused-parameter
|
||||
endif
|
||||
# - More flags (profiling, ...)
|
||||
#CMOREFLAGS :=
|
||||
# - All C Compiler flags
|
||||
CFLAGS := $(CWARN) -std=gnu11 -O2 -D NAME="$(NAME)" -D VERSION="$(VERSION)" \
|
||||
-D MAINTAINER="$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>" \
|
||||
-D DEFAULT_STORAGE="$(DEFAULT_STORAGE)" \
|
||||
-D DEFAULT_ZOOM="$(DEFAULT_ZOOM)" \
|
||||
$(CMOREFLAGS)
|
||||
|
||||
# Linker
|
||||
LD := $(TARGET)gcc
|
||||
# - Specific linker flags
|
||||
LDFLAGS_Linux := -Wl,-z,relro
|
||||
# - Linker flags
|
||||
LDFLAGS := $(if $(FOR_WINDOWS),,$(LDFLAGS_Linux))
|
||||
|
||||
# Raw ELF object maker
|
||||
LDR := $(TARGET)ld -r
|
||||
|
||||
# Maker
|
||||
MAKE := make --no-print-directory
|
||||
# Directory maker
|
||||
MD := mkdir -p
|
||||
# File remover
|
||||
RM := rm -f
|
||||
# Installer
|
||||
INSTALL := install
|
||||
# Asciidoc
|
||||
A2X := a2x
|
||||
# Gzipper
|
||||
GZIP := gzip -f
|
||||
|
||||
#******************************************************************************#
|
||||
# Binaries and sources #
|
||||
#******************************************************************************#
|
||||
# Look for binaries
|
||||
BINARIES := $(notdir $(shell find $(SRCDIR) -mindepth 1 -maxdepth 1 \
|
||||
-type d | sort))
|
||||
|
||||
# Get their libs
|
||||
define get-binary-libs
|
||||
LIBS_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk libs 2>/dev/null)
|
||||
DISABLE_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk disable 2>/dev/null \
|
||||
&& echo y)
|
||||
endef
|
||||
$(foreach bin,$(BINARIES), \
|
||||
$(eval $(call get-binary-libs,$(bin))))
|
||||
|
||||
# Get the default binaries
|
||||
DEFAULT_BINARIES := $(foreach bin,$(BINARIES), \
|
||||
$(if $(DISABLE_$(bin)),,$(bin)))
|
||||
|
||||
# Look for their sources
|
||||
define get-binary-sources
|
||||
SRC_$1 := $(basename $(shell find $(SRCDIR)/$1 \
|
||||
-maxdepth 1 -mindepth 1 \
|
||||
\( -name "*.c" -or -name "*.exe" \) \
|
||||
-printf "%P\n" | sort))
|
||||
|
||||
# - get the flags
|
||||
CFLAGS_$1 := $(CFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --cflags 2>/dev/null) \
|
||||
-D BIN="$1$(if $(FOR_WINDOWS),.exe)"
|
||||
LDFLAGS_$1 := $(LDFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --libs 2>/dev/null)
|
||||
endef
|
||||
$(foreach bin,$(BINARIES), \
|
||||
$(eval $(call get-binary-sources,$(bin))))
|
||||
|
||||
#******************************************************************************#
|
||||
# Look for manpages #
|
||||
#******************************************************************************#
|
||||
# Get the manpages sections and contents
|
||||
MAN_SECTIONS :=
|
||||
define check-man
|
||||
MAN_SECTIONS += $1
|
||||
MAN_$1 += $2
|
||||
endef
|
||||
$(foreach doc, $(basename $(shell find $(DOCDIR) \
|
||||
-maxdepth 1 -mindepth 1 -printf "%P\n" -type f -or -type l -name "*.*.txt")), \
|
||||
$(eval $(call check-man,$(patsubst .%,%,$(suffix $(doc))),$(basename $(doc)))))
|
||||
|
||||
# Remove duplicate sections.
|
||||
MAN_SECTIONS := $(sort $(MAN_SECTIONS))
|
||||
|
||||
#******************************************************************************#
|
||||
# Check for DESTDIR (add as prefix to installation root) #
|
||||
#******************************************************************************#
|
||||
define add-dest-dir
|
||||
$1 = $(DESTDIR)$($1)
|
||||
endef
|
||||
$(if $(DESTDIR), $(foreach idir,IBINDIR IMANDIR, \
|
||||
$(eval $(call add-dest-dir,$(idir)))))
|
||||
|
||||
# End of file.
|
|
@ -0,0 +1,53 @@
|
|||
# p7utils - Shell utilities to interact with CASIO calculators and files
|
||||
## Introduction
|
||||
**p7utils** is a set of command-line utilities that allow you to interact with
|
||||
your CASIO calculators/files. The name comes from the fact that it originally
|
||||
was the merge of `p7`, `p7screen` and `p7os` (which had an almost identical
|
||||
project structure), then the `g1mutils` (shell utilities for
|
||||
[libg1m](https://github.com/cakeisalie5/libg1m/) merged with this project.
|
||||
|
||||
Available utilities are:
|
||||
|
||||
* `p7` will interact with the storage memories;
|
||||
* `p7screen` will display the result of the screen streaming;
|
||||
* `p7os` will allow you to interact with the calculator's OS (backup, flash);
|
||||
* `mcsfile` will display the content of an MCS archive file.
|
||||
|
||||
## Prerequisites
|
||||
### Making-only dependencies
|
||||
| Name | Version |
|
||||
| -------------------------------------------------- | -------- |
|
||||
| [gcc](https://gcc.gnu.org/) | >= 4.9 |
|
||||
| [binutils](https://www.gnu.org/software/binutils/) | >= 2.25 |
|
||||
| [asciidoc](http://asciidoc.org/) | >= 8.6.9 |
|
||||
| [gzip](https://www.gnu.org/software/gzip/) | >= 1.6 |
|
||||
|
||||
### Making and runtime dependencies
|
||||
| Name | Version |
|
||||
| -------------------------------------------------- | --------- |
|
||||
| [libp7](https://p7.planet-casio.com/en.html) | >= 3.0 |
|
||||
| [libg1m](https://github.com/cakeisalie5/libg1m) | >= 0.1 |
|
||||
| [libsdl](https://libsdl.org/) | == 1.2.15 |
|
||||
|
||||
Notice that dependencies varies if you only want to build some
|
||||
executables: only `p7screen` will require the SDL, and `mcsfile`
|
||||
is the only one to require `libg1m`.
|
||||
|
||||
You should check `src/<name>/vars.mk` to see what the dependencies of
|
||||
the particular executable you want are (if you don't want them all; see
|
||||
the `libs` target).
|
||||
|
||||
## Building
|
||||
Just `./configure` then `make`. To install, use `make install`.
|
||||
Make the manpages with `make all-doc` and install them with `make install-doc`.
|
||||
|
||||
Other useful targets :
|
||||
- `all-<name>[.exe]`: build only a given executable (and its doc);
|
||||
- `install-<name>[.exe]`: install only a given executable (and its doc, if
|
||||
`--noinstall-manpages` is not passed to the configure script);
|
||||
- `uninstall-<name>[.exe]`: uninstall only a given executable (and its doc);
|
||||
- `clean`, `clean-<name>[.exe]`, `clean-doc`: remove built files;
|
||||
- `mrproper`: remove all built files, and the configuration;
|
||||
- `re`: remove all built files, and build all the default executables and docs.
|
||||
|
||||
Notice that the `.exe` suffix is facultative and is valid for all targets.
|
|
@ -0,0 +1,190 @@
|
|||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
#******************************************************************************#
|
||||
# Defaults #
|
||||
#******************************************************************************#
|
||||
# Project variables
|
||||
name="$(make -s getname)"
|
||||
version="$(make -s getversion)"
|
||||
maintainer="$(make -s getmaintainer)"
|
||||
|
||||
# Make options
|
||||
make_full_log=
|
||||
more_warnings=
|
||||
|
||||
# Build options
|
||||
target=
|
||||
windows=
|
||||
default_zoom=8
|
||||
default_storage=fls0
|
||||
|
||||
# Installation directories
|
||||
root=''
|
||||
prefix='${root}/usr'
|
||||
bindir='${prefix}/bin'
|
||||
mandir='${prefix}/share/man'
|
||||
|
||||
# Installation options
|
||||
install_manpages=yes
|
||||
|
||||
#******************************************************************************#
|
||||
# Help message #
|
||||
#******************************************************************************#
|
||||
usage() {
|
||||
cat <<EOF
|
||||
\`configure\` configures ${name} to adapt to systems that aren't mine.
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Defaults for the options are specified in brackets.
|
||||
|
||||
General options:
|
||||
--help display this help and exit
|
||||
--version display version information and quit
|
||||
--make-full-log display full commands while making
|
||||
--maintainer enable maintainer mode
|
||||
|
||||
Build options:
|
||||
--target=TARGET the build target [$target]
|
||||
--default-zoom=ZOOM the default zoom for \`p7screen\` [$default_zoom]
|
||||
--default-storage=STOR the default storage device [$default_storage]
|
||||
|
||||
Installation options:
|
||||
--noinstall-manpages do not install manpages
|
||||
|
||||
Installation directories:
|
||||
--root=ROOT installation root [$root]
|
||||
--prefix=PREFIX main installation prefix [$prefix]
|
||||
|
||||
Fine tuning of the installation directories:
|
||||
--bindir=DIR user executables, not "dustbin" [$bindir]
|
||||
--mandir=DIR man root [$mandir]
|
||||
|
||||
Report bugs to ${maintainer}.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
#******************************************************************************#
|
||||
# Version message #
|
||||
#******************************************************************************#
|
||||
version() {
|
||||
cat <<EOF
|
||||
${name} configure script v${version}
|
||||
Hand-written by Thomas "Cakeisalie5" Touhey.
|
||||
|
||||
This configure script is free software.
|
||||
There is NO warranty; not even for MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
#******************************************************************************#
|
||||
# Check for help and version #
|
||||
#******************************************************************************#
|
||||
put_version=
|
||||
put_help=
|
||||
for arg ; do case "$arg" in
|
||||
--help|-h) put_help=y ;;
|
||||
--version|-v) put_version=y ;;
|
||||
esac; done
|
||||
[ $put_version ] && version
|
||||
[ $put_help ] && usage
|
||||
|
||||
#******************************************************************************#
|
||||
# Parse arguments #
|
||||
#******************************************************************************#
|
||||
for arg ; do case "$arg" in
|
||||
--make-full-log) make_full_log=yes ;;
|
||||
--target=*) target="${arg#*=}" ;;
|
||||
--maintainer) more_warnings=yes ;;
|
||||
--default-zoom=*)
|
||||
zoom="${arg#*=}"
|
||||
if ! [ $zoom -eq $zoom 2>/dev/null ]; then
|
||||
echo "--default-zoom: a number is expected (got \"$zoom\")" >&2
|
||||
elif [ $zoom -lt 1 ]; then
|
||||
echo "--default-zoom: should be 1 or more (got $zoom)" >&2
|
||||
elif [ $zoom -gt 16 ]; then
|
||||
echo "--default-zoom: should be 16 or less (got $zoom)" >&2
|
||||
else default_zoom=$zoom; fi ;;
|
||||
--default-storage=*)
|
||||
storage="${arg#*=}"
|
||||
# check if 4 chars long
|
||||
if [ ! $(echo "$storage" | wc -c ) -eq 5 ]; then
|
||||
echo "$0: --default-storage: must be 4 characters long"
|
||||
continue
|
||||
fi
|
||||
# then set
|
||||
default_storage="$storage" ;;
|
||||
--noinstall-manpages) install_manpages= ;;
|
||||
--root=*) root="${arg#*=}" ;;
|
||||
--prefix=*) prefix="${arg#*=}" ;;
|
||||
--bindir=*) bindir="${arg#*=}" ;;
|
||||
--mandir=*) mandir="${arg#*=}" ;;
|
||||
*) echo "$arg: didn't read" ;;
|
||||
esac; done
|
||||
|
||||
#******************************************************************************#
|
||||
# Little things #
|
||||
#******************************************************************************#
|
||||
# Cross-compilation things
|
||||
if [ ! $prefix_set ] && [ $target ]; then
|
||||
prefix="$prefix"/"$target"
|
||||
fi
|
||||
|
||||
# Check MS-Windows targets
|
||||
case "$target" in *-mingw32) windows=y ;; esac
|
||||
|
||||
# Evaluate variables
|
||||
for var in prefix bindir mandir; do
|
||||
eval $var'='$(eval 'echo $'$var)
|
||||
done
|
||||
|
||||
# Check if is on Cygwin
|
||||
[ "$(expr substr "$(uname -s)" 1 10)" = "MINGW32_NT" ] && windows=y
|
||||
|
||||
# If on MS-Windows, do not make the manpages.
|
||||
[ "$windows" ] && install_manpages=
|
||||
|
||||
#******************************************************************************#
|
||||
# Create Makefile configuration #
|
||||
#******************************************************************************#
|
||||
# Clean before.
|
||||
make mrproper MAKE_FULL_LOG=y 1>/dev/null 2>/dev/null
|
||||
|
||||
# Do it!
|
||||
exec 3>&1 1>Makefile.cfg
|
||||
cat <<EOF
|
||||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Makefile configuration generated by ./configure #
|
||||
#******************************************************************************#
|
||||
# Configuration version and messages configuration
|
||||
CONFIG_VERSION := $version
|
||||
MAKE_FULL_LOG := $make_full_log
|
||||
MORE_WARNINGS := $more_warnings
|
||||
|
||||
# Build options
|
||||
TARGET := $target
|
||||
FOR_WINDOWS := $windows
|
||||
DEFAULT_ZOOM := $default_zoom
|
||||
DEFAULT_STORAGE := $default_storage
|
||||
|
||||
# Installation directories
|
||||
IBINDIR := $bindir
|
||||
IMANDIR := $mandir
|
||||
|
||||
# Installation options
|
||||
INSTALL_MANPAGES := $install_manpages
|
||||
|
||||
# End of file.
|
||||
EOF
|
||||
exec 1>&3 3>&-
|
||||
chmod +x Makefile.cfg
|
||||
|
||||
#******************************************************************************#
|
||||
# Finish #
|
||||
#******************************************************************************#
|
||||
echo "Configuration loaded, you can make now."
|
||||
|
||||
# End of file.
|
|
@ -0,0 +1,36 @@
|
|||
MCSFILE(1)
|
||||
==========
|
||||
Thomas "Cakeisalie5" Touhey
|
||||
:Email: thomas@touhey.fr
|
||||
:man source: p7utils
|
||||
:man manual: p7utils manual
|
||||
|
||||
NAME
|
||||
----
|
||||
mcsfile - list subfiles in a CASIO MCS archive file
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[source,bash]
|
||||
----
|
||||
mcsfile [--help] [--version] <archive.g1m>
|
||||
----
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
mcsfile is a simple utility that looks like *file*(1), excepts it lists subfiles
|
||||
in a CASIO MCS archive file (things with extensions like *g1m* or *g2r*).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
Options start with one or two dashes. Some of the options require an additional
|
||||
value next to them.
|
||||
|
||||
*-h, --help*::
|
||||
Display command/subcommand help page and quit.
|
||||
*-v, --version*::
|
||||
Display version and quit.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*libg1m*(3)
|
|
@ -0,0 +1,85 @@
|
|||
P7(1)
|
||||
=====
|
||||
Thomas "Cakeisalie5" Touhey
|
||||
:Email: thomas@touhey.fr
|
||||
:man source: p7utils
|
||||
:man manual: p7utils manual
|
||||
|
||||
NAME
|
||||
----
|
||||
p7 - command-line utility to communicate with casio calculators
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[source,bash]
|
||||
----
|
||||
p7 [-h|--help] [-v|--version] [<command> [<args>]]
|
||||
----
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
p7 is a command-line utility to communicate with machines using casio's
|
||||
communication protocol 7.00, like (almost only, not gonna lie) CASIO
|
||||
fx calculators. For now, it only implements file sending/getting functions
|
||||
on flash memories.
|
||||
|
||||
Available submenus are:
|
||||
|
||||
*send [-f] [-o oncalc.ext] [-d oncalcdir] local.ext*::
|
||||
Send a file to the calculator.
|
||||
*get [-o local.ext] [-d oncalcdir] oncalc.ext*::
|
||||
Get a file from calculator.
|
||||
*copy [-d sourcedir] [-t destdir] source.ext dest.ext*::
|
||||
Copies a file into another on the calculator.
|
||||
*del [-d oncalcdir] oncalc.ext*::
|
||||
Delete a file on the calculator.
|
||||
*ls*::
|
||||
List files on the calculator.
|
||||
*reset*::
|
||||
Reset a filesystem on the calculator.
|
||||
*optimize*::
|
||||
Optimize the distant filesystem (defragment).
|
||||
*info*::
|
||||
Dumps information about the calculator.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
Options start with one or two dashes. Some of the options require an additional
|
||||
value next to them.
|
||||
|
||||
*-h, --help*::
|
||||
Display command/subcommand help page and quit.
|
||||
*-v, --version*::
|
||||
Display version and quit.
|
||||
*--com <port>*::
|
||||
The USB-serial port, if you want to communicate with a calculator connected
|
||||
using a USB-to-serial cable. (1 to 20)
|
||||
If this option isn't used, the program will look for a directly connected
|
||||
USB calculator.
|
||||
*--storage abc0*::
|
||||
The storage device with which to interact.
|
||||
*--no-term, --no-exit*::
|
||||
Do not terminate connection when action is completed.
|
||||
*--no-start, --no-init*::
|
||||
Do not initialize connection -- should only be used when
|
||||
*--no-term*/*--no-exit* was used last time p7 was called.
|
||||
*-d DIR, --directory=DIR*::
|
||||
The on-calc directory to work in.
|
||||
Default for this option is device root.
|
||||
*-t DDIR, --to=DIR*::
|
||||
The destination directory (for file copying/moving).
|
||||
Default for this option is device root.
|
||||
*-o OUT, --output=OUT*::
|
||||
For the *get* subcommand, the local file path to store in the output (or
|
||||
'-' for stdout). For the *send* subcommand, the distant filename. For the
|
||||
two subcommands, default is adapted from the input parameter.
|
||||
*-f, --force*::
|
||||
For the *send* subcommand, force overwrite (default is interactive
|
||||
confirmation from user).
|
||||
*-#*::
|
||||
Displays a nice little loading bar for *send* and *get* subcommands. If
|
||||
command is *get* and output is stdout, loading bar won't be displayed.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*libp7*(3)
|
|
@ -0,0 +1,60 @@
|
|||
P7OS(1)
|
||||
=======
|
||||
Thomas "Cakeisalie5" Touhey
|
||||
:Email: thomas@touhey.fr
|
||||
:man source: p7utils
|
||||
:man manual: p7utils manual
|
||||
|
||||
NAME
|
||||
----
|
||||
p7os - backup and setup CASIO calculator's software components using protocol 7
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[source,bash]
|
||||
----
|
||||
p7os [-h|--help] [-v|--version] [--no-prepare] [--uexe <path>]
|
||||
[<subcommand> [<args>]]
|
||||
----
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
p7os is a command-line utility to get and upload an OS on CASIO fx calculators,
|
||||
using its communication protocol 7.00 and OS update mode.
|
||||
|
||||
Available submenus are :
|
||||
|
||||
*prepare-only*::
|
||||
Sends the update program, but leave it for other programs to interact
|
||||
with it.
|
||||
*get [-o os.bin]*::
|
||||
Backup the bootcode, CASIOWIN entry and OS.
|
||||
|
||||
You have to *prepare* before doing any other action. Preparing means sending
|
||||
a P7 server on the calculator that will be able to execute commands required
|
||||
by other subcommands.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
Options start with one or two dashes. Some of the options require an additional
|
||||
value next to them.
|
||||
|
||||
*-h, --help*::
|
||||
Display command/subcommand help page and quit.
|
||||
*-v, --version*::
|
||||
Display version and quit.
|
||||
*--com <port>*::
|
||||
The USB-serial port, if you want to communicate with a calculator connected
|
||||
using a USB-to-serial cable. (1 to 20)
|
||||
If this option isn't used, the program will look for a directly connected
|
||||
USB calculator.
|
||||
*--no-prepare*::
|
||||
Use the current environment, instead of uploading one.
|
||||
*--uexe <path>*::
|
||||
Use a custom update program.
|
||||
*-o OUT, --output=OUT*::
|
||||
When getting something, where to store.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*libp7*(3)
|
|
@ -0,0 +1,43 @@
|
|||
P7SCREEN(1)
|
||||
===========
|
||||
Thomas "Cakeisalie5" Touhey
|
||||
:Email: thomas@touhey.fr
|
||||
:man source: p7utils
|
||||
:man manual: p7utils manual
|
||||
|
||||
NAME
|
||||
----
|
||||
p7screen - display streamed screen from casio fx calculator
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[source,bash]
|
||||
----
|
||||
p7screen [-h|--help] [-v|--version]
|
||||
----
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
p7screen is a command-line utility to display streamed screen from casio fx
|
||||
calculator, using its communication protocol 7.00 and screenstreaming mode.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
Options start with one or two dashes. Some of the options require an additional
|
||||
value next to them.
|
||||
|
||||
*-h, --help*::
|
||||
Display help page and quit.
|
||||
*-v, --version*::
|
||||
Display version and quit.
|
||||
*--com <port>*::
|
||||
The USB-serial port, if you want to communicate with a calculator connected
|
||||
using a USB-to-serial cable. (1 to 20)
|
||||
If this option isn't used, the program will look for a directly connected
|
||||
USB calculator.
|
||||
*-z ZOOM, --zoom=ZOOM*::
|
||||
Change the zoom (will change the window size too).
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*libp7*(3)
|
|
@ -0,0 +1,93 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* args.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2016/12/18 01:20:51 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <getopt.h>
|
||||
#define Q(x) #x
|
||||
#define QUOTE(x) Q(x)
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Help and version messages */
|
||||
/* ************************************************************************** */
|
||||
/* Help message */
|
||||
static const char *help_message =
|
||||
"Usage: mcsfile [--version|-v] [--help|-h] <g1m file>\n"
|
||||
"\n"
|
||||
"Reads mcs files in a g1m file.\n"
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
" -h, --help Display this help message.\n"
|
||||
" -v, --version Display the version message.\n"
|
||||
"\n"
|
||||
"Report bugs to " QUOTE(MAINTAINER) ".";
|
||||
|
||||
/* Version message */
|
||||
static const char *version_message =
|
||||
"mcsfile - from p7utils v" QUOTE(VERSION) " (licensed under GPLv2)\n"
|
||||
"Maintained by " QUOTE(MAINTAINER) ".\n"
|
||||
"\n"
|
||||
"This is free software; see the source for copying conditions.\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or\n"
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.";
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main function */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* parse_args:
|
||||
* Args parsing main function.
|
||||
*
|
||||
* @arg ac the arguments count.
|
||||
* @arg av the arguments values.
|
||||
* @arg files pointer to the file paths tab to allocate.
|
||||
* @return if execution should stop.
|
||||
*/
|
||||
|
||||
int parse_args(int ac, char **av, const char **path)
|
||||
{
|
||||
/* getopt elements */
|
||||
const char *optstring = "hv";
|
||||
const struct option longopts[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{}
|
||||
};
|
||||
|
||||
/* get options */
|
||||
int c; opterr = 0;
|
||||
int help = 0, version = 0;
|
||||
while ((c = getopt_long(ac, av, optstring, longopts, NULL)) != -1)
|
||||
switch (c) {
|
||||
case 'h': help = 1; break;
|
||||
case 'v': version = 1; break;
|
||||
default: switch (optopt) {
|
||||
default:
|
||||
fprintf(stderr, "-%c: unknown option.\n", optopt);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* check parameters */
|
||||
int pc = ac - optind;
|
||||
char **pv = &av[optind];
|
||||
if (pc != 1) help = 1;
|
||||
else *path = *pv;
|
||||
|
||||
/* display version or help message */
|
||||
if (version) {
|
||||
puts(version_message);
|
||||
return (1);
|
||||
} else if (help) {
|
||||
puts(help_message);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* main.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2016/12/18 01:19:25 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* main:
|
||||
* Entry point of the program.
|
||||
*
|
||||
* @arg ac the arguments count.
|
||||
* @arg av the arguments values.
|
||||
* @return the status code (0 if ok).
|
||||
*/
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
/* parse arguments */
|
||||
const char *path;
|
||||
if (parse_args(ac, av, &path))
|
||||
return (0);
|
||||
|
||||
/* parse */
|
||||
g1m_t *handle; int err;
|
||||
if ((err = g1m_open(&handle, path, g1m_type_mcs))) switch (err) {
|
||||
case g1m_error_wrong_type:
|
||||
fprintf(stderr, "An MCS file was expected (g1m/g1r, g1m/g2r, g3m)\n");
|
||||
return (0);
|
||||
case g1m_error_nostream:
|
||||
fprintf(stderr, "Could not open file: %s\n", strerror(errno));
|
||||
return (0);
|
||||
case g1m_error_magic:
|
||||
fprintf(stderr, "Magic error: file might be corrupted\n");
|
||||
return (0);
|
||||
case g1m_error_eof:
|
||||
fprintf(stderr, "Unexpected end of file\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* read */
|
||||
put_files(handle);
|
||||
|
||||
/* no error */
|
||||
g1m_free(handle);
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* main.h |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2016/12/18 01:33:41 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#ifndef MAIN_H
|
||||
# define MAIN_H
|
||||
# include <libg1m.h>
|
||||
|
||||
/* Some printf types */
|
||||
# ifdef _WIN64
|
||||
# define PRIuSIZE "l64u"
|
||||
# elif _WIN32
|
||||
# define PRIuSIZE "u"
|
||||
# else
|
||||
# define PRIuSIZE "zu"
|
||||
# endif
|
||||
|
||||
/* Prototypes */
|
||||
int parse_args(int ac, char **av, const char **paths);
|
||||
void put_files(g1m_t *handle);
|
||||
|
||||
#endif /* MAIN_H */
|
|
@ -0,0 +1,130 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* line.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2016/12/18 01:43:52 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Sort */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* compare:
|
||||
* Compare two MCS files.
|
||||
*
|
||||
* @arg
|
||||
*/
|
||||
|
||||
static int compare(const void *vpfile1, const void *vpfile2)
|
||||
{
|
||||
g1m_mcsfile_t *file1 = *((g1m_mcsfile_t**)vpfile1);
|
||||
g1m_mcsfile_t *file2 = *((g1m_mcsfile_t**)vpfile2);
|
||||
|
||||
/* compare dirnames */
|
||||
int dirdiff = strcmp(file1->_dirname, file2->_dirname);
|
||||
if (dirdiff) return (dirdiff > 0);
|
||||
|
||||
/* compare names */
|
||||
return (strcmp(file1->name, file2->name) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sort_files:
|
||||
* Sort MCS files.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
*/
|
||||
|
||||
static void sort_files(g1m_t *handle)
|
||||
{
|
||||
qsort(handle->files, (size_t)handle->count,
|
||||
sizeof(g1m_mcsfile_t*), &compare);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Display */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* put_description:
|
||||
* Put the description (with the newline).
|
||||
*
|
||||
* @arg file the MCS file.
|
||||
*/
|
||||
|
||||
static void put_description(g1m_mcsfile_t *file)
|
||||
{
|
||||
if (!file->type)
|
||||
printf("unknown content (%" PRIuSIZE" octets)\n", file->content_size);
|
||||
else if (file->type & g1m_mcstype_program) {
|
||||
printf("program (");
|
||||
if (g1m_has_password(file)) printf("password: '%s')\n", file->password);
|
||||
else printf("no password)\n");
|
||||
} else if (file->type & g1m_mcstype_list) {
|
||||
printf("list %d (", g1m_get_id_minor(file->id));
|
||||
if (g1m_get_id_major(file->id))
|
||||
printf("from listfile %d, ", g1m_get_id_major(file->id));
|
||||
printf("%d columns)\n", file->columns);
|
||||
} else if (file->type & g1m_mcstype_mat)
|
||||
printf("matrix %c (%d columns, %d rows)\n",
|
||||
'A' + file->id - 1, file->columns, file->rows);
|
||||
else if (file->type & g1m_mcstype_vct)
|
||||
printf("vector %c (%d rows)\n",
|
||||
'A' + file->id - 1, file->rows);
|
||||
else if (file->type & g1m_mcstype_pict)
|
||||
printf("picture %d (double %dx%d image)\n",
|
||||
file->id, file->width, file->height);
|
||||
else if (file->type & g1m_mcstype_capt)
|
||||
printf("capture %d (%dx%d)\n",
|
||||
file->id, file->width, file->height);
|
||||
else if (file->type & g1m_mcstype_spreadsheet)
|
||||
printf("spreadsheet (%d columns, %d rows)\n",
|
||||
file->columns, file->rows);
|
||||
else if (file->type & g1m_mcstype_string)
|
||||
printf("string %d\n", file->id);
|
||||
else if (file->type & g1m_mcstype_setup)
|
||||
printf("setup\n");
|
||||
else if (file->type & g1m_mcstype_alphamem)
|
||||
printf("alpha memory\n");
|
||||
else
|
||||
printf("unmanaged format\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* put_files:
|
||||
* Put the files.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
*/
|
||||
|
||||
void put_files(g1m_t *handle)
|
||||
{
|
||||
if (!handle->count) {
|
||||
fprintf(stderr, "Provided file was empty.\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
sort_files(handle);
|
||||
/* get first part maximum size */
|
||||
int max_size = 0;
|
||||
for (int i = 0; i < handle->count; i++) {
|
||||
g1m_mcsfile_t *file = handle->files[i];
|
||||
int sz = strlen(file->name) + strlen(file->_dirname);
|
||||
if (sz > max_size) max_size = sz;
|
||||
}
|
||||
max_size += 2;
|
||||
|
||||
/* put the lines */
|
||||
char buf[max_size + 1];
|
||||
for (int i = 0; i < handle->count; i++) if (handle->files[i]) {
|
||||
g1m_mcsfile_t *file = handle->files[i];
|
||||
sprintf(buf, "%s/%s:", file->_dirname, file->name);
|
||||
printf("%-*s ", max_size, buf);
|
||||
put_description(handle->files[i]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/make -f
|
||||
disable:
|
||||
libs:
|
||||
@echo libg1m
|
|
@ -0,0 +1,348 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* p7/args.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 23:55:54 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Help and version messages */
|
||||
/* ************************************************************************** */
|
||||
/* Version message */
|
||||
static const char version_message[] =
|
||||
QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION) " (licensed under GPLv2)\n"
|
||||
"Maintained by " QUOTE(MAINTAINER) ".\n"
|
||||
"\n"
|
||||
"This is free software; see the source for copying conditions.\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or\n"
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.";
|
||||
|
||||
/* Main help message */
|
||||
static const char help_main[] =
|
||||
"Usage: " QUOTE(BIN) " [--version|-v] [--help|-h] [--no-init] [--no-exit]\n"
|
||||
" [--storage <fls0>] [--com <port>]\n"
|
||||
" <subcommand> [options...]\n"
|
||||
"\n"
|
||||
"Subcommands you can use are:\n"
|
||||
" send Send a file to the calculator.\n"
|
||||
" get Get a file from the calculator.\n"
|
||||
" copy Copy a file into another on the calculator.\n"
|
||||
" del Delete a file on the calculator.\n"
|
||||
" reset Reset the flash memory.\n"
|
||||
" optimize Optimize the distant filesystem.\n"
|
||||
" ls List files on the distant filesystem.\n"
|
||||
" info Dump info about the calculator.\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
" -h, --help Display the help page of the (sub)command and quit.\n"
|
||||
" -v, --version Display the version message and quit.\n"
|
||||
" --com <port> The USB-serial port, if you want to communicate with a\n"
|
||||
" calculator connected using a USB-to-serial cable. (1 to 20)\n"
|
||||
" If this option isn't used, the program will look for a\n"
|
||||
" directly connected USB calculator.\n"
|
||||
" --storage <abc0> The storage device with which to interact (fls0, crd0).\n"
|
||||
" Default storage device is '" QUOTE(DEFAULT_STORAGE) "'.\n"
|
||||
" --no-exit Does not terminate connection when action is completed.\n"
|
||||
" --no-init Does not initialize connection (should only be used\n"
|
||||
" when --no-exit was used last time p7 was called).\n"
|
||||
"\n"
|
||||
"Type \"" QUOTE(BIN) " <subcommand> --help\" for some help about the subcommand.\n"
|
||||
"Report bugs to " QUOTE(MAINTAINER) ".";
|
||||
|
||||
/* Parts */
|
||||
#define FOOT \
|
||||
"\nType \"" QUOTE(BIN) " --help\" for other subcommands and general options."
|
||||
|
||||
/* Sending help message */
|
||||
static const char help_send[] =
|
||||
"Usage: " QUOTE(BIN) " send [-f] [-o <on-calc filename>]\n"
|
||||
" [-d <on-calc directory>] [-#] <local file>\n"
|
||||
"Send a file to the calculator.\n"
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
" -f, --force Overwrite without asking\n"
|
||||
" -o <name> The output filename on the calculator (by default, the same\n"
|
||||
" as the local file)\n"
|
||||
" -d <dir> The directory on-calc in which the file will be stored (by\n"
|
||||
" default, the root directory)\n"
|
||||
" -# Display a nice little loading bar\n"
|
||||
FOOT;
|
||||
|
||||
/* Getting help message */
|
||||
static const char help_get[] =
|
||||
"Usage: " QUOTE(BIN) " get [-o <local file>]\n"
|
||||
" [-d <on-calc directory>] <on-calc filename>\n"
|
||||
"Request a file from the calculator.\n"
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
" -o <name> The output filename (by default, the same as the on-calc file)\n"
|
||||
" -d <dir> The directory on-calc in which to get the file (by default,\n"
|
||||
" the root directory)\n"
|
||||
" -# Display a nice little loading bar (if output isn't stdout)\n"
|
||||
FOOT;
|
||||
|
||||
/* Copying help message */
|
||||
static const char help_copy[] =
|
||||
"Usage: p7 copy [-f] [-d <source directory]\n"
|
||||
" [-t <destination directory>] <source file> <dest file>\n"
|
||||
"Copies a file into the other on the calculator.\n"
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
" -d <srcdir> The source directory (by default, the root directory)\n"
|
||||
" -t <dstdir> The dest. directory (by default, the root directory)\n"
|
||||
FOOT;
|
||||
|
||||
/* Deleting help message */
|
||||
static const char help_del[] =
|
||||
"Usage: p7 del [-d <on-calc directory] <on-calc filename>\n"
|
||||
"Delete a file on the calculator.\n"
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
" -d <dir> The directory on-calc in which to remove the file (by default,\n"
|
||||
" the root directory)\n"
|
||||
FOOT;
|
||||
|
||||
/* Listing help message */
|
||||
static const char help_ls[] =
|
||||
"Usage: p7 ls\n"
|
||||
"List files on the distant filesystem.\n"
|
||||
FOOT;
|
||||
|
||||
/* Resetting help message */
|
||||
static const char help_reset[] =
|
||||
"Usage: p7 reset\n"
|
||||
"Reset the distant filesystem.\n"
|
||||
FOOT;
|
||||
|
||||
/* Optimizing help message */
|
||||
static const char help_optimize[] =
|
||||
"Usage: p7 optimize\n"
|
||||
"Optimize the distant filesystem.\n"
|
||||
FOOT;
|
||||
|
||||
/* Dumping help message */
|
||||
static const char help_info[] =
|
||||
"Usage: p7 info\n"
|
||||
"Dump information about the calculator.\n"
|
||||
FOOT;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main function */
|
||||
/* ************************************************************************** */
|
||||
/* useful macros */
|
||||
#define sub_init(CMD, NARGS) \
|
||||
args->menu = mn_##CMD; \
|
||||
if (help || aac != 1 + (NARGS)) { \
|
||||
puts(help_##CMD); \
|
||||
return (0); \
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_args:
|
||||
* Args parsing main function.
|
||||
*
|
||||
* Was my very first experiment with getopt.
|
||||
* Then I took an arrow in the knee.
|
||||
*
|
||||
* @arg ac the arguments count
|
||||
* @arg av the arguments values
|
||||
* @arg args the parsed args pointer
|
||||
* @return if it was successfully parsed
|
||||
*/
|
||||
|
||||
int parse_args(int ac, char **av, args_t *args)
|
||||
{
|
||||
/* initialize args */
|
||||
*args = (args_t){
|
||||
.menu = 0,
|
||||
.nicedisp = 0,
|
||||
.dirname = NULL, .filename = NULL,
|
||||
.newdir = NULL, .newname = NULL,
|
||||
.local = NULL, .force = 0,
|
||||
.com = 0,
|
||||
.storage = QUOTE(DEFAULT_STORAGE),
|
||||
.initflags = P7_ACTIVE | P7_CHECK | P7_TERM};
|
||||
|
||||
/* define options */
|
||||
char short_options[] = "hvfo:d:t:#";
|
||||
struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"com", required_argument, NULL, 'c'},
|
||||
{"storage", required_argument, NULL, 's'},
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{"directory", required_argument, NULL, 'd'},
|
||||
{"to", required_argument, NULL, 't'},
|
||||
{"no-init", no_argument, NULL, 'i'},
|
||||
{"no-start", no_argument, NULL, 'i'},
|
||||
{"no-exit", no_argument, NULL, 'e'},
|
||||
{"no-term", no_argument, NULL, 'e'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* get all options */
|
||||
int c; opterr = 0;
|
||||
int help = 0;
|
||||
const char *s_out = NULL, *s_dir = NULL, *s_todir = NULL, *s_com = NULL;
|
||||
while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
/* help */
|
||||
case 'h': help = 1; break;
|
||||
/* version */
|
||||
case 'v': puts(version_message); return (0); break;
|
||||
/* force */
|
||||
case 'f': args->force = 1; break;
|
||||
/* nice display */
|
||||
case '#': args->nicedisp = 1; break;
|
||||
|
||||
/* output file (on calc or local) */
|
||||
case 'o': s_out = optarg; break;
|
||||
/* directory name */
|
||||
case 'd': s_dir = optarg; break;
|
||||
/* destination directory name */
|
||||
case 't': s_todir = optarg; break;
|
||||
|
||||
/* com port */
|
||||
case 'c': s_com = optarg; break;
|
||||
/* storage */
|
||||
case 's': args->storage = optarg; break;
|
||||
/* force no initialization */
|
||||
case 'i': args->initflags &= ~P7_CHECK; break;
|
||||
/* force no exit */
|
||||
case 'e': args->initflags &= ~P7_TERM; break;
|
||||
|
||||
/* in case of error */
|
||||
case '?':
|
||||
if (optopt == 'o')
|
||||
log("-o, --output: expected an argument\n");
|
||||
else if (optopt == 'd')
|
||||
log("-d, --directory: expected an argument\n");
|
||||
else if (optopt == 't')
|
||||
log("-t, --to: expected an argument\n");
|
||||
else if (optopt == 'c')
|
||||
log("--com: expected an argument\n");
|
||||
else if (optopt == 's')
|
||||
log("--storage: expected an argument\n");
|
||||
else
|
||||
break;
|
||||
return (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check com port */
|
||||
if (s_com) {
|
||||
if (!isdigit(s_com[0])) {
|
||||
log("-c, --com: expected a number\n");
|
||||
return (0);
|
||||
}
|
||||
args->com = atoi(s_com);
|
||||
if (args->com < 1 || args->com > 20) {
|
||||
log("-c, --com: COM port number should be between 1 and 20\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* get non-option arguments (subcommand and parameters) */
|
||||
int aac = ac - optind;
|
||||
char **aav = &av[optind];
|
||||
|
||||
/* get subcommand and things to check */
|
||||
char fpmode[2] = " ";
|
||||
args->localpath = NULL;
|
||||
/* - all subcommands - */
|
||||
if (!aac || !strcmp(aav[0], "help")) {
|
||||
puts(help_main);
|
||||
return (0);
|
||||
} else if (!strcmp(aav[0], "version")) {
|
||||
puts(version_message);
|
||||
return (0);
|
||||
} else if (!strcmp(aav[0], "info")) {
|
||||
sub_init(info, 0)
|
||||
} else if (!strcmp(aav[0], "ls")) {
|
||||
sub_init(ls, 0)
|
||||
} else if (!strcmp(aav[0], "reset")) {
|
||||
sub_init(reset, 0)
|
||||
} else if (!strcmp(aav[0], "optimize")) {
|
||||
sub_init(optimize, 0)
|
||||
} else if (!strcmp(aav[0], "send")) {
|
||||
sub_init(send, 1)
|
||||
|
||||
/* put arguments to check */
|
||||
fpmode[0] = 'r';
|
||||
args->localpath = aav[1];
|
||||
args->dirname = s_dir ? s_dir : NULL;
|
||||
if (s_out) args->filename = s_out;
|
||||
else {
|
||||
char *rs = strrchr(args->localpath, '/');
|
||||
args->filename = rs ? rs + 1 : args->localpath;
|
||||
}
|
||||
} else if (!strcmp(aav[0], "get")) {
|
||||
sub_init(get, 1)
|
||||
|
||||
/* put arguments to check */
|
||||
fpmode[0] = 'w';
|
||||
args->filename = aav[1];
|
||||
args->dirname = s_dir ? s_dir : NULL;
|
||||
args->localpath = s_out ? s_out : args->filename;
|
||||
} else if (!strcmp(aav[0], "copy")) {
|
||||
sub_init(copy, 2)
|
||||
|
||||
/* get filename */
|
||||
args->filename = aav[1];
|
||||
args->dirname = s_dir ? s_dir : NULL;
|
||||
args->newname = aav[2];
|
||||
args->newdir = s_todir ? s_todir : NULL;
|
||||
} else if (!strcmp(aav[0], "del") || !strcmp(aav[0], "delete")) {
|
||||
sub_init(del, 1)
|
||||
|
||||
/* get filename */
|
||||
args->filename = aav[1];
|
||||
args->dirname = s_dir ? s_dir : NULL;
|
||||
} else {
|
||||
/* unknown subcommand ! */
|
||||
log("Unknown subcommand '%s'.\n", aav[0]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* check string lengths */
|
||||
int noerror = 0;
|
||||
if (args->filename && strnlen(args->filename, 13) == 13)
|
||||
log("On-calc filename must have 12 chars or less!\n");
|
||||
else if (args->newname && strnlen(args->newname, 13) == 13)
|
||||
log("Destination filename must have 12 chars or less!\n");
|
||||
else if (args->dirname && strnlen(args->dirname, 9) == 9)
|
||||
log("On-calc directory name must have 8 chars or less!\n");
|
||||
else if (args->newdir && strnlen(args->newdir, 9) == 9)
|
||||
log("Destination directory name must have 8 chars or less!\n");
|
||||
else if (strnlen(args->storage, 5) != 4)
|
||||
log("Storage device (%s) should be 4 chars long!\n", args->storage);
|
||||
else
|
||||
noerror = 1;
|
||||
if (!noerror) return (0);
|
||||
|
||||
/* check local path */
|
||||
if (args->localpath) {
|
||||
if (fpmode[0] == 'w' && !strcmp(args->localpath, "-"))
|
||||
args->local = stdout;
|
||||
else if (!(args->local = fopen(args->localpath, fpmode))) {
|
||||
log("Could not open local file : %s\n", strerror(errno));
|
||||
if (fpmode[0] == 'w')
|
||||
remove(args->localpath);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* everything went well */
|
||||
return (1);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* p7/dump.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 23:55:54 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <inttypes.h>
|
||||
#include <libp7/packetio.h>
|
||||
#define numformat "%" PRIuP7INT
|
||||
#define addrformat "0x%08" PRIxP7INT
|
||||
|
||||
/**
|
||||
* dump:
|
||||
* Dump calculator information.
|
||||
*
|
||||
* @arg handle the libp7 handle
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int dump(p7_handle_t *handle)
|
||||
{
|
||||
/* get server info */
|
||||
const p7_server_t *info = p7_get_info(handle);
|
||||
|
||||
/* Wiped out things */
|
||||
if (info->preprog_rom_wiped)
|
||||
log("Warning: Preprogrammed ROM information looks wiped out !\n");
|
||||
if (info->bootcode_wiped)
|
||||
log("Warning: Bootcode information looks wiped out !\n");
|
||||
if (info->os_wiped)
|
||||
log("Warning: OS information looks wiped out!\n");
|
||||
if (!info->username[0])
|
||||
log("Warning: Username is not set.\n");
|
||||
|
||||
/* main information */
|
||||
printf("CPU ID (probably out of date): %s\n", info->cpuid);
|
||||
printf("Environnement ID: %s\n", info->hwid);
|
||||
printf("Product ID: %s\n", info->product_id);
|
||||
|
||||
/* Preprogrammed ROM */
|
||||
if (!info->preprog_rom_wiped) {
|
||||
printf("Preprogrammed ROM version: %02u.%02u",
|
||||
info->preprog_rom_version.major, info->preprog_rom_version.minor);
|
||||
if (info->preprog_rom_version.rev)
|
||||
printf(" (%u)", info->preprog_rom_version.rev);
|
||||
printf("\nPreprogrammed ROM capacity: " numformat "o\n",
|
||||
info->preprog_rom_capacity);
|
||||
}
|
||||
|
||||
/* ROM and RAM */
|
||||
printf("ROM capacity: " numformat "KiB\n", info->flash_rom_capacity / 1024);
|
||||
printf("RAM capacity: " numformat "KiB\n", info->ram_capacity / 1024);
|
||||
|
||||
/* Bootcode */
|
||||
if (!info->bootcode_wiped) {
|
||||
printf("Bootcode version: %02u.%02u",
|
||||
info->bootcode_version.major, info->bootcode_version.minor);
|
||||
if (info->bootcode_version.rev)
|
||||
printf(" (%u)", info->bootcode_version.rev);
|
||||
printf("\nBootcode offset: " addrformat "\n", info->bootcode_offset);
|
||||
printf("Bootcode size: " numformat "KiB\n", info->bootcode_size / 1024);
|
||||
}
|
||||
|
||||
/* OS */
|
||||
if (!info->os_wiped) {
|
||||
printf("OS version: %02u.%02u",
|
||||
info->os_version.major, info->os_version.minor);
|
||||
if (info->os_version.rev)
|
||||
printf(" (%u)", info->os_version.rev);
|
||||
printf("\nOS offset: " addrformat "\n", info->os_offset);
|
||||
printf("OS size: " numformat "KiB\n", info->os_size / 1024);
|
||||
}
|
||||
|
||||
/* Miscallenous information */
|
||||
if (info->username[0])
|
||||
printf("Username: %s\n", info->username);
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* p7/main.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 23:55:54 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Error messages */
|
||||
/* ************************************************************************** */
|
||||
/* Couldn't initialize connexion with the calculator. */
|
||||
static const char error_noconnexion[] =
|
||||
"Could not connect to the calculator.\n"
|
||||
"- Is it plugged in and in receive mode?\n"
|
||||
"- Have you tried changing the cable?\n";
|
||||
|
||||
/* Calculator was disconnected. */
|
||||
static const char error_disconnected[] =
|
||||
"Lost connexion to the calculator!\n"
|
||||
"Please reconnect the calculator, rerun receive mode and try again.\n";
|
||||
|
||||
/* Calculator was found but program wasn't allowed to communicate with it. */
|
||||
static const char error_noaccess[] =
|
||||
"Could not get access to the calculator.\n"
|
||||
"Install the appropriate udev rule, or run as root.\n";
|
||||
|
||||
/* Command was unsupported. */
|
||||
static const char error_unsupported[] =
|
||||
"The command is unsupported by the calculator.\n"
|
||||
"- Does the calculator have mass storage?\n"
|
||||
"- Does its OS allow the use of it?\n"
|
||||
"- Is it in Receive Mode (and not in OS Update)?\n";
|
||||
|
||||
/* The device didn't exist. */
|
||||
static const char error_unsupported_device[] =
|
||||
"Device '%s' is not supported by the device.\n";
|
||||
|
||||
/* The calculator acted in an unplanned way. */
|
||||
static const char error_unplanned[] =
|
||||
"The calculator didn't act as planned.\n"
|
||||
"Stop receive mode on calculator and start it again before re-running " \
|
||||
QUOTE(BIN) ".\n"
|
||||
"Error was: %s\n";
|
||||
|
||||
/* Requested file didn't exist. */
|
||||
static const char error_noexists[] =
|
||||
"Requested file didn't exist.\n";
|
||||
|
||||
/* Sent file cannot be empty. */
|
||||
static const char error_empty[] =
|
||||
"Can't send an empty file!\n";
|
||||
|
||||
/* Not enough space left on the calculator. */
|
||||
static const char error_nospace[] =
|
||||
"Not enough space on the calculator for the file you're trying to send.\n"
|
||||
"If you believe there should be, try optimizing (OPT) on the calculator\n"
|
||||
"(in MEMORY menu) and try again.\n";
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Auxiliary functions */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* sendfile_confirm:
|
||||
* Confirm file sending.
|
||||
*
|
||||
* @return if the file overwriting is confirmed
|
||||
*/
|
||||
|
||||
static int sendfile_confirm(void)
|
||||
{
|
||||
char line[10];
|
||||
|
||||
/* Print stuff */
|
||||
printf("It looks like the file already exists on the calculator.\n");
|
||||
printf("Overwrite ? ([n]/y) ");
|
||||
|
||||
/* Get the line */
|
||||
if (!fgets(line, 10, stdin))
|
||||
return (0);
|
||||
|
||||
/* Check if should overwrite */
|
||||
return (*line == 'y');
|
||||
}
|
||||
|
||||
/**
|
||||
* sendfile_display:
|
||||
* File sending nice display.
|
||||
*
|
||||
* "Initialization" is when id > total (called in main).
|
||||
*
|
||||
* @arg id data packet ID
|
||||
* @arg total total number of data packets
|
||||
*/
|
||||
|
||||
static int sendfile_display_initialized = 0;
|
||||
static void sendfile_display(p7ushort_t id, p7ushort_t total)
|
||||
{
|
||||
/* here's the buffer */
|
||||
static char buf[50] =
|
||||
"\r|---------------------------------------| 00.00%";
|
||||
static char *bar = &buf[2];
|
||||
|
||||
/* initialize */
|
||||
static int pos;
|
||||
|
||||
/* if is initialize, fill */
|
||||
if (id > total) {
|
||||
pos = 0;
|
||||
/* indicate that is has been initialized */
|
||||
sendfile_display_initialized = 1;
|
||||
/* put initial buffer */
|
||||
fputs(buf, stdout);
|
||||
/* save cursor position */
|
||||
fputs("\x1B[s", stdout);
|
||||
/* we're done */
|
||||
return ;
|
||||
}
|
||||
|
||||
/* id and total start from 1, let them start from zero */
|
||||
id--; total--;
|
||||
|
||||
/* modify buffer */
|
||||
/* - # - */
|
||||
int current = 38 * id / total;
|
||||
while (pos <= current) bar[pos++] = '#';
|
||||
/* - % - */
|
||||
unsigned int percent = 10000 * id / total;
|
||||
sprintf(&buf[43], "%02u.%02u", percent / 100, percent % 100);
|
||||
|
||||
/* put it */
|
||||
fputs(buf, stdout);
|
||||
/* force cursor position */
|
||||
fputs("\x1B""8", stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* print_file_info:
|
||||
* File listing callback.
|
||||
*
|
||||
* @arg cookie (unused)
|
||||
* @arg dir the directory in which the file is stored (NULL if root)
|
||||
* @arg name the filename
|
||||
* @arg size the filesize
|
||||
*/
|
||||
|
||||
static void print_file_info(void *cookie, const char *dir, const char *name,
|
||||
p7uint_t size)
|
||||
{
|
||||
(void)cookie;
|
||||
/* initialize buffer */
|
||||
static char buf[45];
|
||||
|
||||
/* clean buffer */
|
||||
memset(buf, ' ', 28);
|
||||
/* put path in buffer */
|
||||
char *b = buf;
|
||||
if (dir) b += sprintf(b, "%s/", dir);
|
||||
if (name) b[sprintf(b, "%s", name)] = ' ';
|
||||
/* put size */
|
||||
sprintf(&buf[28], "%10uo", (unsigned)size);
|
||||
|
||||
/* put the string */
|
||||
puts(buf);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main function */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* main:
|
||||
* User entry point of the program.
|
||||
*
|
||||
* @arg ac arguments count
|
||||
* @arg av arguments values
|
||||
* @return return code (0 if ok)
|
||||
*/
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
/* Parse args */
|
||||
args_t args;
|
||||
if (!parse_args(ac, av, &args))
|
||||
return (0);
|
||||
|
||||
/* Initialize libp7 and communication */
|
||||
p7_handle_t *handle = NULL; int err;
|
||||
if (args.com) err = p7_cominit(&handle, args.initflags, args.com);
|
||||
else err = p7_init(&handle, args.initflags);
|
||||
if (err) {
|
||||
/* display error */
|
||||
switch (err) {
|
||||
case p7_error_nocalc: log(error_noconnexion); break;
|
||||
case p7_error_noaccess: log(error_noaccess); break;
|
||||
default: log(error_unplanned, p7_strerror(err)); break;
|
||||
}
|
||||
|
||||
/* closing, removing if necessary */
|
||||
if (args.menu == mn_send)
|
||||
fclose(args.local);
|
||||
if (args.menu == mn_get && args.local != stdout) {
|
||||
fclose(args.local);
|
||||
remove(args.localpath);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Check according to menu */
|
||||
switch (args.menu) {
|
||||
case mn_send:
|
||||
/* get file size */
|
||||
fseek(args.local, 0, SEEK_END);
|
||||
size_t filesize = (p7uint_t)ftell(args.local);
|
||||
rewind(args.local);
|
||||
|
||||
/* get capacity */
|
||||
p7uint_t capacity;
|
||||
err = p7_getfreemem(handle, args.storage, &capacity);
|
||||
if (err) break;
|
||||
|
||||
/* optimize if required */
|
||||
if (filesize > (size_t)capacity) {
|
||||
printf("Not enough space on the device. Let's optimize!\n");
|
||||
err = p7_optimize(handle, args.storage);
|
||||
if (err) break;
|
||||
}
|
||||
|
||||
/* send the file */
|
||||
err = p7_sendfile(handle, args.local,
|
||||
args.dirname, args.filename,
|
||||
args.storage, 1, args.force ? NULL : &sendfile_confirm,
|
||||
args.nicedisp ? &sendfile_display : NULL);
|
||||
break;
|
||||
case mn_get:
|
||||
err = p7_reqfile(handle, args.local, args.dirname, args.filename,
|
||||
args.storage, args.nicedisp && args.local != stdout
|
||||
? &sendfile_display : NULL);
|
||||
break;
|
||||
case mn_copy:
|
||||
err = p7_copy(handle, args.dirname, args.filename,
|
||||
args.newdir, args.newname, args.storage);
|
||||
break;
|
||||
case mn_del:
|
||||
err = p7_delete(handle, args.dirname, args.filename,
|
||||
args.storage);
|
||||
break;
|
||||
case mn_ls:
|
||||
err = p7_list(handle, args.storage, &print_file_info, NULL);
|
||||
break;
|
||||
case mn_reset:
|
||||
err = p7_reset(handle, args.storage);
|
||||
break;
|
||||
case mn_optimize:
|
||||
err = p7_optimize(handle, args.storage);
|
||||
break;
|
||||
case mn_info:
|
||||
err = dump(handle);
|
||||
break;
|
||||
}
|
||||
|
||||
/* put error */
|
||||
if (err && err != p7_error_denied_overwrite) {
|
||||
if (sendfile_display_initialized)
|
||||
puts("\b\b\b\b\b\bError !");
|
||||
|
||||
/* close the file */
|
||||
if (args.local) fclose(args.local);
|
||||
if (args.menu == mn_get && args.local != stdout)
|
||||
remove(args.localpath);
|
||||
|
||||
/* put the error string */
|
||||
switch (err) {
|
||||
case p7_error_fullmem: log(error_nospace); break;
|
||||
case p7_error_empty: log(error_empty); break;
|
||||
case p7_error_notfound: log(error_noexists); break;
|
||||
case p7_error_nocalc: log(error_disconnected); break;
|
||||
case p7_error_unsupported: log(error_unsupported); break;
|
||||
case p7_error_unsupported_device:
|
||||
log(error_unsupported_device, args.storage); break;
|
||||
default: log(error_unplanned, p7_strerror(err));
|
||||
}
|
||||
|
||||
/* that doesn't mean you shouldn't exit, heh. */
|
||||
p7_exit(handle);
|
||||
|
||||
/* return that an error has occured */
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (sendfile_display_initialized)
|
||||
puts("\b\b\b\b\b\bTransfer complete.");
|
||||
if (args.local) fclose(args.local);
|
||||
|
||||
/* terminate communication and de-initialize libp7 */
|
||||
p7_exit(handle);
|
||||
|
||||
/* Then we're good */
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* p7/main.h |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 23:55:54 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#ifndef MAIN_H
|
||||
# define MAIN_H
|
||||
# define Q(x) #x
|
||||
# define QUOTE(x) Q(x)
|
||||
# include <stdio.h>
|
||||
# include <libp7.h>
|
||||
# define log(S, ...) fprintf(stderr, S, ##__VA_ARGS__)
|
||||
|
||||
/* Menus */
|
||||
typedef enum {
|
||||
mn_send, mn_get, mn_copy, mn_del, mn_ls, mn_reset, mn_optimize,
|
||||
mn_info
|
||||
} menu_t;
|
||||
|
||||
/* Arguments */
|
||||
typedef struct {
|
||||
/* basic things */
|
||||
menu_t menu;
|
||||
int nicedisp;
|
||||
|
||||
/* for file transferring menus */
|
||||
const char *dirname, *filename;
|
||||
const char *newdir, *newname;
|
||||
FILE *local; const char *localpath;
|
||||
int force;
|
||||
|
||||
/* other options */
|
||||
unsigned int initflags;
|
||||
int com; const char *storage;
|
||||
} args_t;
|
||||
|
||||
/* Parsing function */
|
||||
int parse_args(int ac, char **av, args_t *args);
|
||||
|
||||
/* Dumping function */
|
||||
int dump(p7_handle_t *handle);
|
||||
|
||||
#endif /* MAIN_H */
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/make -f
|
||||
libs:
|
||||
@echo libp7
|
|
@ -0,0 +1,220 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* p7os/args.c |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 23:55:54 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
#include "main.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Help and version messages */
|
||||
/* ************************************************************************** */
|
||||
/* The version message - that's when the President comes in */
|
||||
static const char version_message[] =
|
||||
QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION) " (licensed under GPLv2)\n"
|
||||
"Maintained by " QUOTE(MAINTAINER) ".\n"
|
||||
"\n"
|
||||
"This is free software; see the source for copying conditions.\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or\n"
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.";
|
||||
|
||||
/* Main help message */
|
||||
static const char help_main[] =
|
||||
"Usage: " QUOTE(BIN) " [--version|-v] [--help|-h] [--com <port>]\n"
|
||||
" [--no-prepare] [--uexe <path>]\n"
|
||||
" <subcommand> [options...]\n"
|
||||
"\n"
|
||||
"Subcommands you can use are :\n"
|
||||
" prepare-only Set-up the update program, but leave it for other programs\n"
|
||||
" to interact with it.\n"
|
||||
" get Get the OS image.\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
" -h, --help Display the help page of the (sub)command and quit.\n"
|
||||
" -v, --version Display the version message and quit.\n"
|
||||
" --com <port> The USB-serial port, if you want to communicate with a\n"
|
||||
" calculator connected using a USB-to-serial cable. (1 to 20)\n"
|
||||
" If this option isn't used, the program will look for a\n"
|
||||
" directly connected USB calculator.\n"
|
||||
" --no-prepare Use the current environment, instead of uploading one.\n"
|
||||
" --uexe <path> Use a custom update program.\n"
|
||||
"\n"
|
||||
"Type \"" QUOTE(BIN) " <subcommand> --help\" for some help about a subcommand.\n"
|
||||
"Report bugs to " QUOTE(MAINTAINER) ".";
|
||||
|
||||
/* Subcommands help messages footer */
|
||||
#define FOOT \
|
||||
"\nType \"" QUOTE(BIN) " --help\" for other subcommands and general options."
|
||||
|
||||
/* Help message for prepare subcommand */
|
||||
static const char help_prepare_only[] =
|
||||
"Usage: " QUOTE(BIN) " prepare-only\n"
|
||||
"Send the P7 server on the calculator for further operations.\n"
|
||||
"This must be used before any other p7os operation.\n"
|
||||
FOOT;
|
||||
|
||||
/* Help message for get subcommand */
|
||||
static const char help_get[] =
|
||||
"Usage: " QUOTE(BIN) " get [-o <os.bin>]\n"
|
||||
"Get the calculator OS image.\n"
|
||||
"You must have \"p7os prepare\"-ed before.\n"
|
||||
"\n"
|
||||
"Options are :\n"
|
||||
" -o <os.bin> Where to store the image (default is \"os.bin\")\n"
|
||||
FOOT;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main function */
|
||||
/* ************************************************************************** */
|
||||
/* Help macro */
|
||||
#define sub_init(CMD, NARGS) { \
|
||||
args->menu = mn_##CMD; \
|
||||
if (help || pc != (NARGS)) { \
|
||||
puts(help_##CMD); \
|
||||
return (1); \
|
||||
}}
|
||||
|
||||
/**
|
||||
* parse_args:
|
||||
* Args parsing main function.
|
||||
*
|
||||
* Based on my very first experiment with getopt.
|
||||
*
|
||||
* @arg ac the arguments count
|
||||
* @arg av the arguments values
|
||||
* @arg args the parsed args pointer
|
||||
* @return if has been parsed successfully
|
||||
*/
|
||||
|
||||
int parse_args(int ac, char **av, args_t *args)
|
||||
{
|
||||
/* initialize args */
|
||||
*args = (args_t){
|
||||
.menu = 0,
|
||||
.com = 0, .noprepare = 0,
|
||||
.uexe = NULL,
|
||||
.local = NULL, .localpath = NULL
|
||||
};
|
||||
|
||||
/* define options */
|
||||
const char shopts[] = "hvo:#";
|
||||
const struct option longopts[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"com", required_argument, NULL, 'c'},
|
||||
{"no-prepare", no_argument, NULL, 'n'},
|
||||
{"uexe", required_argument, NULL, 'u'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* get all options */
|
||||
int c; opterr = 0;
|
||||
int help = 0, version = 0;
|
||||
const char *s_out = "os.bin", *s_com = 0, *s_uexe = NULL;
|
||||
while ((c = getopt_long(ac, av, shopts, longopts, NULL)) != -1) switch (c) {
|
||||
/* help */
|
||||
case 'h': help = 1; break;
|
||||
/* version */
|
||||
case 'v': version = 1; break;
|
||||
/* com port */
|
||||
case 'c': s_com = optarg; break;
|
||||
/* no prepare */
|
||||
case 'n': args->noprepare = 1; break;
|
||||
/* uexe */
|
||||
case 'u': s_uexe = optarg; break;
|
||||
/* output */
|
||||
case 'o': s_out = optarg; break;
|
||||
|
||||
/* error */
|
||||
case '?':
|
||||
if (optopt == 'o')
|
||||
log("-o, --output: expected an argument\n");
|
||||
else if (optopt == 'c')
|
||||
log("--com: expected an argument\n");
|
||||
else if (optopt == 'u')
|
||||
log("--uexe: expected an argument\n");
|
||||
else
|
||||
break;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* check for version */
|
||||
if (version) {
|
||||
puts(version_message);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* get non-option arguments (subcommand and parameters) */
|
||||
int pc = ac - optind;
|
||||
char **pv = &av[optind];
|
||||
char *sub = pc ? pv[0] : NULL;
|
||||
pc--; pv++;
|
||||
|
||||
/* subcommand. */
|
||||
char fpmode[2] = "r";
|
||||
if (!sub || !strcmp(sub, "help")) {
|
||||
puts(help_main);
|
||||
return (1);
|
||||
} else if (!strcmp(sub, "version")) {
|
||||
puts(version_message);
|
||||
return (1);
|
||||
} else if (!strcmp(sub, "prepare-only")) {
|
||||
sub_init(prepare_only, 0)
|
||||
|
||||
if (args->noprepare) {
|
||||
log("So we should prepare but we should not prepare? Duh!\n");
|
||||
return (1);
|
||||
}
|
||||
} else if (!strcmp(sub, "get")) {
|
||||
sub_init(get, 0)
|
||||
args->localpath = s_out;
|
||||
fpmode[0] = 'w';
|
||||
} else {
|
||||
log("Unknown subcommand '%s'.\n", sub);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* check com port */
|
||||
if (s_com) {
|
||||
if (!isdigit(s_com[0])) {
|
||||
log("-c, --com: expected a number\n");
|
||||
return (0);
|
||||
}
|
||||
args->com = atoi(s_com);
|
||||
if (args->com < 1 || args->com > 20) {
|
||||
log("-c, --com: COM port number should be between 1 and 20\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* open destination file */
|
||||
if (args->localpath) {
|
||||
args->local = fopen(args->localpath, fpmode);
|
||||
if (!args->local) {
|
||||
log("Could not open local file: %s\n", strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* open update.exe file */
|
||||
if (s_uexe) {
|
||||
args->uexe = fopen(s_uexe, "r");
|
||||
if (!args->uexe) {
|
||||
log("Could not open update program: %s\n", strerror(errno));
|
||||
if (args->local) fclose(args->local);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* everything went well :) */
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/Makefile.cfg
|
||||
/obj
|
||||
/update.exe.elf
|
||||
/update.exe.bin
|
||||
/cake.exe.elf
|
||||
/cake.exe.bin
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "libgint"]
|
||||
path = libgint
|
||||
url = http://git.planet-casio.com/lephe/gint.git
|
|
@ -0,0 +1,336 @@
|
|||
GNU General Public License
|
||||
==========================
|
||||
|
||||
_Version 2, June 1991_
|
||||
_Copyright © 1989, 1991 Free Software Foundation, Inc.,_
|
||||
_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
### Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: **(1)** copyright the software, and
|
||||
**(2)** offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
**0.** This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The “Program”, below,
|
||||
refers to any such program or work, and a “work based on the Program”
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term “modification”.) Each licensee is addressed as “you”.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
**1.** You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
**2.** You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
* **a)** You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
* **b)** You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
* **c)** If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
**3.** You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
* **a)** Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
* **b)** Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
* **c)** Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
**4.** You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
**5.** You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
**6.** Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
**7.** If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
**8.** If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
**9.** The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and “any
|
||||
later version”, you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
**10.** If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
### NO WARRANTY
|
||||
|
||||
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
### How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the “copyright” line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w` and `show c` should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w` and `show c`; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a “copyright disclaimer” for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Include variables and message subsystem #
|
||||
#******************************************************************************#
|
||||
include Makefile.vars Makefile.msg
|
||||
|
||||
#******************************************************************************#
|
||||
# General targets #
|
||||
#******************************************************************************#
|
||||
# Build everything.
|
||||
all: all-bin
|
||||
|
||||
# Mostly clean everything (remove everything but the end results).
|
||||
mostlyclean: mostlyclean-bin
|
||||
mclean: mostlyclean
|
||||
|
||||
# Clean everything.
|
||||
clean: clean-bin clean-gint
|
||||
fclean: clean
|
||||
|
||||
# Clean everything with configuration.
|
||||
mrproper: clean
|
||||
$(call rmsg,Removing configuration.)
|
||||
$(call qcmd,$(RM) Makefile.cfg)
|
||||
distclean: mrproper
|
||||
|
||||
# Remake everything (clean and build).
|
||||
re: mostlyclean all
|
||||
|
||||
.PHONY: all mostlyclean mclean clean fclean distclean mrproper re
|
||||
#******************************************************************************#
|
||||
# Configuration (version) checking dependencies #
|
||||
#******************************************************************************#
|
||||
# Define the dependencies.
|
||||
CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \
|
||||
$(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \
|
||||
check-config-version))
|
||||
|
||||
# Define the rules.
|
||||
check-config:
|
||||
@printf "\033[1;31mNo configuration file found!\n"
|
||||
@printf "You should configure before re-running this target.\033[0m\n"
|
||||
@false
|
||||
check-config-version:
|
||||
@printf "\033[1;31mConfiguration version is incorrect!\n"
|
||||
@printf "You should re-configure before re-running this target.\033[0m\n"
|
||||
@false
|
||||
|
||||
.PHONY: check-config check-config-version
|
||||
#******************************************************************************#
|
||||
# Information getting from the Makefile variables #
|
||||
#******************************************************************************#
|
||||
# Get the project name.
|
||||
getname:
|
||||
@echo $(NAME)
|
||||
|
||||
# Get the project version.
|
||||
getversion:
|
||||
@echo $(VERSION)
|
||||
|
||||
# Get the project maintainer.
|
||||
getmaintainer:
|
||||
@echo "$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>"
|
||||
|
||||
.PHONY: getname getmaintainer getversion
|
||||
#******************************************************************************#
|
||||
# gint-related targets #
|
||||
#******************************************************************************#
|
||||
# Main gint target
|
||||
all-gint: $(GLIBDIR)/libgint.a
|
||||
|
||||
# Configure gint libraries.
|
||||
$(GLIBDIR)/gcc.cfg:
|
||||
-$(call qcmd,test -e .git && ! test -e $(GLIBDIR)/.git && \
|
||||
git submodule update --init $(GLIBDIR))
|
||||
$(call bmsg,Configuring gint.)
|
||||
$(call qcmd,cd $(GLIBDIR) && ./configure --no-syscalls)
|
||||
|
||||
# Make gint libraries.
|
||||
$(GLIBDIR)/libgint.a $(GLIBDIR)/libc.a: $(GLIBDIR)/gcc.cfg
|
||||
$(call bmsg,Making gint.)
|
||||
$(call bcmd,make,gint,$(MAKE) $(GLIBDIR) libgint.a libc.a | sed 's/^/ /')
|
||||
|
||||
# Clean gint libraries.
|
||||
clean-gint:
|
||||
$(call rmsg,Cleaning gint.)
|
||||
-$(call qcmd,test -e $(GLIBDIR)/Makefile && \
|
||||
$(MAKE) $(GLIBDIR) distclean | sed 's/^/ /')
|
||||
|
||||
.PHONY: all-gint clean-gint
|
||||
#******************************************************************************#
|
||||
# Binary-related targets #
|
||||
#******************************************************************************#
|
||||
# Make the binary.
|
||||
all-bin: $(CHECKCFG) $(NAME).bin
|
||||
|
||||
# Make the object directory.
|
||||
$(OBJDIR):
|
||||
$(call bcmd,mkdir,$@,$(MD) $@)
|
||||
|
||||
# Make an object file out of an assembly source file.
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.s | $(OBJDIR)
|
||||
$(call bcmd,as,$@,$(AS) -c -o $@ $<)
|
||||
|
||||
# Make an object file out of a C source file.
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
|
||||
$(call bcmd,cc,$@,$(CC) -c -o $@ $< $(CFLAGS))
|
||||
|
||||
# Make the ELF file.
|
||||
$(NAME).elf: all-gint $(SRC:%=$(OBJDIR)/%.o)
|
||||
$(call bcmd,ld,$@,$(LD) -o $@ $(SRC:%=$(OBJDIR)/%.o) $(LDFLAGS))
|
||||
|
||||
# Make the binary file.
|
||||
$(NAME).bin: $(NAME).elf
|
||||
$(call bcmd,objcopy,$@,$(OBJCOPY) -R .comment -R .bss -O binary $< $@)
|
||||
|
||||
# Removing the objects directory.
|
||||
mostlyclean-bin:
|
||||
$(call rmsg,Removing the objects directory.)
|
||||
$(call qcmd,$(RM) -r $(OBJDIR))
|
||||
$(call rmsg,Removing the ELF file.)
|
||||
$(call qcmd,$(RM) *.elf)
|
||||
|
||||
mclean-bin: mostlyclean-bin
|
||||
|
||||
# Remove everything that was built.
|
||||
clean-bin: mostlyclean-bin
|
||||
$(call rmsg,Removing the final binary.)
|
||||
$(call qcmd,$(RM) *.bin)
|
||||
fclean-bin: clean-bin
|
||||
|
||||
# Remake the binary.
|
||||
re-bin: clean-bin all-bin
|
||||
|
||||
.PHONY: all-bin mostlyclean-bin mclean-bin clean-bin fclean-bin re-bin
|
||||
# End of file.
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/make -f
|
||||
# The Makefile message subsystem.
|
||||
# For nice logs. 5 dollars per log only.
|
||||
#******************************************************************************#
|
||||
# Colors and misc #
|
||||
#******************************************************************************#
|
||||
# Used colors ANSI modifiers escape codes
|
||||
color_green := 32
|
||||
color_red := 31
|
||||
color_yellow := 33
|
||||
|
||||
# Newline - comes handy in some situations
|
||||
define \n
|
||||
|
||||
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# General messages #
|
||||
#******************************************************************************#
|
||||
# Command message - display basic info about the command, and run it.
|
||||
define cmd
|
||||
@$(if $(MAKE_FULL_LOG),,printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";)
|
||||
$(if $(MAKE_FULL_LOG),,@)$3
|
||||
endef
|
||||
|
||||
# Quiet command - make it non-quiet if full log is enabled.
|
||||
define qcmd
|
||||
$(if $(MAKE_FULL_LOG),,@)$1
|
||||
endef
|
||||
|
||||
# Normal message - display it.
|
||||
define msg
|
||||
$(if $(MAKE_FULL_LOG),,@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1")
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# Commands #
|
||||
#******************************************************************************#
|
||||
# Build command
|
||||
define bcmd
|
||||
$(call cmd,$1,$2,$3,$(color_green))
|
||||
endef
|
||||
|
||||
#******************************************************************************#
|
||||
# Messages #
|
||||
#******************************************************************************#
|
||||
# Build message
|
||||
define bmsg
|
||||
$(call msg,$1,$(color_green))
|
||||
endef
|
||||
|
||||
# Remove message
|
||||
define rmsg
|
||||
$(call msg,$1,$(color_red))
|
||||
endef
|
||||
|
||||
# Install message
|
||||
define imsg
|
||||
$(call msg,$1,$(color_yellow))
|
||||
endef
|
||||
|
||||
# End of file.
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Include configuration #
|
||||
#******************************************************************************#
|
||||
-include Makefile.cfg
|
||||
|
||||
#******************************************************************************#
|
||||
# Project main information #
|
||||
#******************************************************************************#
|
||||
# Project name.
|
||||
NAME := cake.exe
|
||||
|
||||
# Maintainer information
|
||||
MAINTAINER_NAME := Thomas \"Cakeisalie5\" Touhey
|
||||
MAINTAINER_MAIL := thomas@touhey.fr
|
||||
|
||||
# Project license
|
||||
LICENSE := GPLv2
|
||||
|
||||
# Project version
|
||||
VERSION_MAJOR := 0
|
||||
VERSION_MINOR := 1
|
||||
INDEV := yes
|
||||
VERSION := $(VERSION_MAJOR).$(VERSION_MINOR)$(if $(INDEV),-indev)
|
||||
|
||||
#******************************************************************************#
|
||||
# Project directories #
|
||||
#******************************************************************************#
|
||||
# Headers directory - where all the headers are.
|
||||
INCDIR := ./include
|
||||
|
||||
# Sources directory - where all the source files are.
|
||||
SRCDIR := ./src
|
||||
|
||||
# Objects directory - where the objects will be put.
|
||||
OBJDIR := ./obj
|
||||
|
||||
# Gint lib directory
|
||||
GLIBDIR := ./libgint
|
||||
|
||||
# Gint include directory
|
||||
GINCDIR := ./libgint/include
|
||||
|
||||
#******************************************************************************#
|
||||
# Binary utilities #
|
||||
#******************************************************************************#
|
||||
# C Compiler
|
||||
CC := sh3eb-elf-gcc
|
||||
# - Check flags (for warnings enabling)
|
||||
CHKFLAGS := -Wall -Wextra
|
||||
# - More flags (for profiling, ...)
|
||||
#CMOREFLAGS :=
|
||||
# - All of the C compiler flags
|
||||
CFLAGS := -m3 -mb -Os -ffreestanding -I $(INCDIR) -I $(GINCDIR) $(CHKFLAGS) \
|
||||
-D AUTHOR="$(AUTHOR_NAME)" -D AUTHOR_MAIL="$(AUTHOR_MAIL)" \
|
||||
-D LICENSE="$(LICENSE)" -D VERSION="$(VERSION)" \
|
||||
$(CMOREFLAGS)
|
||||
|
||||
# Assembler
|
||||
AS := sh3eb-elf-as
|
||||
# Linker
|
||||
LD := sh3eb-elf-gcc
|
||||
# - Linker flags
|
||||
LDFLAGS := -nostdlib -T osupd.ld -L $(GLIBDIR) -lgint -lc -lgcc
|
||||
|
||||
# Maker.
|
||||
MAKE := make --no-print-directory -C
|
||||
# Object copier
|
||||
OBJCOPY := sh3eb-elf-objcopy
|
||||
# Directory maker
|
||||
MD := mkdir -p
|
||||
# File remover
|
||||
RM := rm -f
|
||||
|
||||
#******************************************************************************#
|
||||
# Look for sources #
|
||||
#******************************************************************************#
|
||||
# SOURCES
|
||||
SRC := $(basename $(notdir $(shell find $(SRCDIR) -name "*.[cs]")))
|
||||
|
||||
# END OF FILE
|
|
@ -0,0 +1,40 @@
|
|||
# cake.exe - communautary Update.Exe for CASIO calculators
|
||||
## Introduction
|
||||
There is a special command in CASIO's Communication Protocol 7.00: the 0x56
|
||||
command, considered by the community to be the "upload and run" command.
|
||||
|
||||
CASIO uses it to modify the OS on the calculator:
|
||||
- The tools uploads an UpdateExe kernel;
|
||||
- The OS checks the UpdateExe, transfers it to RAM and transfers
|
||||
full machine control to it;
|
||||
- The kernel sets up a Protocol 7 server;
|
||||
- The tool communicates with this server to make operations on the calculator
|
||||
(mainly on flash memory): backup the OS, flash a new OS, ...
|
||||
|
||||
Simon Lothar made his own for fxRemote, using bootcode functions for displaying
|
||||
and communicating (USB, Protocol 7).
|
||||
This project is a community-made update.exe to imitate proprietary CASIO ones
|
||||
and Simon Lothar's one.
|
||||
|
||||
## Restrictions
|
||||
In order to be SH3 and SH4 compatible, the size of the kernel musn't be
|
||||
greater than 64Kio. Also, a full independence from the OS and the bootcode
|
||||
should be seeked, so that this update.exe can also serve for flash-erasure
|
||||
operations - which may come in a very very long time.
|
||||
|
||||
Also, the binary should finish with an identification block --
|
||||
see `src/endblock.c` for details.
|
||||
|
||||
## Making dependencies
|
||||
| Name | Version |
|
||||
| -------------------------------------------------- | ------- |
|
||||
| [sh3eb-elf-gcc](https://gcc.gnu.org/) | >= 4.9 |
|
||||
| [binutils](https://www.gnu.org/software/binutils/) | >= 2.25 |
|
||||
|
||||
## Building
|
||||
|
||||
Just `make`.
|
||||
|
||||
Other useful targets:
|
||||
- `mostlyclean`, `clean`: remove built files.
|
||||
- `re`: remake.
|
|
@ -0,0 +1,8 @@
|
|||
# TODO in Update.exe
|
||||
## As soon as possible
|
||||
- Integrate gint (with USB implemented)
|
||||
- Make a P7 server
|
||||
|
||||
## Later
|
||||
- Find out update.exe-specific commands
|
||||
- Implement flash commands
|
|
@ -0,0 +1,97 @@
|
|||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
#******************************************************************************#
|
||||
# Defaults #
|
||||
#******************************************************************************#
|
||||
# Project variables
|
||||
name="$(make -s getname)"
|
||||
version="$(make -s getversion)"
|
||||
|
||||
# Maintainer
|
||||
maintainer="$(make -s getmaintainer)"
|
||||
|
||||
# Make options
|
||||
make_full_log=
|
||||
|
||||
#******************************************************************************#
|
||||
# Help message #
|
||||
#******************************************************************************#
|
||||
usage() {
|
||||
cat <<EOF
|
||||
\`configure\` configures ${name} to adapt to systems that aren't mine.
|
||||
Usage: $0 [OPTION]
|
||||
|
||||
Defaults for the options are specified in brackets.
|
||||
|
||||
General options:
|
||||
--help display this help and exit
|
||||
--version display version information and quit
|
||||
--make-full-log display full commands while making
|
||||
|
||||
Report bugs to ${maintainer}.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
#******************************************************************************#
|
||||
# Version message #
|
||||
#******************************************************************************#
|
||||
version() {
|
||||
cat <<EOF
|
||||
${name} configure script v${version}
|
||||
Hand-written by Thomas "Cakeisalie5" Touhey.
|
||||
|
||||
This configure script is free software.
|
||||
There is NO warranty; not even for MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
#******************************************************************************#
|
||||
# Check for help and version #
|
||||
#******************************************************************************#
|
||||
put_version=
|
||||
put_help=
|
||||
for arg ; do case "$arg" in
|
||||
--help|-h) put_help=1 ;;
|
||||
--version|-v) put_version=1 ;;
|
||||
esac; done
|
||||
[ $put_version ] && version
|
||||
[ $put_help ] && usage
|
||||
|
||||
#******************************************************************************#
|
||||
# Parse arguments #
|
||||
#******************************************************************************#
|
||||
for arg ; do case "$arg" in
|
||||
--make-full-log) make_full_log=yes ;;
|
||||
*) echo "$arg: didn't read" ;;
|
||||
esac; done
|
||||
|
||||
#******************************************************************************#
|
||||
# Create Makefile configuration #
|
||||
#******************************************************************************#
|
||||
# Clean
|
||||
make mrproper MAKE_FULL_LOG=y 1>/dev/null
|
||||
|
||||
# Write
|
||||
exec 3>&1 1>Makefile.cfg
|
||||
cat <<EOF
|
||||
#!/usr/bin/make -f
|
||||
#******************************************************************************#
|
||||
# Makefile configuration generated by ./configure #
|
||||
#******************************************************************************#
|
||||
# Configuration version and messages configuration
|
||||
CONFIG_VERSION := $version
|
||||
MAKE_FULL_LOG := $make_full_log
|
||||
|
||||
# End of file.
|
||||
EOF
|
||||
exec 1>&3 3>&-
|
||||
chmod +x Makefile.cfg
|
||||
|
||||
# Finish
|
||||
echo "Configuration loaded, you can make now."
|
||||
|
||||
# End of file.
|
|
@ -0,0 +1,10 @@
|
|||
/* ************************************************************************** */
|
||||
/* _____ _ */
|
||||
/* main.h |_ _|__ _ _| |__ ___ _ _ */
|
||||
/* | Project: cake.exe | |/ _ \| | | | '_ \ / _ \ | | | */
|
||||
/* | | (_) | |_| | | | | __/ |_| | */
|
||||
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
||||
/* Last updated: 2017/01/16 18:05:44 |___/ */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# Build directory
|
||||
build/**
|
||||
|
||||
# Sublime Text files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# Object files.
|
||||
*.o
|
||||
|
||||
# Some notes.
|
||||
LIBC
|
||||
|
||||
# Output files
|
||||
libc.a
|
||||
libgint.a
|
||||
gintdemo.g1a
|
||||
|
||||
# Configuration files
|
||||
gcc.cfg
|
|
@ -0,0 +1,210 @@
|
|||
#! /usr/bin/make -f
|
||||
#---
|
||||
#
|
||||
# gint project Makefile.
|
||||
#
|
||||
#---
|
||||
|
||||
|
||||
|
||||
#---
|
||||
# Project variables.
|
||||
#---
|
||||
|
||||
# Modules
|
||||
modules-gint = core clock keyboard mmu mpu rtc screen timer \
|
||||
bopti display gray tales events
|
||||
modules-libc = setjmp string stdio stdlib time
|
||||
|
||||
# Targets
|
||||
target-g1a = gintdemo.g1a
|
||||
target-lib = libgint.a
|
||||
target-std = libc.a
|
||||
|
||||
# Tools
|
||||
cc = sh3eb-elf-gcc
|
||||
as = sh3eb-elf-as
|
||||
ar = sh3eb-elf-ar
|
||||
ob = sh3eb-elf-objcopy
|
||||
wr = g1a-wrapper
|
||||
|
||||
# Flags
|
||||
cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
||||
-W -Wall -Wextra -pedantic @gcc.cfg
|
||||
|
||||
# Demo application (could be done better)
|
||||
demo-src = $(notdir $(wildcard demo/*.[cs]))
|
||||
demo-dep = $(wildcard demo/*.h)
|
||||
demo-ld = demo/gintdemo.ld
|
||||
demo-icon = demo/icon.bmp
|
||||
demo-res = $(notdir $(wildcard demo/resources/*))
|
||||
demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res))
|
||||
demo-elf = build/gintdemo.elf
|
||||
demo-bin = build/gintdemo.bin
|
||||
demo-libs = -L. -lgint -lc -lgcc
|
||||
|
||||
# Specific objects
|
||||
obj-lib-spec = build/display_font_system.bmp.o
|
||||
obj-std-spec =
|
||||
|
||||
# Configuration files
|
||||
config = gcc.cfg
|
||||
|
||||
#---
|
||||
# Automatic variables.
|
||||
#---
|
||||
|
||||
# Modules are subfolders of src/.
|
||||
modules = $(modules-gint) $(modules-libc)
|
||||
|
||||
define n
|
||||
# This is a newline character.
|
||||
|
||||
endef
|
||||
|
||||
ifeq ("$(wildcard $(config))","")
|
||||
$(error "Configuration files are missing. Did you ./configure?")
|
||||
endif
|
||||
|
||||
# Module-scope variables.
|
||||
$(foreach mod, $(modules), $(eval \
|
||||
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
|
||||
mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\
|
||||
mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\
|
||||
mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \
|
||||
))
|
||||
|
||||
# Target-scope variables.
|
||||
obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec)
|
||||
obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec)
|
||||
|
||||
# Dependencies
|
||||
hdr-dep = $(wildcard include/*.h include/internals/*.h)
|
||||
|
||||
|
||||
|
||||
#---
|
||||
# Rule templates.
|
||||
#---
|
||||
|
||||
#ifndef VERBOSE
|
||||
#$(note "default full log")
|
||||
#VERBOSE =
|
||||
#endif
|
||||
|
||||
# C source file template:
|
||||
# $1 module name
|
||||
# $2 filename
|
||||
# $3 dependencies
|
||||
define rule-c-source
|
||||
build/$1_$2.o: src/$1/$2 $3 $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $$<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(cflags) -I src/$1
|
||||
endef
|
||||
|
||||
# asm source file template:
|
||||
# $1 module name
|
||||
# $2 filename
|
||||
define rule-asm-source
|
||||
build/$1_$2.o: src/$1/$2 $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m as $$<\n')
|
||||
$(if $(VERBOSE),,@) $(as) -c $$< -o $$@
|
||||
endef
|
||||
|
||||
|
||||
|
||||
#---
|
||||
# Building.
|
||||
#---
|
||||
|
||||
# Generic rules
|
||||
|
||||
all: $(config) $(target-std) $(target-lib) $(target-g1a)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m All done!\n'
|
||||
|
||||
build:
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n')
|
||||
$(if $(VERBOSE),,@) mkdir -p $@
|
||||
|
||||
$(obj-std) $(obj-lib) $(demo-obj): | build
|
||||
|
||||
$(target-std): $(config) $(obj-std)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
|
||||
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-std)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libc ('
|
||||
@ printf $$(stat -c %s $@)
|
||||
@ printf ' bytes)\n\n'
|
||||
|
||||
$(target-lib): $(config) $(target-std) $(obj-lib)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
|
||||
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-lib)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libgint ('
|
||||
@ printf $$(stat -c %s $@)
|
||||
@ printf ' bytes)\n\n'
|
||||
|
||||
$(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(demo-elf)\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(demo-bin)\n')
|
||||
$(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n')
|
||||
$(if $(VERBOSE),,@) $(wr) $(demo-bin) -o $@ -i $(demo-icon)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built demo application ('
|
||||
@ printf $$(stat -c %s $@)
|
||||
@ printf ' bytes)\n\n'
|
||||
|
||||
# Automated rules
|
||||
|
||||
$(foreach mod,$(modules), \
|
||||
$(foreach source,$(mod-$(mod)-c), $(eval \
|
||||
$(call rule-c-source,$(mod),$(source),$(hdr-dep)))) \
|
||||
$(foreach source,$(mod-$(mod)-asm), $(eval \
|
||||
$(call rule-asm-source,$(mod),$(source)))) \
|
||||
)
|
||||
|
||||
# Specific rules
|
||||
|
||||
# This one should not be optimized. It makes __attribute__((interrupt_handler))
|
||||
# buggy... maybe. Anyway there's some bug in this file that I can't fix now.
|
||||
build/core_gint.c.o: src/core/gint.c $(mod-core-dep) $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) -I src/core -O0
|
||||
|
||||
build/display_font_system.bmp.o: src/display/font_system.bmp
|
||||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
$(if $(VERBOSE),,@) fxconv $< -o $@ --font -n gint_font_system
|
||||
|
||||
# Demo application
|
||||
|
||||
build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags)
|
||||
|
||||
build/demo_font_%.bmp.o: demo/resources/font_%.bmp
|
||||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
$(if $(VERBOSE),,@) fxconv $< -o $@ --font -n $(patsubst demo/resources/%.bmp,res_%,$<)
|
||||
|
||||
build/demo_%.bmp.o: demo/resources/%.bmp
|
||||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
$(if $(VERBOSE),,@) fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<)
|
||||
|
||||
|
||||
|
||||
#---
|
||||
# Cleaning and others.
|
||||
#---
|
||||
|
||||
clean:
|
||||
@ rm -rf build
|
||||
|
||||
mrproper: clean
|
||||
@ rm -f $(target-g1a) $(target-lib) $(target-std)
|
||||
@ rm -f $(config)
|
||||
|
||||
distclean: mrproper
|
||||
|
||||
install:
|
||||
p7 send -f $(target-g1a)
|
||||
|
||||
|
||||
.PHONY: all clean mrproper distclean install help
|
|
@ -0,0 +1,72 @@
|
|||
gint project
|
||||
============
|
||||
|
||||
gint (pronounce 'guin') is a low-level library for fx-9860G calculators. It
|
||||
provides the tools needed to develop programs under Linux using the gcc
|
||||
toolchain (sh3eb-elf).
|
||||
|
||||
By the way, gint is free software; you may use it for any purpose, share it,
|
||||
modify it and share you changes. No credit of any kind is needed, though
|
||||
appreciated.
|
||||
|
||||
|
||||
|
||||
Interrupt handler
|
||||
-----------------
|
||||
|
||||
The interrupt handler is the lowest-level part of the library. It directly
|
||||
accesses the peripheral modules and performs keyboard analyzes, swaps screen
|
||||
buffers, etc.
|
||||
|
||||
gint does not allow user programs to use their own handlers. However, it is
|
||||
possible to map interrupt-driven events to user callbacks using the public API
|
||||
(which is not possible with the system's interrupt handler). This may be
|
||||
particularly useful for timers and RTC (the 16 Hz interrupt can be used as a
|
||||
basis for a physical engine).
|
||||
|
||||
|
||||
|
||||
Public Interface
|
||||
----------------
|
||||
|
||||
gint's API provides access to keyboard, timers, clock and more. It does some
|
||||
powerful drawing and offers reliable multi-getkey, a gray engine, facilitates
|
||||
register access and implements a few standard functions.
|
||||
|
||||
|
||||
|
||||
Building and installing
|
||||
-----------------------
|
||||
|
||||
There are some dependencies:
|
||||
* The `sh3eb-elf` toolchain somewhere in the PATH
|
||||
* The fxSDK installed and available in the PATH
|
||||
|
||||
The easiest way to build gint is simply to enter a terminal and execute `make`.
|
||||
This will build the following components :
|
||||
* `libgint.a`, the gint library
|
||||
* `libc.a`, a (very) few standard procedures
|
||||
* `gintdemo.g1a`, a test application
|
||||
|
||||
The common `clean`, `mrproper`, and `distclean` rules will clean the directory.
|
||||
|
||||
|
||||
|
||||
Source organization
|
||||
-------------------
|
||||
|
||||
gint is made of *modules*. Each module may have any of the following
|
||||
components:
|
||||
* A header file in `/include`
|
||||
* An internal header file in `/include/internals`
|
||||
* Single-function source files in `/src/module`: to avoid linking against the
|
||||
whole library, some functions have their own object files. Their names are
|
||||
those of the functions.
|
||||
* Other source files in `/src/module`: contain multiple functions that always
|
||||
work together, or are lightweight enough not to be separated. Their names
|
||||
often begin with `module_`.
|
||||
* Other files in `/src/module`: the `display` module contains a font, I think.
|
||||
|
||||
The demo application is in the `demo` directory.
|
||||
|
||||
The `doc` folder contains some documentation.
|
|
@ -0,0 +1,33 @@
|
|||
Bugs to fix:
|
||||
- Left-vram overflow when rendering text
|
||||
- A few key hits ignored after leaving the application (could not reproduce)
|
||||
- Lost keyboard control at startup (could not reproduce)
|
||||
- Back-light issues (0xa400012c on SH3, 0xa4050138 on SH4)
|
||||
|
||||
Simple improvements:
|
||||
- bopti: Monochrome bitmaps blending modes
|
||||
- bopti: Partial transparency
|
||||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||
- display: Rectangle-based drawing functions
|
||||
- tales: Test all font encodings
|
||||
- time: Compute CLOCKS_PER_SEC
|
||||
- timer: Add duration and frequency settings
|
||||
- core: Add VBR handlers debugging information (if possible)
|
||||
- core: Implement all callbacks and a complete user API
|
||||
|
||||
Modules to implement:
|
||||
- Serial communication
|
||||
- Sound playback and synthesizing
|
||||
- Handle errors within errno
|
||||
|
||||
Things to investigate:
|
||||
- Packed bit fields alignment
|
||||
- Registers that may need to be saved within setjmp()
|
||||
- Registers that may need to be saved and restored by gint
|
||||
- Possible bug when optimizing __attribute__((interrupt_handler))
|
||||
|
||||
Configuration:
|
||||
- ATEXIT_MAX (16)
|
||||
- RTC_CB_ARRAY_SIZE (5)
|
||||
- EVENTS_QUEUE_SIZE (64)
|
||||
- GINT_NO_SYSCALLS (undefined)
|
|
@ -0,0 +1,78 @@
|
|||
#! /bin/bash
|
||||
|
||||
declare -A conf
|
||||
conf[ATEXIT_MAX]=16
|
||||
conf[RTC_CB_ARRAY_SIZE]=5
|
||||
conf[EVENTS_QUEUE_SIZE]=64
|
||||
conf[GINT_NO_SYSCALLS]=
|
||||
fail=false
|
||||
output="gcc.cfg"
|
||||
|
||||
help()
|
||||
{
|
||||
cat << EOF
|
||||
Configuration script for the gint library.
|
||||
|
||||
Options that affect the behavior of the library:
|
||||
--no-syscalls [default: false]
|
||||
Never use syscalls. Expect some trouble with the malloc() function...
|
||||
Do not trigger this option unless you know what you are doing.
|
||||
|
||||
Options that customize size limits:
|
||||
--atexit-max=<integer> [default: 16]
|
||||
Number of exit handlers that can be registered by atexit().
|
||||
--rtc-callbacks=<integer> [default: 5]
|
||||
Number of RTC callbacks that can be registered.
|
||||
--events-queue-size=<integer> [default: 64]
|
||||
Number of events simultaneously stored in the event queue.
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
for arg; do case "$arg" in
|
||||
-h | --help) help;;
|
||||
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
|
||||
|
||||
--atexit-max=*)
|
||||
size=${arg#*=}
|
||||
if [[ $size == +([0-9]) ]]; then
|
||||
conf[ATEXIT_MAX]=$size
|
||||
else echo "error: --atexit-max expects an integer value"
|
||||
fail=true; fi;;
|
||||
--rtc-callbacks=*)
|
||||
size=${arg#*=}
|
||||
if [[ $size == +([0-9]) ]]; then
|
||||
conf[RTC_CB_ARRAY_SIZE]=$size
|
||||
else echo "error: --rtc-callbacks expects an integer value"
|
||||
fail=true; fi;;
|
||||
--events-queue-size=*)
|
||||
size=${arg#*=}
|
||||
if [[ $size == +([0-9]) ]]; then
|
||||
conf[EVENTS_QUEUE_SIZE]=$size
|
||||
else echo "error: --events-queue-size expects an integer value"
|
||||
fail=true; fi;;
|
||||
|
||||
--atexit-max | --rtc-callbacks | --events-queue-size)
|
||||
echo "error: syntax for $arg is $arg=<integer-value>";;
|
||||
|
||||
*)
|
||||
echo "error: unrecognized argument '$arg'"; fail=true;;
|
||||
esac; done
|
||||
|
||||
output_config()
|
||||
{
|
||||
echo "-D ATEXIT_MAX=${conf[ATEXIT_MAX]}"
|
||||
echo "-D RTC_CB_ARRAY_SIZE=${conf[RTC_CB_ARRAY_SIZE]}"
|
||||
echo "-D EVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}"
|
||||
if [ "${conf[GINT_NO_SYSCALLS]}" != "" ]; then
|
||||
echo "-D GINT_NO_SYSCALLS"
|
||||
fi
|
||||
}
|
||||
|
||||
if $fail; then
|
||||
echo "Configuration has not been modified."
|
||||
else
|
||||
output_config > $output
|
||||
echo "Configuration details have been output to file $output."
|
||||
fi
|
|
@ -0,0 +1,531 @@
|
|||
#include "gintdemo.h"
|
||||
|
||||
#include <mpu.h>
|
||||
#include <gint.h>
|
||||
#include <keyboard.h>
|
||||
#include <display.h>
|
||||
#include <gray.h>
|
||||
|
||||
#include <internals/stdio.h>
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// A few procedures for displaying text aligned on a 21*8 grid.
|
||||
// Not really beautiful... but this will do.
|
||||
//---
|
||||
|
||||
void locate(int x, int y, const char *str)
|
||||
{
|
||||
if(x < 1 || x > 21 || y < 1 || y > 8) return;
|
||||
if(gray_runs()) gtext(x * 6 - 5, y * 8 - 8, str);
|
||||
else dtext(x * 6 - 5, y * 8 - 8, str);
|
||||
}
|
||||
|
||||
void print(int x, int y, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
__printf(0, format, args);
|
||||
va_end(args);
|
||||
|
||||
locate(x, y, __stdio_buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
printf_test()
|
||||
Tests formatting functions.
|
||||
|
||||
void printf_test(void)
|
||||
{
|
||||
dclear();
|
||||
locate(1, 1, "Formatted printing");
|
||||
|
||||
print(2, 3, "%%4.2d 5 :\"%4.2d\"", 5);
|
||||
print(2, 4, "%%-3c '&':\"%-3c\"", '&');
|
||||
print(2, 5, "%%#05x 27 :\"%#05x\"", 27);
|
||||
print(2, 6, "%%1s \"tr\":\"%1s\"", "tr");
|
||||
print(2, 7, "%%6p NULL :\"%6p\"", NULL);
|
||||
|
||||
dupdate();
|
||||
while(getkey() != KEY_EXIT);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
static const unsigned char screen[1024] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 7, 159, 0, 0, 1, 192, 0, 0, 0, 0, 0, 121, 240, 0, 0, 0,
|
||||
31, 191, 192, 0, 3, 224, 27, 216, 0, 0, 1, 251, 252, 0, 0, 0, 57, 247, 222,
|
||||
30, 7, 240, 36, 36, 62, 25, 131, 159, 24, 255, 129, 224, 0, 227, 142, 126, 1,
|
||||
192, 45, 172, 127, 127, 192, 14, 1, 255, 199, 224, 0, 227, 140, 240, 1, 192,
|
||||
26, 88, 115, 127, 224, 14, 57, 221, 207, 0, 0, 227, 13, 192, 1, 192, 34, 68,
|
||||
120, 30, 0, 14, 25, 156, 220, 0, 0, 227, 253, 252, 1, 192, 36, 36, 126, 28,
|
||||
0, 14, 219, 156, 223, 192, 0, 227, 253, 252, 1, 192, 36, 36, 31, 12, 0, 46,
|
||||
27, 140, 223, 192, 0, 227, 141, 193, 193, 192, 40, 20, 7, 140, 0, 206, 25, 140,
|
||||
220, 28, 0, 227, 140, 225, 129, 199, 24, 24, 99, 156, 1, 14, 25, 204, 206, 24,
|
||||
0, 227, 142, 127, 1, 195, 39, 228, 255, 156, 2, 14, 24, 237, 199, 240, 1, 247,
|
||||
222, 62, 1, 198, 44, 44, 223, 30, 2, 31, 28, 237, 131, 224, 1, 224, 0, 0, 3,
|
||||
254, 27, 216, 0, 0, 4, 30, 0, 0, 0, 0, 3, 192, 0, 0, 7, 252, 0, 0, 0, 0, 4,
|
||||
60, 1, 249, 240, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 4, 0, 97, 240, 56, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 224, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 0, 47, 192, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 32, 255, 128, 63, 128,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 32, 255, 0, 48, 78, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 15, 176, 255, 0, 112, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 8, 56, 255, 0,
|
||||
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 8, 60, 255, 0, 224, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 130, 56, 126, 255, 3, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 192,
|
||||
62, 255, 15, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 14, 191, 255, 192, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, 129, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 6, 0, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 7, 128, 63, 192,
|
||||
0, 0, 96, 1, 224, 1, 0, 0, 0, 2, 0, 0, 7, 0, 31, 192, 0, 0, 95, 1, 11, 68, 88,
|
||||
0, 0, 4, 0, 0, 7, 128, 31, 192, 0, 1, 192, 129, 204, 85, 100, 0, 0, 8, 0, 0,
|
||||
15, 128, 63, 224, 0, 0, 95, 1, 8, 85, 68, 0, 1, 144, 0, 0, 31, 128, 143, 224,
|
||||
64, 0, 96, 1, 232, 41, 68, 0, 2, 96, 0, 31, 255, 129, 7, 248, 96, 0, 0, 0, 0,
|
||||
0, 0, 0, 4, 0, 0, 96, 254, 129, 7, 254, 96, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 128,
|
||||
254, 131, 135, 255, 224, 0, 0, 1, 192, 64, 16, 0, 8, 0, 7, 0, 254, 131, 255,
|
||||
63, 224, 0, 0, 1, 38, 113, 208, 0, 8, 0, 13, 0, 222, 147, 254, 31, 224, 0, 0,
|
||||
1, 41, 74, 80, 0, 8, 0, 25, 0, 222, 67, 254, 31, 160, 0, 0, 1, 41, 74, 80, 0,
|
||||
12, 0, 49, 0, 222, 19, 254, 62, 48, 0, 0, 1, 198, 113, 208, 0, 2, 0, 32, 128,
|
||||
222, 195, 255, 252, 56, 0, 0, 0, 0, 0, 0, 0, 2, 0, 124, 64, 220, 151, 135, 248,
|
||||
127, 0, 0, 0, 0, 0, 0, 0, 2, 0, 66, 32, 221, 223, 7, 240, 255, 0, 0, 0, 0, 0,
|
||||
0, 0, 2, 0, 129, 23, 93, 159, 15, 241, 131, 0, 0, 0, 0, 0, 0, 0, 4, 0, 128,
|
||||
136, 217, 95, 3, 226, 9, 0, 0, 1, 240, 0, 0, 0, 4, 0, 128, 72, 89, 95, 129,
|
||||
228, 18, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 72, 73, 127, 128, 224, 36, 0, 0, 0, 0,
|
||||
0, 0, 0, 28, 1, 0, 76, 129, 127, 192, 96, 8, 0, 0, 0, 0, 0, 0, 0, 16, 1, 0,
|
||||
231, 203, 124, 96, 64, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 1, 28, 123, 240, 12, 64,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 16, 1, 2, 28, 143, 128, 15, 192, 7, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 1, 4, 17, 143, 24, 15, 192, 14, 0, 0, 0, 0, 0, 0, 0, 28, 1, 4, 1, 135,
|
||||
24, 31, 192, 24, 0, 0, 0, 0, 0, 0, 0, 18, 1, 62, 1, 135, 248, 63, 224, 192,
|
||||
0, 0, 0, 0, 0, 0, 0, 35, 1, 195, 1, 135, 128, 254, 126, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 35, 193, 131, 195, 135, 255, 248, 112, 1, 0, 0, 0, 0, 0, 0, 0, 67, 241, 131,
|
||||
14, 207, 255, 192, 224, 3, 0, 0, 0, 0, 0, 0, 3, 67, 15, 143, 56, 255, 7, 1,
|
||||
224, 7, 0, 0, 0, 0, 0, 0, 28, 130, 7, 255, 112, 204, 7, 131, 224, 31, 0, 0,
|
||||
0, 0, 0, 0, 32, 134, 30, 29, 120, 156, 7, 255, 224, 127, 0, 0, 0, 0, 0, 63,
|
||||
197, 206, 60, 56, 192, 248, 15, 255, 248, 255, 0, 0, 0, 0, 0, 120, 5, 227, 248,
|
||||
56, 195, 248, 127, 191, 254, 63, 0, 0, 0, 0, 7, 254, 255, 193, 255, 15, 193,
|
||||
255, 15, 31, 252, 31 };
|
||||
|
||||
void ML_bmp_or_cl(const unsigned char *bmp, int x, int y, int width, int height)
|
||||
{
|
||||
unsigned short line;
|
||||
char shift, *screen, *p;
|
||||
int i, j, real_width, begin_x, end_x, begin_y, end_y;
|
||||
char bool1=1, bool2=1, bool3;
|
||||
if(!bmp || x<1-width || x>127 || y<1-height || y>63 || height<1 || width<1) return;
|
||||
p = (char*)&line;
|
||||
real_width = (width-1>>3<<3)+8;
|
||||
if(y < 0) begin_y = -y;
|
||||
else begin_y = 0;
|
||||
if(y+height > 64) end_y = 64-y;
|
||||
else end_y = height;
|
||||
shift = 8-(x&7);
|
||||
if(x<0)
|
||||
{
|
||||
begin_x = -x>>3;
|
||||
if(shift != 8) bool1 = 0;
|
||||
} else begin_x = 0;
|
||||
if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0;
|
||||
else end_x = real_width-1>>3;
|
||||
bool3 = (end_x == real_width-1>>3);
|
||||
screen = display_getCurrentVRAM()+(y+begin_y<<4)+(x>>3);
|
||||
|
||||
for(i=begin_y ; i<end_y ; i++)
|
||||
{
|
||||
if(begin_x < end_x)
|
||||
{
|
||||
line = bmp[i*(real_width>>3)+begin_x] << shift;
|
||||
if(bool1) screen[begin_x] |= *p;
|
||||
if(shift!=8) screen[begin_x+1] |= *(p+1);
|
||||
for(j=begin_x+1 ; j<end_x ; j++)
|
||||
{
|
||||
line = bmp[i*(real_width>>3)+j] << shift;
|
||||
screen[j] |= *p;
|
||||
if(shift!=8) screen[j+1] |= *(p+1);
|
||||
}
|
||||
}
|
||||
line = bmp[i*(real_width>>3)+end_x];
|
||||
if(bool3) line &= -1<<real_width-width;
|
||||
line <<= shift;
|
||||
if(begin_x < end_x || bool1) screen[end_x] |= *p;
|
||||
if(bool2) screen[end_x+1] |= *(p+1);
|
||||
screen += 16;
|
||||
}
|
||||
}
|
||||
|
||||
#include <internals/timer.h>
|
||||
void debug(void)
|
||||
{
|
||||
extern Image res_screen_start;
|
||||
struct mod_tmu *timer;
|
||||
int time1, time2;
|
||||
int i;
|
||||
|
||||
timer_get(TIMER_USER, &timer, NULL);
|
||||
|
||||
dclear();
|
||||
ML_bmp_or_cl(screen, 1, 1, 128, 64);
|
||||
dupdate();
|
||||
getkey();
|
||||
|
||||
dclear();
|
||||
dimage(&res_screen_start, 1, 1);
|
||||
dupdate();
|
||||
getkey();
|
||||
|
||||
dclear();
|
||||
dtext("ML...", 2, 2);
|
||||
dupdate();
|
||||
|
||||
timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0);
|
||||
for(i = 0; i < 1000; i++) ML_bmp_or_cl(screen, 1, 1, 128, 64);
|
||||
time1 = timer->TCNT;
|
||||
timer_stop(TIMER_USER);
|
||||
time1 = 0x0fffffff - time1;
|
||||
|
||||
dclear();
|
||||
dtext("gint...", 2, 2);
|
||||
dupdate();
|
||||
|
||||
timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0);
|
||||
for(i = 0; i < 1000; i++) dimage(&res_screen_start, 1, 1);
|
||||
time2 = timer->TCNT;
|
||||
timer_stop(TIMER_USER);
|
||||
time2 = 0x0fffffff - time2;
|
||||
|
||||
dclear();
|
||||
print_hex(time1, 2, 2);
|
||||
print_hex(time2, 2, 9);
|
||||
dupdate();
|
||||
while(getkey() != KEY_EXIT);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
tlb_debug()
|
||||
Displays the TLB contents and some information. Only available for
|
||||
SH7705, because the SH7305's TLB is much more complicated.
|
||||
|
||||
void tlb_debug(void)
|
||||
{
|
||||
// Entry address address (pointer in the address array), entry data
|
||||
// address (pointer in the data address), and their contents.
|
||||
unsigned int address, data, a, d;
|
||||
// Virtual page number and physical page number.
|
||||
unsigned int vpn, ppn;
|
||||
// Contents of register MMUCR.
|
||||
unsigned mmucr;
|
||||
|
||||
int i, r, key = 0;
|
||||
int way = 0, entry = 0;
|
||||
int pointer_base;
|
||||
|
||||
const char *protection[] = { "pr", "prw", "ar", "arw" };
|
||||
mmucr = *((volatile unsigned int *)gint_reg(Register_MMUCR));
|
||||
|
||||
dclear();
|
||||
locate("MMU register info", 1, 1);
|
||||
locate("MMUCR.IX = ", 2, 3);
|
||||
locate(mmucr & 0x02 ? "1" : "0", 13, 3);
|
||||
dupdate();
|
||||
getkey();
|
||||
|
||||
while(key != KEY_EXIT && way < 4)
|
||||
{
|
||||
dclear();
|
||||
|
||||
print(1, 1, "TLB way=%d %d-%d", way, entry,
|
||||
entry > 29 ? 31 : entry + 2);
|
||||
|
||||
for(i = 0; i < 3 && entry < 32; i++, entry++)
|
||||
{
|
||||
address = 0xf2000000 | (entry << 12) | (way << 8);
|
||||
data = 0xf3000000 | (entry << 12) | (way << 8);
|
||||
|
||||
a = *((volatile unsigned int *)address);
|
||||
d = *((volatile unsigned int *)data);
|
||||
|
||||
ppn = (d >> 10) & 0x00007ffff;
|
||||
// 4-kbyte page
|
||||
if(d & 0x08)
|
||||
{
|
||||
vpn = (a >> 12) | entry;
|
||||
pointer_base = vpn << 12;
|
||||
}
|
||||
// 1-kbyte page
|
||||
else
|
||||
{
|
||||
vpn = (a >> 10) | (entry << 2);
|
||||
pointer_base = vpn << 10;
|
||||
}
|
||||
|
||||
r = 2 * i + 3;
|
||||
print(1, r, "%08x :%08x", pointer_base, ppn << 10);
|
||||
|
||||
r++;
|
||||
locate((d & 0x08) ? "4k" : "1k", 1, r);
|
||||
print(5, r, "pr=%s", protection[(d >> 5) & 3]);
|
||||
locate((d & 0x02) ? "shared" : "exclusive", 13, r);
|
||||
}
|
||||
|
||||
if(entry == 32) entry = 0, way++;
|
||||
|
||||
dupdate();
|
||||
key = getkey();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
main_menu()
|
||||
Displays the main menu and returns user's choice: 0 for [EXIT],
|
||||
application numbers otherwise. Sets the ctaegory and application
|
||||
number.
|
||||
*/
|
||||
void main_menu(int *category, int *app)
|
||||
{
|
||||
//---
|
||||
// Quite a few things to declare...
|
||||
//---
|
||||
|
||||
extern Image res_opt_menu;
|
||||
|
||||
const char *mpu, *mpu_names[] = {
|
||||
"Unknown",
|
||||
"SH7337",
|
||||
"SH7355",
|
||||
"SH7305",
|
||||
"SH7724",
|
||||
"[error]"
|
||||
};
|
||||
|
||||
const char *list_tests[] = {
|
||||
"Keyboard",
|
||||
"Gray engine",
|
||||
"Image rendering",
|
||||
"Text rendering",
|
||||
"Real-time clock",
|
||||
"Clocks and timers",
|
||||
NULL
|
||||
};
|
||||
const char *list_perfs[] = {
|
||||
"Image rendering",
|
||||
"Text rendering",
|
||||
NULL
|
||||
};
|
||||
const char *list_debug[] = {
|
||||
"View TLB (SH3 only)",
|
||||
NULL
|
||||
};
|
||||
const char **list = NULL;
|
||||
int list_len = 0;
|
||||
|
||||
extern unsigned int bgint, egint;
|
||||
extern unsigned int romdata;
|
||||
int gint_size = (char *)&egint - (char *)&bgint;
|
||||
|
||||
|
||||
|
||||
static int tab = 0, index = 0, scroll = 0;
|
||||
// Set to 1 when interface has to be redrawn.
|
||||
int leave = 1;
|
||||
int i;
|
||||
|
||||
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
|
||||
text_configure(NULL, Color_Black);
|
||||
|
||||
while(1)
|
||||
{
|
||||
//---
|
||||
// Displaying the current tab.
|
||||
//---
|
||||
|
||||
dclear();
|
||||
dupdate();
|
||||
|
||||
switch(tab)
|
||||
{
|
||||
case 0:
|
||||
locate(1, 1, "Demo application");
|
||||
print(2, 3, "gint version: %5s", GINT_VERSION_STR);
|
||||
print(2, 4, "handler size: %5d", gint_size);
|
||||
print(2, 5, "mpu type: %7s", mpu);
|
||||
print(2, 6, "romdata: %08x", &romdata);
|
||||
|
||||
list = NULL;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
locate(1, 1, "Test list");
|
||||
list = list_tests;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
locate(1, 1, "Performance");
|
||||
list = list_perfs;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
locate(1, 1, "Debug");
|
||||
list = list_debug;
|
||||
break;
|
||||
|
||||
default:
|
||||
print(1, 1, "Tab %d", tab);
|
||||
break;
|
||||
}
|
||||
dimage(0, 56, &res_opt_menu);
|
||||
|
||||
if(list)
|
||||
{
|
||||
list_len = 0;
|
||||
while(list[list_len]) list_len++;
|
||||
|
||||
for(i = scroll; list[i] && i < scroll + 6; i++)
|
||||
locate(2, i - scroll + 2, list[i]);
|
||||
|
||||
if(scroll > 0) locate(20, 2, "\x0d");
|
||||
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
|
||||
|
||||
dreverse_area(0, 8 * (index - scroll) + 8, 127,
|
||||
8 * (index - scroll) + 15);
|
||||
}
|
||||
dupdate();
|
||||
|
||||
//---
|
||||
// Waiting for events.
|
||||
//---
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
|
||||
switch(getkey())
|
||||
{
|
||||
case KEY_F1:
|
||||
tab = 0;
|
||||
index = 0;
|
||||
break;
|
||||
case KEY_F2:
|
||||
tab = 1;
|
||||
index = 0;
|
||||
scroll = 0;
|
||||
break;
|
||||
case KEY_F3:
|
||||
tab = 2;
|
||||
index = 0;
|
||||
scroll = 0;
|
||||
break;
|
||||
case KEY_F4:
|
||||
tab = 3;
|
||||
index = 0;
|
||||
scroll = 0;
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
if(list && list_len > 1)
|
||||
{
|
||||
if(index)
|
||||
{
|
||||
index--;
|
||||
if(index < scroll) scroll--;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = list_len - 1;
|
||||
scroll = list_len - 6;
|
||||
if(scroll < 0) scroll = 0;
|
||||
}
|
||||
}
|
||||
else leave = 0;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(list && list_len > 1)
|
||||
{
|
||||
if(list[index + 1])
|
||||
{
|
||||
index++;
|
||||
if(index >= scroll + 6)
|
||||
scroll++;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
scroll = 0;
|
||||
}
|
||||
}
|
||||
else leave = 0;
|
||||
break;
|
||||
|
||||
case KEY_EXE:
|
||||
if(!tab) break;
|
||||
if(category) *category = tab;
|
||||
if(app) *app = index + 1;
|
||||
return;
|
||||
|
||||
case KEY_MENU:
|
||||
if(category) *category = 0;
|
||||
if(app) *app = 0;
|
||||
return;
|
||||
|
||||
default:
|
||||
leave = 0;
|
||||
}
|
||||
}
|
||||
while(!leave);
|
||||
}
|
||||
|
||||
if(category) *category = 0;
|
||||
if(app) *app = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
main()
|
||||
No need for description.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
int category, app;
|
||||
|
||||
while(1)
|
||||
{
|
||||
main_menu(&category, &app);
|
||||
if(!category) break;
|
||||
|
||||
switch((category << 8) | app)
|
||||
{
|
||||
case 0x0101:
|
||||
test_keyboard();
|
||||
break;
|
||||
case 0x0102:
|
||||
test_gray();
|
||||
break;
|
||||
case 0x0103:
|
||||
test_bopti();
|
||||
break;
|
||||
case 0x0104:
|
||||
test_tales();
|
||||
break;
|
||||
case 0x0105:
|
||||
test_rtc();
|
||||
break;
|
||||
case 0x0106:
|
||||
test_timer();
|
||||
break;
|
||||
|
||||
case 0x0201:
|
||||
// perf_bopti();
|
||||
break;
|
||||
case 0x0202:
|
||||
// perf_tales();
|
||||
break;
|
||||
|
||||
case 0x0301:
|
||||
// if(isSH3()) debug_tlb();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//---
|
||||
//
|
||||
// gint demo application
|
||||
//
|
||||
// Displays some tests cases for many features of the library.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _GINTDEMO_H
|
||||
#define _GINTDEMO_H
|
||||
|
||||
//---
|
||||
// Main routines and common functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
main()
|
||||
No need for description.
|
||||
*/
|
||||
int main(void);
|
||||
|
||||
/*
|
||||
main_menu()
|
||||
Displays the main menu and returns user's choice by setting the
|
||||
category and application. Category is 0 when the user leaves the
|
||||
application.
|
||||
*/
|
||||
void main_menu(int *category, int *app);
|
||||
|
||||
/*
|
||||
locate()
|
||||
Displays text using a system-like monospaced font on a 21*8 grid.
|
||||
*/
|
||||
void locate(int x, int y, const char *str);
|
||||
|
||||
/*
|
||||
print()
|
||||
Locates a string using formatted printing.
|
||||
*/
|
||||
void print(int x, int y, const char *format, ...);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Test applications.
|
||||
//---
|
||||
|
||||
/*
|
||||
test_keyboard()
|
||||
Displays a real-time multigetkey() and the keyboard state.
|
||||
*/
|
||||
void test_keyboard(void);
|
||||
|
||||
/*
|
||||
test_gray()
|
||||
Lets the user set the gray delays and see the results.
|
||||
*/
|
||||
void test_gray(void);
|
||||
|
||||
/*
|
||||
test_bopti()
|
||||
Displays and moves many kinds of bitmaps.
|
||||
*/
|
||||
void test_bopti(void);
|
||||
|
||||
/*
|
||||
test_tales()
|
||||
Displays some text using different modes and clipping options.
|
||||
*/
|
||||
void test_tales(void);
|
||||
|
||||
/*
|
||||
test_rtc()
|
||||
Just a clock.
|
||||
*/
|
||||
void test_rtc(void);
|
||||
|
||||
/*
|
||||
test_timer()
|
||||
Clock timer and timer precision.
|
||||
*/
|
||||
void test_timer(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Performance applications.
|
||||
//---
|
||||
|
||||
/*
|
||||
perf_bopti()
|
||||
Compares bopti and MonochromeLib.
|
||||
*/
|
||||
void perf_bopti(void);
|
||||
|
||||
/*
|
||||
perf_tales()
|
||||
Compares tales and the system's text rendering functions.
|
||||
*/
|
||||
void perf_tales(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Debug applications.
|
||||
//---
|
||||
|
||||
/*
|
||||
debug_tlb()
|
||||
On SH7705, displays the TLB contents. Does nothing on SH7305.
|
||||
*/
|
||||
void debug_tlb(void);
|
||||
|
||||
#endif // _GINTDEMO_H
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
This linker script links the object files when generating the ELF
|
||||
output. Note how symbols romdata, bbss, ebss, bdata and edata are used
|
||||
in the initialization routine (crt0.c) to initialize the application.
|
||||
|
||||
Two ram areas are specified. The "real ram" is accessed direcly while
|
||||
the other area is virtualized. It is not possible to execute code in
|
||||
virtualized ram.
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH(sh3)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
rom : o = 0x00300200, l = 512k
|
||||
/* 0x0810000 is apparently mapped to 0x8801c0000. */
|
||||
ram : o = 0x08100000, l = 8k
|
||||
realram : o = 0x8800d000, l = 12k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
ROM sections : binary code and read-only data.
|
||||
*/
|
||||
|
||||
.text : {
|
||||
/* Initialization code. */
|
||||
*(.pretext.entry)
|
||||
*(.pretext)
|
||||
|
||||
_bctors = . ;
|
||||
*(.ctors)
|
||||
_ectors = . ;
|
||||
_bdtors = . ;
|
||||
*(.dtors)
|
||||
_edtors = . ;
|
||||
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
} > rom
|
||||
|
||||
.rodata : {
|
||||
*(.rodata.fxconv);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
|
||||
_romdata = ALIGN(4) ;
|
||||
} > rom
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RAM sections : bss section and read/write data.
|
||||
The BSS section is meant to be stripped from the ELF file (to
|
||||
reduce the binary size) and initialized with zeros in the
|
||||
initialization routine, therefore its location is undefined.
|
||||
*/
|
||||
|
||||
.bss : {
|
||||
_bbss = . ;
|
||||
*(.bss)
|
||||
_ebss = . ;
|
||||
} > ram
|
||||
|
||||
.data : AT(_romdata) ALIGN(4) {
|
||||
_bdata = . ;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
_edata = . ;
|
||||
} > ram
|
||||
|
||||
.cc : AT(_romdata + SIZEOF(.data)) ALIGN(4) {
|
||||
*(.eh_frame)
|
||||
*(.jcr)
|
||||
|
||||
_gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ;
|
||||
} > ram
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Real RAM : interrupt, exception and TLB miss handlers.
|
||||
*/
|
||||
|
||||
.gint : AT(_gint_data) ALIGN(4) {
|
||||
/* The vbr needs to be 0x100-aligned because of an ld issue. */
|
||||
. = ALIGN(0x100) ;
|
||||
_gint_vbr = . ;
|
||||
_bgint = . ;
|
||||
|
||||
/* Exception handler. */
|
||||
. = _gint_vbr + 0x100 ;
|
||||
*(.gint.exc.entry)
|
||||
*(.gint.exc)
|
||||
|
||||
/* TLB miss handler. */
|
||||
. = _gint_vbr + 0x400 ;
|
||||
*(.gint.tlb.entry)
|
||||
*(.gint.tlb)
|
||||
|
||||
/* Interrupt handler. */
|
||||
. = _gint_vbr + 0x600 ;
|
||||
*(.gint.int.entry)
|
||||
*(.gint.int)
|
||||
|
||||
_egint = . ;
|
||||
} > realram
|
||||
}
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 71 KiB |
|
@ -0,0 +1,221 @@
|
|||
#include "gintdemo.h"
|
||||
#include <display.h>
|
||||
#include <gray.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
#include <internals/bopti.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
test_bopti()
|
||||
Displays and moves many kinds of bitmaps. Here are the images used:
|
||||
|
||||
Name Size Color Alpha
|
||||
---------------------------------------------------------
|
||||
items.bmp 266 * 124 Gray -
|
||||
sprites.bmp 66 * 33 Gray -
|
||||
swords.bmp 88 * 16 Gray Full
|
||||
---------------------------------------------------------
|
||||
zelda.bmp 86 * 280 Mono -
|
||||
isometric.bmp 37 * 27 Mono Full
|
||||
Mono Greater
|
||||
---------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void getwh(Image *img, int *width, int *height)
|
||||
{
|
||||
const unsigned char *data;
|
||||
|
||||
if(!img)
|
||||
{
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
return;
|
||||
}
|
||||
*width = img->width;
|
||||
*height = img->height;
|
||||
if(*width && *height) return;
|
||||
|
||||
data = img->data;
|
||||
*width = (data[0] << 8) | data[1];
|
||||
*height = (data[2] << 8) | data[3];
|
||||
}
|
||||
|
||||
static void getxy(Image *img, int *x, int *y)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
getwh(img, &width, &height);
|
||||
*x = 64 - (width >> 1);
|
||||
*y = 28 - (height >> 1);
|
||||
}
|
||||
|
||||
static Image *select(Image *current)
|
||||
{
|
||||
extern Image res_bopti_thumbs;
|
||||
extern Image
|
||||
res_items,
|
||||
res_sprites,
|
||||
res_swords,
|
||||
res_zelda,
|
||||
res_isometric;
|
||||
|
||||
struct {
|
||||
Image *img;
|
||||
const char *name;
|
||||
const char *info;
|
||||
} images[] = {
|
||||
{ &res_items, "Items", "Gray" },
|
||||
{ &res_sprites, "Sprites", "Gray" },
|
||||
{ &res_swords, "Swords", "Gray Alpha" },
|
||||
{ &res_zelda, "Zelda", "Mono" },
|
||||
{ &res_isometric, "Isometric", "Mono Alpha" },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
Image *thumbs = &res_bopti_thumbs;
|
||||
int items = 0;
|
||||
static int row = 0;
|
||||
int leave = 1, i;
|
||||
|
||||
while(images[items].img) items++;
|
||||
|
||||
gray_start();
|
||||
|
||||
while(1)
|
||||
{
|
||||
gclear();
|
||||
locate(1, 1, "Select an image:");
|
||||
|
||||
for(i = 0; i < items && i < 7; i++)
|
||||
{
|
||||
locate(2, 2 + i + (i > row), images[i].name);
|
||||
gimage_part(100, 8 + 8 * (i + (i > row)), thumbs, 0,
|
||||
8 * i, 7, 7);
|
||||
if(i == row)
|
||||
{
|
||||
int width, height;
|
||||
getwh(images[i].img, &width, &height);
|
||||
print(2, 2 + i + 1, "%d\x04%d", width, height);
|
||||
locate(10, 2 + i + 1, images[i].info);
|
||||
}
|
||||
}
|
||||
|
||||
greverse_area(0, 8 * row + 8, 128, 8 * row + 23);
|
||||
gupdate();
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
|
||||
switch(getkey())
|
||||
{
|
||||
case KEY_UP:
|
||||
row = (row + items - 1) % items;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
row = (row + 1) % items;
|
||||
break;
|
||||
case KEY_EXE:
|
||||
return images[row].img;
|
||||
case KEY_EXIT:
|
||||
return current;
|
||||
default:
|
||||
leave = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(!leave);
|
||||
}
|
||||
|
||||
gray_stop();
|
||||
}
|
||||
|
||||
void test_bopti(void)
|
||||
{
|
||||
extern Image res_opt_bitmap;
|
||||
Image *img = NULL;
|
||||
|
||||
int leave = 1;
|
||||
int black_bg = 0;
|
||||
int x = 0, y = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(img && (img->format & Channel_Light))
|
||||
{
|
||||
gray_start();
|
||||
gclear();
|
||||
|
||||
if(black_bg) greverse_area(0, 0, 127, 63);
|
||||
if(img) gimage(x, y, img);
|
||||
|
||||
gclear_area(0, 55, 127, 63);
|
||||
gimage(0, 56, &res_opt_bitmap);
|
||||
gupdate();
|
||||
}
|
||||
else if(img)
|
||||
{
|
||||
gray_stop();
|
||||
dclear();
|
||||
|
||||
if(black_bg) dreverse_area(0, 0, 127, 63);
|
||||
if(img) dimage(x, y, img);
|
||||
|
||||
dclear_area(0, 55, 127, 63);
|
||||
dimage(0, 56, &res_opt_bitmap);
|
||||
dupdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
gray_stop();
|
||||
|
||||
dclear();
|
||||
locate(3, 3, "No image selected");
|
||||
|
||||
dimage(0, 56, &res_opt_bitmap);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
|
||||
switch(getkey())
|
||||
{
|
||||
case KEY_EXIT:
|
||||
gray_stop();
|
||||
return;
|
||||
|
||||
case KEY_F1:
|
||||
img = select(img);
|
||||
getxy(img, &x, &y);
|
||||
break;
|
||||
case KEY_F5:
|
||||
black_bg = !black_bg;
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
y--;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
y++;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
x--;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
x++;
|
||||
break;
|
||||
|
||||
default:
|
||||
leave = 0;
|
||||
}
|
||||
}
|
||||
while(!leave);
|
||||
}
|
||||
|
||||
gray_stop();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include "gintdemo.h"
|
||||
#include <gray.h>
|
||||
#include <keyboard.h>
|
||||
#include <mpu.h>
|
||||
|
||||
/*
|
||||
test_gray()
|
||||
Lets the user set the gray delays and see the results.
|
||||
*/
|
||||
|
||||
static void draw(int delay1, int delay2, int selected)
|
||||
{
|
||||
extern Image res_opt_gray;
|
||||
unsigned int *vl = gray_lightVRAM();
|
||||
unsigned int *vd = gray_darkVRAM();
|
||||
|
||||
gclear();
|
||||
locate(1, 1, "Gray engine");
|
||||
|
||||
for(int i = 0; i < 36; i++)
|
||||
{
|
||||
int o = ((i + 12) << 2) + 2;
|
||||
unsigned light = -((i % 24) < 12);
|
||||
unsigned dark = -(i < 24);
|
||||
vl[o] = light >> 8;
|
||||
vl[o + 1] = light << 8;
|
||||
vd[o] = dark >> 8;
|
||||
vd[o + 1] = dark << 8;
|
||||
}
|
||||
|
||||
locate(3, 3, "light");
|
||||
print(4, 4, "%d", delay1);
|
||||
|
||||
locate(3, 5, "dark");
|
||||
print(4, 6, "%d", delay2);
|
||||
|
||||
locate(3, selected ? 6 : 4, "\x02");
|
||||
|
||||
gimage(0, 56, &res_opt_gray);
|
||||
gupdate();
|
||||
}
|
||||
|
||||
void test_gray(void)
|
||||
{
|
||||
int delays[2]; // { light, dark }
|
||||
int key, changed = 1;
|
||||
int selected = 0;
|
||||
|
||||
gray_getDelays(delays, delays + 1);
|
||||
gray_start();
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(changed)
|
||||
{
|
||||
gray_setDelays(delays[0], delays[1]);
|
||||
draw(delays[0], delays[1], selected);
|
||||
}
|
||||
changed = 0;
|
||||
|
||||
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
|
||||
if(key == KEY_EXIT) break;
|
||||
|
||||
changed = 1;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case KEY_F1:
|
||||
selected = !selected;
|
||||
break;
|
||||
case KEY_F2:
|
||||
delays[0] = 912;
|
||||
delays[1] = 1343;
|
||||
break;
|
||||
case KEY_F3:
|
||||
delays[0] = 993;
|
||||
delays[1] = 1609;
|
||||
break;
|
||||
case KEY_F4:
|
||||
delays[0] = 860;
|
||||
delays[1] = 1298;
|
||||
break;
|
||||
case KEY_UP:
|
||||
delays[selected] += 10;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(delays[selected] >= 110) delays[selected] -= 10;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
delays[selected]++;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
if(delays[selected] >= 101) delays[selected]--;
|
||||
break;
|
||||
default:
|
||||
changed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gray_stop();
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
#include "gintdemo.h"
|
||||
#include <display.h>
|
||||
#include <keyboard.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
test_keyboard()
|
||||
Displays a real-time multigetkey() and the keyboard state.
|
||||
*/
|
||||
|
||||
static void draw(volatile unsigned char *state)
|
||||
{
|
||||
int i, j, k, l;
|
||||
int x, y;
|
||||
|
||||
for(i = 0; i < 10; i++) for(j = 1; j < 8; j++)
|
||||
{
|
||||
// Eliminating keys that do not exist.
|
||||
if(!i && j != 7) continue;
|
||||
if(i && j == 7) continue;
|
||||
if(i <= 4 && j == 6) continue;
|
||||
if(i == 4 && j == 5) continue;
|
||||
|
||||
x = 5 * j + 1;
|
||||
y = 61 - 5 * i;
|
||||
// Moving the [AC/ON] key.
|
||||
if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4);
|
||||
|
||||
// Drawing a filled shape when the key is pressed.
|
||||
if(state[i] & (128 >> j))
|
||||
{
|
||||
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
|
||||
if(abs(k) + abs(l) <= 2)
|
||||
dpixel(x + k, y + l, Color_Black);
|
||||
}
|
||||
// Drawing a square border otherwise.
|
||||
else
|
||||
{
|
||||
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
|
||||
if(k || l) dpixel(x + k, y + l, Color_Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_keyboard(void)
|
||||
{
|
||||
const char *key_names[] = {
|
||||
"F1", "F2", "F3", "F4", "F5", "F6",
|
||||
"SHIFT", "OPTN", "VARS", "MENU", "Left", "Up",
|
||||
"ALPHA", "x^2", "^", "EXIT", "Down", "Right",
|
||||
"X,\x1d,T", "log", "ln", "sin", "cos", "tan",
|
||||
"[frac]", "F\x0f\x09" "D", "(", ")", ",", "\x09",
|
||||
"7", "8", "9", "DEL", "AC/ON", NULL,
|
||||
"4", "5", "6", "\x04", "\x05", NULL,
|
||||
"1", "2", "3", "+", "-", NULL,
|
||||
"0", ".", "\x08", "(-)", "EXE", NULL
|
||||
};
|
||||
|
||||
volatile unsigned char *state = keystate();
|
||||
int keys[4] = { 0 };
|
||||
int i;
|
||||
|
||||
while(1)
|
||||
{
|
||||
dclear();
|
||||
locate(1, 1, "Keyboard driver");
|
||||
locate(8, 3, "Pressed keys:");
|
||||
draw(state);
|
||||
|
||||
if(keys[0] == KEY_NONE) locate(9, 4, ":None");
|
||||
else for(i = 0; i < 4 && keys[i] != KEY_NONE; i++)
|
||||
{
|
||||
locate( 9, i + 4, ":");
|
||||
locate(10, i + 4, key_names[keyid(keys[i])]);
|
||||
}
|
||||
|
||||
dupdate();
|
||||
|
||||
multigetkey(keys, 4, 1);
|
||||
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
#include "gintdemo.h"
|
||||
#include <display.h>
|
||||
#include <rtc.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
test_rtc()
|
||||
Just a clock. Of course using all this RTCTime conversion and this / 10
|
||||
is awfully un-optimized, but it's a test case so it's made to check the
|
||||
values in the structure are correct.
|
||||
*/
|
||||
|
||||
#include <internals/rtc.h>
|
||||
#include <mpu.h>
|
||||
|
||||
static void draw(struct RTCTime time)
|
||||
{
|
||||
extern Image res_rtc_segments;
|
||||
|
||||
const char *days[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
}, *months[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
|
||||
"Oct", "Nov", "Dec"
|
||||
};
|
||||
int x[6] = { 20, 33, 52, 65, 84, 97 };
|
||||
int digits[6];
|
||||
int i;
|
||||
|
||||
digits[0] = time.hours / 10;
|
||||
digits[1] = time.hours % 10;
|
||||
digits[2] = time.minutes / 10;
|
||||
digits[3] = time.minutes % 10;
|
||||
digits[4] = time.seconds / 10;
|
||||
digits[5] = time.seconds % 10;
|
||||
|
||||
// Drawing digits.
|
||||
for(i = 0; i < 6; i++) dimage_part(x[i], 8, &res_rtc_segments,
|
||||
12 * digits[i], 0, 11, 19);
|
||||
// Drawing ':' between pairs of digits.
|
||||
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
|
||||
14 + 5 * !!(i & 4) + !!(i & 2), Color_Black);
|
||||
|
||||
// This should print time.year + 1900 but for the sake of this demo we
|
||||
// have tweaked the field so that it already contains time.year + 1900.
|
||||
print(4, 6, "%s %s %02d %4d", days[time.week_day],
|
||||
months[time.month], time.month_day, time.year);
|
||||
}
|
||||
|
||||
static void callback(void)
|
||||
{
|
||||
extern Image res_opt_rtc;
|
||||
struct RTCTime time = rtc_getTime();
|
||||
time.year += 1900;
|
||||
|
||||
dclear();
|
||||
draw(time);
|
||||
dimage_part(0, 56, &res_opt_rtc, 0, 0, 19, 8);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
static void set_region(struct RTCTime *time, int region, int value)
|
||||
{
|
||||
switch(region)
|
||||
{
|
||||
case 0:
|
||||
time->hours = 10 * value + (time->hours % 10);
|
||||
break;
|
||||
case 1:
|
||||
time->hours = time->hours - (time->hours % 10) + value;
|
||||
break;
|
||||
case 2:
|
||||
time->minutes = 10 * value + (time->minutes % 10);
|
||||
break;
|
||||
case 3:
|
||||
time->minutes = time->minutes - (time->minutes % 10) + value;
|
||||
break;
|
||||
case 4:
|
||||
time->seconds = 10 * value + (time->seconds % 10);
|
||||
break;
|
||||
case 5:
|
||||
time->seconds = time->seconds - (time->seconds % 10) + value;
|
||||
break;
|
||||
case 6:
|
||||
time->week_day = value;
|
||||
break;
|
||||
case 7:
|
||||
time->month = value;
|
||||
break;
|
||||
case 8:
|
||||
time->month_day = 10 * value + (time->month_day % 10);
|
||||
break;
|
||||
case 9:
|
||||
time->month_day = time->month_day - (time->month_day % 10)
|
||||
+ value;
|
||||
break;
|
||||
case 10:
|
||||
time->year = 1000 * value + (time->year % 1000);
|
||||
break;
|
||||
case 11:
|
||||
time->year = time->year - (time->year % 1000) + 100 * value
|
||||
+ (time->year % 100);
|
||||
break;
|
||||
case 12:
|
||||
time->year = time->year - (time->year % 100) + 10 * value
|
||||
+ (time->year % 10);
|
||||
break;
|
||||
case 13:
|
||||
time->year = time->year - (time->year % 10) + value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set(void)
|
||||
{
|
||||
extern Image res_opt_rtc;
|
||||
Image *opt = &res_opt_rtc;
|
||||
|
||||
struct {
|
||||
int x, y;
|
||||
int w, h;
|
||||
} regions[] = {
|
||||
{ 19, 7, 13, 21 }, { 32, 7, 13, 21 }, { 51, 7, 13, 21 },
|
||||
{ 64, 7, 13, 21 }, { 83, 7, 13, 21 }, { 96, 7, 13, 21 },
|
||||
{ 18, 39, 19, 9 }, { 42, 39, 19, 9 }, { 66, 39, 7, 9 },
|
||||
{ 72, 39, 7, 9 }, { 84, 39, 7, 9 }, { 90, 39, 7, 9 },
|
||||
{ 96, 39, 7, 9 }, { 102, 39, 7, 9 },
|
||||
};
|
||||
struct RTCTime time = rtc_getTime();
|
||||
int region_count = 14;
|
||||
int n = 0, slide = 0, key, leave;
|
||||
|
||||
time.year += 1900;
|
||||
|
||||
while(1)
|
||||
{
|
||||
dclear();
|
||||
draw(time);
|
||||
dreverse_area(regions[n].x, regions[n].y, regions[n].x
|
||||
+ regions[n].w - 1, regions[n].y + regions[n].h - 1);
|
||||
|
||||
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
|
||||
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
|
||||
else dimage_part(0, 56, opt, 22 + 22 * (n == region_count - 1),
|
||||
0, 19, 8);
|
||||
|
||||
dupdate();
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
key = getkey();
|
||||
if(key == KEY_EXIT) return;
|
||||
|
||||
else if(key == KEY_F1 || key == KEY_EXE)
|
||||
{
|
||||
n++;
|
||||
slide = 0;
|
||||
if(n == region_count)
|
||||
{
|
||||
time.year -= 1900;
|
||||
rtc_setTime(time);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if(key == KEY_F6)
|
||||
{
|
||||
if(n == 6) slide = (slide + 1) % 2;
|
||||
if(n == 7) slide = (slide + 1) % 3;
|
||||
}
|
||||
|
||||
else if((key & 0x0f) == 9) // Other F-keys
|
||||
{
|
||||
int k = 7 - (key >> 4); // Number of F-key
|
||||
|
||||
if(n == 7)
|
||||
{
|
||||
int month = k + 4 * slide - 2;
|
||||
set_region(&time, n, month);
|
||||
n++;
|
||||
slide = 0;
|
||||
}
|
||||
|
||||
else if(n == 6 && (slide != 1 || k != 5))
|
||||
{
|
||||
int day = k + 4 * slide - 1;
|
||||
set_region(&time, n, day);
|
||||
n++;
|
||||
slide = 0;
|
||||
}
|
||||
|
||||
else leave = 0;
|
||||
}
|
||||
|
||||
else if(isdigit(keychar(key))) // Numbers
|
||||
{
|
||||
int val = keychar(key) - '0';
|
||||
int ok = 1;
|
||||
|
||||
if(n == 0) ok = (val <= 2);
|
||||
if(n == 1)
|
||||
{
|
||||
int max = time.hours >= 20 ? 3 : 9;
|
||||
ok = (val <= max);
|
||||
}
|
||||
if(n == 2 || n == 4) ok = (val <= 5);
|
||||
if(n == 8) ok = (val <= 3);
|
||||
if(n == 9)
|
||||
{
|
||||
int max = time.month_day >= 30 ? 1 : 9;
|
||||
ok = (val <= max);
|
||||
}
|
||||
|
||||
if(ok)
|
||||
{
|
||||
set_region(&time, n, val);
|
||||
n++;
|
||||
if(n == region_count)
|
||||
{
|
||||
time.year -= 1900;
|
||||
rtc_setTime(time);
|
||||
return;
|
||||
}
|
||||
slide = 0;
|
||||
}
|
||||
else leave = 0;
|
||||
}
|
||||
|
||||
else leave = 0;
|
||||
} while(!leave);
|
||||
}
|
||||
|
||||
while(getkey() != KEY_EXIT);
|
||||
}
|
||||
|
||||
void test_rtc(void)
|
||||
{
|
||||
int key, cb_id;
|
||||
|
||||
cb_id = rtc_cb_add(RTCFreq_1Hz, callback, 0);
|
||||
callback();
|
||||
|
||||
while(1)
|
||||
{
|
||||
key = getkey();
|
||||
|
||||
if(key == KEY_EXIT) break;
|
||||
if(key == KEY_F1)
|
||||
{
|
||||
rtc_cb_edit(cb_id, RTCFreq_None, NULL);
|
||||
set();
|
||||
callback();
|
||||
rtc_cb_edit(cb_id, RTCFreq_1Hz, callback);
|
||||
}
|
||||
}
|
||||
|
||||
rtc_cb_end(cb_id);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
#include "gintdemo.h"
|
||||
#include <display.h>
|
||||
#include <keyboard.h>
|
||||
#include <gray.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
test_tales()
|
||||
Displays some text using different modes and clipping options.
|
||||
*/
|
||||
|
||||
static Font *select(Font *current)
|
||||
{
|
||||
extern Font res_font_modern;
|
||||
struct {
|
||||
Font *font;
|
||||
const char *name;
|
||||
} fonts[] = {
|
||||
{ NULL, "gint default" },
|
||||
{ &res_font_modern, "Modern" },
|
||||
};
|
||||
int font_number = 2;
|
||||
|
||||
static int row = 0;
|
||||
int i, leave;
|
||||
|
||||
while(1)
|
||||
{
|
||||
text_configure(NULL, Color_Black);
|
||||
|
||||
dclear();
|
||||
locate(1, 1, "Select a font:");
|
||||
|
||||
for(i = 0; i < font_number && i < 6; i++)
|
||||
{
|
||||
if(fonts[i].font)
|
||||
{
|
||||
int height = fonts[i].font->line_height;
|
||||
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
|
||||
|
||||
text_configure(fonts[i].font, Color_Black);
|
||||
dtext(7, y, fonts[i].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
text_configure(NULL, Color_Black);
|
||||
locate(2, i + 2, fonts[i].name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dreverse_area(0, 8 * row + 8, 128, 8 * row + 15);
|
||||
dupdate();
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
|
||||
switch(getkey())
|
||||
{
|
||||
case KEY_UP:
|
||||
row = (row + font_number - 1) % font_number;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
row = (row + 1) % font_number;
|
||||
break;
|
||||
case KEY_EXE:
|
||||
return fonts[row].font;
|
||||
case KEY_EXIT:
|
||||
return current;
|
||||
default:
|
||||
leave = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(!leave);
|
||||
}
|
||||
}
|
||||
|
||||
void test_tales(void)
|
||||
{
|
||||
enum Color colors[] = { Color_Black, Color_Dark, Color_Light,
|
||||
Color_White, Color_Invert };
|
||||
extern Image res_opt_tales;
|
||||
Font *font = NULL;
|
||||
|
||||
int black_bg = 0;
|
||||
int color = 0;
|
||||
int i, x, height;
|
||||
int leave;
|
||||
|
||||
gray_start();
|
||||
while(1)
|
||||
{
|
||||
gclear();
|
||||
if(black_bg) greverse_area(0, 0, 127, 54);
|
||||
|
||||
if(font)
|
||||
{
|
||||
text_configure(font, colors[color]);
|
||||
height = font->line_height + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
text_configure(NULL, colors[color]);
|
||||
height = 8;
|
||||
}
|
||||
|
||||
for(i = 0; i < 6 && 2 + (i + 1) * height < 56; i++)
|
||||
{
|
||||
char str[17];
|
||||
for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j;
|
||||
str[16] = 0;
|
||||
|
||||
gtext(2, 2 + i * height, str);
|
||||
}
|
||||
|
||||
gimage(0, 56, &res_opt_tales);
|
||||
|
||||
x = 45 + 8 * color;
|
||||
gline(x, 57, x + 5, 57, Color_Black);
|
||||
gline(x, 57, x, 62, Color_Black);
|
||||
gline(x + 5, 57, x + 5, 62, Color_Black);
|
||||
gline(x, 62, x + 5, 62, Color_Black);
|
||||
|
||||
gupdate();
|
||||
|
||||
do
|
||||
{
|
||||
leave = 1;
|
||||
|
||||
switch(getkey())
|
||||
{
|
||||
case KEY_F1:
|
||||
gray_stop();
|
||||
font = select(font);
|
||||
gray_start();
|
||||
break;
|
||||
case KEY_F2:
|
||||
color = (color + 1) % 5;
|
||||
break;
|
||||
case KEY_F5:
|
||||
black_bg = !black_bg;
|
||||
break;
|
||||
|
||||
case KEY_EXIT:
|
||||
gray_stop();
|
||||
text_configure(NULL, Color_Black);
|
||||
return;
|
||||
default:
|
||||
leave = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!leave);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
#include "gintdemo.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <internals/timer.h>
|
||||
#include <timer.h>
|
||||
#include <display.h>
|
||||
#include <keyboard.h>
|
||||
#include <clock.h>
|
||||
#include <mpu.h>
|
||||
#include <rtc.h>
|
||||
|
||||
static void draw(int new_tab);
|
||||
static struct ClockConfig conf;
|
||||
|
||||
//---
|
||||
// Timer-RTC comparison.
|
||||
// The precision of the timer is measured by comparing it to the RTC.
|
||||
//---
|
||||
|
||||
static volatile int elapsed_timer = -1;
|
||||
static volatile int elapsed_rtc = -1;
|
||||
static int cb_id = -1;
|
||||
|
||||
static void timing_rtc(void)
|
||||
{
|
||||
elapsed_rtc++;
|
||||
}
|
||||
|
||||
static void timing_timer(void)
|
||||
{
|
||||
elapsed_timer++;
|
||||
}
|
||||
|
||||
static void timing_start(void)
|
||||
{
|
||||
timer_start(TIMER_USER, clock_setting(16, Clock_Hz), TIMER_Po_4,
|
||||
timing_timer, 0);
|
||||
rtc_cb_edit(cb_id, RTCFreq_16Hz, timing_rtc);
|
||||
|
||||
elapsed_timer = 0;
|
||||
elapsed_rtc = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Drawing.
|
||||
//---
|
||||
|
||||
/*
|
||||
small_text()
|
||||
Renders small text using a minimalist bitmap-based font.
|
||||
*/
|
||||
static void small_text(int x, int y, const char *text, int alignment)
|
||||
{
|
||||
extern Image res_clock_chars;
|
||||
Image *chars = &res_clock_chars;
|
||||
const char *table = "0123456789kMHz*/";
|
||||
|
||||
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
|
||||
int c;
|
||||
|
||||
while(*text)
|
||||
{
|
||||
const char *ptr = strchr(table, *text++);
|
||||
if(!ptr) continue;
|
||||
c = ptr - table;
|
||||
|
||||
dimage_part(x, y, chars, c << 2, 0, 3, 5);
|
||||
x += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
getFreq()
|
||||
Prints the given frequency in a string on the form:
|
||||
332kHz
|
||||
There are 1, 2 or 3 characters for the value, and 2 or 3
|
||||
characters for the unit. The string is compacted.
|
||||
*/
|
||||
void getFreq(char *str, int freq)
|
||||
{
|
||||
if(freq < 1000) sprintf(str, "%dHz", freq);
|
||||
else if(freq < 1000000) sprintf(str, "%dkHz", (freq + 500) / 1000);
|
||||
else sprintf(str, "%dMHz", (freq + 500000) / 1000000);
|
||||
}
|
||||
|
||||
/*
|
||||
dislay_freq()
|
||||
Displays a frequency value a unit, in an simple form.
|
||||
*/
|
||||
static void display_freq(int x, int y, int freq)
|
||||
{
|
||||
int ratio, letter, dot, i;
|
||||
char buffer[10];
|
||||
|
||||
if(freq <= 0)
|
||||
{
|
||||
dtext(x, y, "Unknown");
|
||||
return;
|
||||
}
|
||||
if(freq < 10000)
|
||||
{
|
||||
dprint(x, y, "%5d", freq);
|
||||
small_text(x + 31, y + 2, "Hz", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(freq < 10000000) ratio = 1, letter = 'k';
|
||||
else ratio = 1000, letter = 'M';
|
||||
|
||||
dot = 1 + (freq >= 10000 * ratio) + (freq >= 100000 * ratio);
|
||||
freq += (ratio * (1 + 9 * (dot >= 2) + 90 * (dot >= 3))) / 2;
|
||||
snprintf(buffer, 6, "%d", freq);
|
||||
|
||||
for(i = 4; i > dot; i--) buffer[i] = buffer[i - 1];
|
||||
buffer[dot] = '.';
|
||||
|
||||
dprint(x, y, buffer);
|
||||
sprintf(buffer, "%cHz", letter);
|
||||
small_text(x + 31, y + 2, buffer, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
draw()
|
||||
Draws the test interface.
|
||||
*/
|
||||
static void draw(int tab)
|
||||
{
|
||||
extern Image res_opt_timer;
|
||||
extern Image res_clock_7705;
|
||||
extern Image res_clock_7305;
|
||||
|
||||
char buffer[16];
|
||||
|
||||
dclear();
|
||||
dimage(0, 56, &res_opt_timer);
|
||||
|
||||
if(!tab)
|
||||
{
|
||||
locate(1, 1, "Clock frequency");
|
||||
dtext(7, 20, "B\x1e");
|
||||
display_freq(24, 20, conf.Bphi_f);
|
||||
dtext(7, 28, "I\x1e");
|
||||
display_freq(24, 28, conf.Iphi_f);
|
||||
dtext(7, 36, "P\x1e");
|
||||
display_freq(24, 36, conf.Pphi_f);
|
||||
|
||||
if(isSH3())
|
||||
{
|
||||
dimage(64, 0, &res_clock_7705);
|
||||
|
||||
getFreq(buffer, conf.CKIO_f);
|
||||
small_text(84, 16, buffer, 1);
|
||||
|
||||
sprintf(buffer, "*%d", conf.PLL1);
|
||||
small_text(84, 34, buffer, 1);
|
||||
|
||||
if(conf.Iphi_div1 == 1)
|
||||
dline(85, 43, 99, 43, Color_Black);
|
||||
else
|
||||
{
|
||||
sprintf(buffer, "/%d", conf.Iphi_div1);
|
||||
small_text(89, 41, buffer, 0);
|
||||
}
|
||||
if(conf.Pphi_div1 == 1)
|
||||
dline(85, 50, 99, 50, Color_Black);
|
||||
else
|
||||
{
|
||||
sprintf(buffer, "/%d", conf.Pphi_div1);
|
||||
small_text(89, 48, buffer, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dimage(64, 0, &res_clock_7305);
|
||||
|
||||
getFreq(buffer, conf.RTCCLK_f);
|
||||
small_text(84, 14, buffer, 1);
|
||||
|
||||
sprintf(buffer, "*%d", conf.FLL);
|
||||
small_text(84, 25, buffer, 1);
|
||||
|
||||
sprintf(buffer, "*%d", conf.PLL);
|
||||
small_text(84, 36, buffer, 1);
|
||||
|
||||
sprintf(buffer, "/%d", conf.Bphi_div1);
|
||||
small_text(89, 43, buffer, 0);
|
||||
sprintf(buffer, "/%d", conf.Iphi_div1);
|
||||
small_text(89, 50, buffer, 0);
|
||||
sprintf(buffer, "/%d", conf.Pphi_div1);
|
||||
small_text(89, 57, buffer, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int timer = elapsed_timer, rtc = elapsed_rtc; // just in case
|
||||
|
||||
locate(1, 1, "Timer/RTC comparison");
|
||||
|
||||
locate(2, 3, "Timer");
|
||||
if(timer >= 0) print(12, 3, "%04x", timer);
|
||||
else locate(12, 3, "...");
|
||||
|
||||
locate(2, 4, "RTC");
|
||||
if(rtc >= 0) print(12, 4, "%04x", rtc);
|
||||
else locate(12, 4, "...");
|
||||
|
||||
// We define the accuracy of the timer as the ratio between the
|
||||
// two counters.
|
||||
locate(2, 5, "Accuracy");
|
||||
if(rtc > 0 && timer > 0)
|
||||
{
|
||||
int ratio;
|
||||
if(timer <= rtc) ratio = (10000 * timer) / rtc;
|
||||
else ratio = (10000 * rtc) / timer;
|
||||
|
||||
print(12, 5, "%d.%02d %%", ratio / 100, ratio % 100);
|
||||
}
|
||||
else locate(12, 5, "...");
|
||||
}
|
||||
|
||||
dupdate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Timer/clock test.
|
||||
//---
|
||||
|
||||
/*
|
||||
test_timer()
|
||||
Clock timer and timer precision.
|
||||
*/
|
||||
void test_timer(void)
|
||||
{
|
||||
int tab = 0;
|
||||
|
||||
clock_measure();
|
||||
clock_measure_end();
|
||||
|
||||
conf = clock_config();
|
||||
|
||||
elapsed_timer = -1;
|
||||
elapsed_rtc = -1;
|
||||
cb_id = rtc_cb_add(RTCFreq_16Hz, timing_start, 0);
|
||||
|
||||
text_configure(NULL, Color_Black);
|
||||
|
||||
while(1)
|
||||
{
|
||||
draw(tab);
|
||||
|
||||
switch(getkey_opt(Getkey_NoOption, 1))
|
||||
{
|
||||
case KEY_EXIT:
|
||||
timer_stop(TIMER_USER);
|
||||
rtc_cb_end(cb_id);
|
||||
return;
|
||||
|
||||
case KEY_F1:
|
||||
tab = 0;
|
||||
break;
|
||||
case KEY_F2:
|
||||
tab = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,306 @@
|
|||
|
||||
# gint documentation: bitmap rendering #
|
||||
|
||||
|
||||
*Warning: this is a draft. The current implementation of bopti is different*
|
||||
*from this description, though similar.*
|
||||
|
||||
|
||||
|
||||
## Basics
|
||||
|
||||
The bitmap drawing module, *bopti*, is based on video-ram (vram) bitwise
|
||||
operations. The images are made of layers that describe (more or less) which
|
||||
pixels of the image an operation applies to. Rendering the image consists in
|
||||
applying an operation function to the existing vram pixels.
|
||||
|
||||
*bopti* makes an extensive use of longword operations and 4-alignment to take
|
||||
advantage of the bit-based structure of the monochrome vram and enhance
|
||||
performance. Among all possible optimizations, avoiding direct pixel access has
|
||||
proven to be the most efficient.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Operations
|
||||
|
||||
Operations are functions applied to update a vram longword in accordance with
|
||||
an operation mask. Bits that are set in the mask indicate pixels which have to
|
||||
be updated by the operation. Bits that are reset indicate pixels that must not
|
||||
be changed.
|
||||
|
||||
All the point is, the functions must not access the bit information in the mask
|
||||
or the vram data individually. They must operate globally using longword
|
||||
bitwise instructions, so that performance is maintained.
|
||||
|
||||
Consider for instance a logical and operation (`(a, b) -> a & b`).
|
||||
Operating on pixels would need to move some data, test the value of a bit in
|
||||
the mask, edit the vram data, and eventually shift both the data and the mask,
|
||||
for all of the 32 pixels.
|
||||
One could not expect this from happening in less than 150 processor cycles
|
||||
(in comparison, using generic-purpose `setPixel()`-like functions would be at
|
||||
least 10 times as long). The smarter method operates directly on the longword
|
||||
parameters, and performs `data = data & ~mask`, which is 2 processor cycles
|
||||
long.
|
||||
|
||||
The following operations are defined by *bopti*:
|
||||
|
||||
- `Draw `: Draws black pixels.
|
||||
- `Alpha `: Erases non-transparent pixels.
|
||||
- `Change `: Changes the pixels' color.
|
||||
- `Lighten `: Lightens gray pixels.
|
||||
- `Lighten2`: Lightens gray pixels more.
|
||||
- `Darken `: Darkens gray pixels.
|
||||
- `Darken2 `: Darkens gray pixels more.
|
||||
|
||||
To perform an operation, *bopti* uses the mask data, which is taken from a
|
||||
layer, and calls the associated operation function. Every operation has its
|
||||
default layer mask (except `change`), but this setting may be overridden.
|
||||
*bopti* allows user programs to use any monochrome image as a mask for an
|
||||
operation. For instance, a black rectangle may be drawn by any of the operation
|
||||
functions, resulting in various results.
|
||||
|
||||
An additional operation, `fill`, is defined by the library. It does all the job
|
||||
necessary to render the full image, which often falls back to performing the
|
||||
operations that correspond to the kind of image.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Operation on gray pixels
|
||||
|
||||
*Detailed article: [Gray engine](gray-engine)*
|
||||
|
||||
Gray pixels are made of four colors represented by pairs of bits. Arguments
|
||||
`light` and `dark` of gray operation functions are longwords containing the
|
||||
least significant and most significant of these bits, respectively.
|
||||
|
||||
white = 0 [00]
|
||||
lightgray = 1 [01]
|
||||
darkgray = 2 [10]
|
||||
black = 3 [11]
|
||||
|
||||
The `Lighten` operation affects pixels as if decrementing their value (white
|
||||
pixels are not changed), and `darken` does the opposite (black pixels are not
|
||||
changed).
|
||||
Operations `Lighten2` and `darken2` do the same two times.
|
||||
|
||||
From this description, and considering two bits `light` and `dark`, it follows
|
||||
that:
|
||||
|
||||
```c
|
||||
lighten2 (light, dark) = (0, light & dark)
|
||||
lighten (light, dark) = (light & dark, light & ~dark)
|
||||
darken (light, dark) = (light | dark, light | ~dark)
|
||||
darken2 (light, dark) = (1, light | dark)
|
||||
```
|
||||
|
||||
This does not take account of a possible operation mask. See section
|
||||
[Operation functions](#operation-functions) for more flexible functions.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Partial transparency
|
||||
|
||||
*bopti* allows monochrome images to have semi-transparent pixels. Consider for
|
||||
example a white background. An opaque black pixel will render black, while a
|
||||
1/3-transparent black pixel will render dark gray, and a 2/3-transparent black
|
||||
pixel will render light gray. Which means that:
|
||||
|
||||
* 1/3-transparent white pixels form the mask for `lighten2`
|
||||
* 2/3-transparent white pixels form the mask for `lighten`
|
||||
* 2/3-transparent black pixels form the mask for `darken`
|
||||
* 1/3-transparent black pixels form the mask for `darken2`
|
||||
|
||||
Partial transparency on gray pixels is not allowed. Apart from the complexity
|
||||
of the generic partial transparency rendering operation, semi-transparent gray
|
||||
pixels are not of any use.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Operation functions
|
||||
|
||||
Operations on monochrome buffers are defined as functions of two parameters:
|
||||
the vram data longword to update, `data`, and the operation mask, `x`. Every
|
||||
of these functions must satisfy `f(data, 0) = data`.
|
||||
|
||||
Operations on gray buffers take three arguments: `light` and `dark`, which are
|
||||
longwords from the [gray buffers](gray-engine), and the operation mask `x`.
|
||||
They update both longwords and return them. These functions must satisfy
|
||||
`f(light, dark, 0) = (light, dark)`.
|
||||
|
||||
The functions for each of the operations are the following:
|
||||
|
||||
~~~c
|
||||
# Draw function
|
||||
draw(data, x) = data | x
|
||||
|
||||
# Alpha function
|
||||
alpha(data, x) = data & ~x
|
||||
|
||||
# Change function
|
||||
change(data, x) = data ^ x
|
||||
|
||||
# Lighten function
|
||||
lighten(light, dark, x) = (light & (dark | ~x), (light | ~x) & (x ^ dark))
|
||||
|
||||
# Lighten2 function
|
||||
lighten2(light, dark, x) = (light & ~x, (light | ~x) & dark)
|
||||
|
||||
# Darken function
|
||||
darken(light, dark, x) = (light | (dark & x), (light & x) | (x ^ dark))
|
||||
|
||||
# Darken2 function
|
||||
darken2(light, dark, x) = (light | x, (light & x) | dark)
|
||||
~~~
|
||||
|
||||
One could easily check that these functions do their jobs when `x = 1` and
|
||||
leave the data unchanged when `x = 0`.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Image format
|
||||
|
||||
Images are made of *layers*, each of which describe the mask for an operation.
|
||||
When an image is rendered, *bopti* draws some of those layers in the vram
|
||||
using the operation functions.
|
||||
|
||||
* Non-transparent monochrome images only have one layer, which describes the
|
||||
mask for the `draw` operation.
|
||||
* Transparent monochrome images have two layers. The first describes the mask
|
||||
for the `draw` operation, while the other is the `alpha` operation mask (which
|
||||
means that it indicates which pixels are not transparent).
|
||||
* Non-transparent gray images also have two layers: one for each
|
||||
[gray buffer](gray-engine). Both are for the `draw` operation.
|
||||
* Transparent gray images have three layers. Two of them constitute the two-bit
|
||||
color information for the `draw` operation, and the third is the `alpha`
|
||||
operation mask.
|
||||
* Semi-transparent monochrome images also have three layers. Two are used to
|
||||
store the two-bit transparency level information (0 is opaque, 3 is fully
|
||||
transparent), and the third indicates the color.
|
||||
|
||||
Layers are encoded as a bit map. The image is split into a *grid*, which is
|
||||
made of 32-pixel *columns*, and an *end*.
|
||||
|
||||
32 32 32 end
|
||||
+------+------+------+---+
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
+------+------+------+---+
|
||||
|
||||
Bitmap
|
||||
|
||||
The first bytes of the layer data is the column data. Each column is encoded
|
||||
as a 32-bit integer array from top to bottom. Columns are written from left to
|
||||
right. The end is encoded as an 8-bit or 16-bit integer array depending on its
|
||||
size, and written from top to bottom. Additionally, 0 to 3 NUL (0x00) bytes are
|
||||
added to make the layer size a multiple of 4 (to allow 32-bit access to the
|
||||
column data of the following layer).
|
||||
|
||||
In case of big images (see the image structure below), the end is expanded to
|
||||
a 32-pixel column to improve performance.
|
||||
|
||||
The image itself is a structure of the following kind (in case of small
|
||||
images):
|
||||
|
||||
```c
|
||||
struct Image
|
||||
{
|
||||
unsigned char magic;
|
||||
unsigned char format;
|
||||
|
||||
unsigned char width;
|
||||
unsigned char height;
|
||||
|
||||
const uint32_t data[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
```
|
||||
|
||||
For bigger images (`width` > 255 or `height` > 255), both `width` and `height`
|
||||
are set to `0` and the actual size information is written on two shorts just
|
||||
where the data resides:
|
||||
|
||||
```c
|
||||
struct BigImage
|
||||
{
|
||||
unsigned char magic;
|
||||
unsigned char format;
|
||||
|
||||
unsigned char null_width; /* contains 0 */
|
||||
unsigned char null_height; /* contains 0 */
|
||||
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
|
||||
const uint32_t data[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
```
|
||||
|
||||
This does not create a memory loss because a two-byte gap was needed to make
|
||||
the data 4-aligned.
|
||||
|
||||
* The `magic` number, which is common to all the file formats of *gint*,
|
||||
identifies the file type and version of the structure. *bopti* will not render
|
||||
an image which is not encoded for its specific version.
|
||||
|
||||
* The `format` attribute describes the layer distribution, as specified by the
|
||||
following enum:
|
||||
|
||||
```c
|
||||
enum ImageFormat
|
||||
{
|
||||
ImageFormat_Mono = 0x01,
|
||||
ImageFormat_MonoAlpha = 0x09,
|
||||
ImageFormat_Gray = 0x06,
|
||||
ImageFormat_GrayAlpha = 0x0e,
|
||||
ImageFormat_GreaterAlpha = 0x31,
|
||||
|
||||
ImageFormat_ColorMask = 0x07,
|
||||
ImageFormat_AlphaMask = 0x38,
|
||||
};
|
||||
```
|
||||
|
||||
`Alpha` refers to uniform transparency. The only format that supports
|
||||
partial transparency is `GreaterAlpha`, and it is always encoded as
|
||||
monochrome (because using gray pixels would lead to 9 different colors,
|
||||
which is rather unoptimized). Gray images with partial transparency
|
||||
will be refused by *fxconv*.
|
||||
|
||||
|
||||
* The `width` and `height` attributes are exactly what you expect.
|
||||
|
||||
* The `data` is simply made of all the layers put one after another. Layers are
|
||||
put in the following order:
|
||||
|
||||
[0] Monochrome `draw` layer
|
||||
[1] Dark gray `draw` layer
|
||||
[2] Light gray `draw` layer
|
||||
[3] Uniform `alpha` layer
|
||||
[4] First semi-`alpha` layer
|
||||
[5] Second semi-`alpha` layer
|
||||
|
||||
Not every format uses the six layers, of course. The layers used by
|
||||
each format may be found by reading the position of the `1`'s in the
|
||||
corresponding `enum ImageFormat` entry. Layers that are not needed are
|
||||
skipped.
|
|
@ -0,0 +1,673 @@
|
|||
#ifndef _7305_H
|
||||
#define _7305_H 1
|
||||
|
||||
/*
|
||||
Double-underscore prefixed structures (e.g. __st_rtc_counter) are used
|
||||
internally but are not meant to be used in user programs.
|
||||
|
||||
Underscore-prefixed names (e.g. _R64CNT) are used to avoid name
|
||||
conflicts (e.g. STRUCTURE.RTC would expand to STRUCTURE.((T *)0x...)).
|
||||
*/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#define gap(n) unsigned: n << 3
|
||||
|
||||
//---
|
||||
// Interrupt controller, part 1.
|
||||
//---
|
||||
|
||||
struct _st_intc
|
||||
{
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned const NMIL :1;
|
||||
unsigned MAI :1;
|
||||
unsigned :4;
|
||||
unsigned NMIB :1;
|
||||
unsigned NMIE :1;
|
||||
unsigned :2;
|
||||
unsigned LVLMODE :1;
|
||||
unsigned :5;
|
||||
};
|
||||
} ICR0;
|
||||
|
||||
char gap1[14];
|
||||
|
||||
union {
|
||||
unsigned int LONG;
|
||||
struct {
|
||||
unsigned IRQ0 :4;
|
||||
unsigned IRQ1 :4;
|
||||
unsigned IRQ2 :4;
|
||||
unsigned IRQ3 :4;
|
||||
unsigned IRQ4 :4;
|
||||
unsigned IRQ5 :4;
|
||||
unsigned IRQ6 :4;
|
||||
unsigned IRQ7 :4;
|
||||
};
|
||||
} INTPRI00;
|
||||
|
||||
char gap2[8];
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned IRQ0S :2;
|
||||
unsigned IRQ1S :2;
|
||||
unsigned IRQ2S :2;
|
||||
unsigned IRQ3S :2;
|
||||
unsigned IRQ4S :2;
|
||||
unsigned IRQ5S :2;
|
||||
unsigned IRQ6S :2;
|
||||
unsigned IRQ7S :2;
|
||||
};
|
||||
} ICR1;
|
||||
|
||||
char gap3[6];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned IRQ0 :1;
|
||||
unsigned IRQ1 :1;
|
||||
unsigned IRQ2 :1;
|
||||
unsigned IRQ3 :1;
|
||||
unsigned IRQ4 :1;
|
||||
unsigned IRQ5 :1;
|
||||
unsigned IRQ6 :1;
|
||||
unsigned IRQ7 :1;
|
||||
};
|
||||
} INTREQ00;
|
||||
|
||||
char gap4[31];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned IRQ0 :1;
|
||||
unsigned IRQ1 :1;
|
||||
unsigned IRQ2 :1;
|
||||
unsigned IRQ3 :1;
|
||||
unsigned IRQ4 :1;
|
||||
unsigned IRQ5 :1;
|
||||
unsigned IRQ6 :1;
|
||||
unsigned IRQ7 :1;
|
||||
};
|
||||
} INTMSK00;
|
||||
|
||||
char gap5[31];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned _IRQ0 :1;
|
||||
unsigned _IRQ1 :1;
|
||||
unsigned _IRQ2 :1;
|
||||
unsigned _IRQ3 :1;
|
||||
unsigned _IRQ4 :1;
|
||||
unsigned _IRQ5 :1;
|
||||
unsigned _IRQ6 :1;
|
||||
unsigned _IRQ7 :1;
|
||||
};
|
||||
} INTMSKCLR00;
|
||||
|
||||
char gap6[91];
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned const NMIL :1;
|
||||
unsigned :14;
|
||||
unsigned NMIFL :1;
|
||||
};
|
||||
} NMIFCR;
|
||||
|
||||
char gap7[6029118];
|
||||
|
||||
union {
|
||||
unsigned int LONG;
|
||||
struct {
|
||||
unsigned HEXA_A5 :8;
|
||||
unsigned :16;
|
||||
unsigned UIMASK :4;
|
||||
unsigned :4;
|
||||
};
|
||||
} USERIMSK;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt controller, part 2.
|
||||
//---
|
||||
|
||||
struct _st_intx
|
||||
{
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned TMU0_0 :4;
|
||||
unsigned TMU0_1 :4;
|
||||
unsigned TMU0_2 :4;
|
||||
unsigned IrDA :4;
|
||||
};
|
||||
} IPRA;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned JPU :4;
|
||||
unsigned LCDC :4;
|
||||
unsigned DMAC1A :4;
|
||||
unsigned BEU2_1 :4;
|
||||
};
|
||||
} IPRB;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned TMU1_0 :4;
|
||||
unsigned TMU1_1 :4;
|
||||
unsigned TMU1_2 :4;
|
||||
unsigned SPU :4;
|
||||
};
|
||||
} IPRC;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned :4;
|
||||
unsigned MMCIF :4;
|
||||
unsigned :4;
|
||||
unsigned ATAPI :4;
|
||||
};
|
||||
} IPRD;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned DMAC0A :4;
|
||||
unsigned VARIOUS :4;
|
||||
unsigned SCIFA3 :4;
|
||||
unsigned VPU5F :4;
|
||||
};
|
||||
} IPRE;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned _KEYSC :4;
|
||||
unsigned DMAC0B :4;
|
||||
unsigned USB01 :4;
|
||||
unsigned CMT :4;
|
||||
};
|
||||
} IPRF;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIF0 :4;
|
||||
unsigned SCIF1 :4;
|
||||
unsigned SCIF2 :4;
|
||||
unsigned VEU3F0 :4;
|
||||
};
|
||||
} IPRG;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned MSIOF0 :4;
|
||||
unsigned MSIOF1 :4;
|
||||
unsigned I2C1 :4;
|
||||
unsigned I2C0 :4;
|
||||
};
|
||||
} IPRH;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIFA4 :4;
|
||||
unsigned ICB :4;
|
||||
unsigned TSIF :4;
|
||||
unsigned _2DG_ICB :4;
|
||||
};
|
||||
} IPRI;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned CEU2_1 :4;
|
||||
unsigned EtherMAC :4;
|
||||
unsigned FSI :4;
|
||||
unsigned SDHI1 :4;
|
||||
};
|
||||
} IPRJ;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned _RTC :4;
|
||||
unsigned DMAC1B :4;
|
||||
unsigned ICB :4;
|
||||
unsigned SDHI0 :4;
|
||||
};
|
||||
} IPRK;
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIFA5 :4;
|
||||
unsigned :4;
|
||||
unsigned TPU :4;
|
||||
unsigned _2DDMAC :4;
|
||||
};
|
||||
} IPRL;
|
||||
char gap1[82];
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
};
|
||||
} IMR0;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned VOUI :1;
|
||||
unsigned VEU1I :1;
|
||||
unsigned BEU0I :1;
|
||||
unsigned CEUOI :1;
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
};
|
||||
} IMR1;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned VPUI :1;
|
||||
unsigned ATAPI :1;
|
||||
unsigned EtherMAC :1;
|
||||
unsigned :1;
|
||||
unsigned SCIFA0 :1;
|
||||
};
|
||||
} IMR2;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
unsigned :3;
|
||||
unsigned IRDAI :1;
|
||||
};
|
||||
} IMR3;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned JPUI :1;
|
||||
unsigned :2;
|
||||
unsigned LCDCI :1;
|
||||
};
|
||||
} IMR4;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned KEYI :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned VEU0I :1;
|
||||
unsigned SCIF2 :1;
|
||||
unsigned SCIF1 :1;
|
||||
unsigned SCIF0 :1;
|
||||
};
|
||||
} IMR5;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned ICBI :1;
|
||||
unsigned SCIFA4 :1;
|
||||
unsigned CEU1I :1;
|
||||
unsigned :1;
|
||||
unsigned MSIOFI0 :1;
|
||||
unsigned MSIOFI1 :1;
|
||||
};
|
||||
} IMR6;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DTE0I :1;
|
||||
unsigned WAITOI :1;
|
||||
unsigned TACK0I :1;
|
||||
unsigned AL0I :1;
|
||||
unsigned DTE1I :1;
|
||||
unsigned WAIT1I :1;
|
||||
unsigned TACK1I :1;
|
||||
unsigned AL1I :1;
|
||||
};
|
||||
} IMR7;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
unsigned :2;
|
||||
unsigned SCFIA5 :1;
|
||||
unsigned FSI :1;
|
||||
};
|
||||
} IMR8;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned CMTI :1;
|
||||
unsigned :1;
|
||||
unsigned USI1 :1;
|
||||
unsigned USI0 :1;
|
||||
unsigned :1;
|
||||
};
|
||||
} IMR9;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned :1;
|
||||
unsigned ATI :1;
|
||||
unsigned PRI :1;
|
||||
unsigned CUI :1;
|
||||
};
|
||||
} IMR10;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned BRK :1;
|
||||
unsigned CEI :1;
|
||||
unsigned INI :1;
|
||||
unsigned TRI :1;
|
||||
unsigned :1;
|
||||
unsigned TPUI :1;
|
||||
unsigned LMBI :1;
|
||||
unsigned TSIFI :1;
|
||||
};
|
||||
} IMR11;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :7;
|
||||
unsigned _2DDMAC :1;
|
||||
};
|
||||
} IMR12;
|
||||
char gap2[15];
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
};
|
||||
} _IMCR0;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned VOUI :1;
|
||||
unsigned VEU1I :1;
|
||||
unsigned BEU0I :1;
|
||||
unsigned CEUOI :1;
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
};
|
||||
} _IMCR1;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned VPUI :1;
|
||||
unsigned ATAPI :1;
|
||||
unsigned EtherMAC :1;
|
||||
unsigned :1;
|
||||
unsigned SCIFA0 :1;
|
||||
};
|
||||
} _IMCR2;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
unsigned :3;
|
||||
unsigned IRDAI :1;
|
||||
};
|
||||
} _IMCR3;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned JPUI :1;
|
||||
unsigned :2;
|
||||
unsigned LCDCI :1;
|
||||
};
|
||||
} _IMCR4;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned KEYI :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned VEU0I :1;
|
||||
unsigned SCIF2 :1;
|
||||
unsigned SCIF1 :1;
|
||||
unsigned SCIF0 :1;
|
||||
};
|
||||
} _IMCR5;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned ICBI :1;
|
||||
unsigned SCIFA4 :1;
|
||||
unsigned CEU1I :1;
|
||||
unsigned :1;
|
||||
unsigned MSIOFI0 :1;
|
||||
unsigned MSIOFI1 :1;
|
||||
};
|
||||
} _IMCR6;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DTE0I :1;
|
||||
unsigned WAITOI :1;
|
||||
unsigned TACK0I :1;
|
||||
unsigned AL0I :1;
|
||||
unsigned DTE1I :1;
|
||||
unsigned WAIT1I :1;
|
||||
unsigned TACK1I :1;
|
||||
unsigned AL1I :1;
|
||||
};
|
||||
} _IMCR7;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
unsigned :2;
|
||||
unsigned SCFIA5 :1;
|
||||
unsigned FSI :1;
|
||||
};
|
||||
} _IMCR8;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned CMTI :1;
|
||||
unsigned :1;
|
||||
unsigned USI1 :1;
|
||||
unsigned USI0 :1;
|
||||
unsigned :1;
|
||||
};
|
||||
} _IMCR9;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned :1;
|
||||
unsigned ATI :1;
|
||||
unsigned PRI :1;
|
||||
unsigned CUI :1;
|
||||
};
|
||||
} _IMCR10;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned BRK :1;
|
||||
unsigned CEI :1;
|
||||
unsigned INI :1;
|
||||
unsigned TRI :1;
|
||||
unsigned :1;
|
||||
unsigned TPUI :1;
|
||||
unsigned LMBI :1;
|
||||
unsigned TSIFI :1;
|
||||
};
|
||||
} _IMCR11;
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :7;
|
||||
unsigned _2DDMAC :1;
|
||||
};
|
||||
} _IMCR12;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
#define INTC (*(volatile struct _st_intc *)0xa4140000)
|
||||
#define INTX (*(volatile struct _st_intx *)0xa4080000)
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif // _7305_H
|
|
@ -0,0 +1,23 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: alloca
|
||||
//
|
||||
// Allows dynamic memory allocation on the stack. Memory is automatically
|
||||
// freed when the calling function exits.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _ALLOCA_H
|
||||
#define _ALLOCA_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
alloca()
|
||||
Allocates a memory block on the stack.
|
||||
*/
|
||||
void *alloca(size_t size);
|
||||
|
||||
#define alloca(size) __builtin_alloca(size)
|
||||
|
||||
#endif // _ALLOCA_H
|
|
@ -0,0 +1,128 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: clock
|
||||
//
|
||||
// Measures the frequency of the MPU clocks. This module assumes that the
|
||||
// clock mode is 3 on SH7305 (as does FTune).
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _CLOCK_H
|
||||
#define _CLOCK_H
|
||||
|
||||
//---
|
||||
// Some type declarations.
|
||||
//---
|
||||
|
||||
enum Clock
|
||||
{
|
||||
Clock_CKIO = 0, // SH7705
|
||||
Clock_RTCCLK = 1, // SH7305
|
||||
Clock_Bphi = 2,
|
||||
Clock_Iphi = 3,
|
||||
Clock_Pphi = 4,
|
||||
};
|
||||
|
||||
enum ClockUnit
|
||||
{
|
||||
Clock_us = 0,
|
||||
Clock_ms = 1,
|
||||
Clock_s = 2,
|
||||
|
||||
Clock_Hz = 10,
|
||||
Clock_kHz = 11,
|
||||
Clock_MHz = 12,
|
||||
};
|
||||
|
||||
struct ClockConfig
|
||||
{
|
||||
union
|
||||
{
|
||||
int PLL1; // SH7705
|
||||
int FLL; // SH7305
|
||||
};
|
||||
union
|
||||
{
|
||||
int PLL2; // SH7705
|
||||
int PLL; // SH7305
|
||||
};
|
||||
|
||||
int Bphi_div1;
|
||||
int Iphi_div1;
|
||||
int Pphi_div1;
|
||||
|
||||
union
|
||||
{
|
||||
int CKIO_f; // SH7705
|
||||
int RTCCLK_f; // SH7305
|
||||
};
|
||||
|
||||
int Bphi_f;
|
||||
int Iphi_f;
|
||||
int Pphi_f;
|
||||
};
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
clock_frequency()
|
||||
Returns the approximate frequency, in Hz, of the given clock. The
|
||||
measurements need to have been done. Returns a negative number on
|
||||
error.
|
||||
*/
|
||||
int clock_frequency(enum Clock clock);
|
||||
|
||||
/*
|
||||
clock_setting()
|
||||
Returns the P_phi / 4 timer setting that will last for the given time.
|
||||
Several units can be used. Be aware that the result is approximate, and
|
||||
very high frequencies or very short delays will yield important errors.
|
||||
*/
|
||||
int clock_setting(int duration, enum ClockUnit unit);
|
||||
|
||||
/*
|
||||
clock_config()
|
||||
Returns a copy of the clock configuration.
|
||||
*/
|
||||
struct ClockConfig clock_config(void);
|
||||
|
||||
/*
|
||||
sleep()
|
||||
Sleeps until an interrupt is accepted.
|
||||
*/
|
||||
void sleep(void);
|
||||
|
||||
/*
|
||||
sleep_us()
|
||||
Sleeps for the given number of us using the user timer. The result will
|
||||
always be slightly less than required.
|
||||
*/
|
||||
void sleep_us(int us_delay);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced for documentation purposes only. Do not use.
|
||||
//---
|
||||
|
||||
/*
|
||||
clock_measure()
|
||||
Begins the frequency measurements. The measurements will end
|
||||
automatically. While doing measurements, do not use the RTC interrupt
|
||||
or the user timer.
|
||||
Call clock_measure_end() to wait until the measurements are finished.
|
||||
It is possible to execute code during the measurements, so that less
|
||||
time is spent.
|
||||
*/
|
||||
void clock_measure(void);
|
||||
|
||||
/*
|
||||
clock_measure_end()
|
||||
Waits until the measurements are finished. This may be immediate.
|
||||
*/
|
||||
void clock_measure_end(void);
|
||||
|
||||
#endif // _CLOCK_H
|
|
@ -0,0 +1,35 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: ctype
|
||||
//
|
||||
// Some character manipulation.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H 1
|
||||
|
||||
// Character definition macros.
|
||||
#define isalnum(c) (isdigit(c) || isalpha(c))
|
||||
#define isalpha(c) (islower(c) || isupper(c))
|
||||
|
||||
#define iscntrl(c) ((c) <= 0x1f || (c) == 0x7f)
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#define isgraph(c) ((c) > ' ' && (c) < 0x7f)
|
||||
#define islower(c) ((c) >= 'a' && (c) <= 'z')
|
||||
#define isprint(c) ((c) >= ' ' && (c) < 0x7f)
|
||||
#define ispunct(c) (((c) >= '!' && (c) <= '/') || \
|
||||
((c) >= ':' && (c) <= '@') || \
|
||||
((c) >= '[' && (c) <= '`') || \
|
||||
((c) >= '{' && (c) <= '~'))
|
||||
#define isspace(c) (((c) >= '\t' && (c) <= '\r') || (c) == ' ')
|
||||
#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define isxdigit(c) (((c) >= '0' && (c) <= '9') || \
|
||||
((c) >= 'A' && (c) <= 'F') || \
|
||||
((c) >= 'a' && (c) <= 'f'))
|
||||
|
||||
// Character manipulation macros.
|
||||
#define tolower(c) (isupper(c) ? (c) | 32 : (c))
|
||||
#define toupper(c) (islower(c) ? (c) & ~32 : (c))
|
||||
|
||||
#endif // _CTYPE_H
|
|
@ -0,0 +1,161 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: display
|
||||
//
|
||||
// Handles vram manipulation and drawing for plain monochrome display.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _DISPLAY_H
|
||||
#define _DISPLAY_H 1
|
||||
|
||||
|
||||
//---
|
||||
// Heading declarations.
|
||||
//---
|
||||
|
||||
enum Color
|
||||
{
|
||||
Color_White = 0,
|
||||
Color_Light = 1,
|
||||
Color_Dark = 2,
|
||||
Color_Black = 3,
|
||||
Color_None = 4,
|
||||
Color_Invert = 5,
|
||||
};
|
||||
|
||||
// This header needs enum Color to be defined.
|
||||
#include <tales.h>
|
||||
|
||||
/*
|
||||
struct Image
|
||||
This structure holds information about a bitmap encoded with fxconv.
|
||||
Data is accessed using longword operations, which *requires* many
|
||||
sizes to be multiples of 4 (structure alignment, data alignment, layer
|
||||
size, ...).
|
||||
*/
|
||||
struct Image
|
||||
{
|
||||
unsigned char magic;
|
||||
unsigned char format;
|
||||
|
||||
unsigned char width;
|
||||
unsigned char height;
|
||||
|
||||
const unsigned char __attribute__((aligned(4))) data[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
// Useful shorthand for user code.
|
||||
typedef struct Image Image;
|
||||
|
||||
|
||||
|
||||
// A few other constants.
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram address. This function always return the
|
||||
same address.
|
||||
The buffer returned by this function should not be used directly when
|
||||
running the gray engine.
|
||||
*/
|
||||
void *display_getLocalVRAM(void);
|
||||
|
||||
/*
|
||||
display_getCurrentVRAM()
|
||||
Returns the current video ram. This function usually returns the
|
||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
||||
is running (in which case the result is undefined). Returns the local
|
||||
vram address by default.
|
||||
*/
|
||||
void *display_getCurrentVRAM(void);
|
||||
|
||||
/*
|
||||
display_useVRAM()
|
||||
Changes the current video ram address. The argument MUST be a 4-
|
||||
aligned 1024-byte buffer; otherwise any drawing operation will crash
|
||||
the program.
|
||||
This function will most likely have no effect when running the gray
|
||||
engine.
|
||||
*/
|
||||
void display_useVRAM(void *vram);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Global drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dupdate()
|
||||
Displays the vram on the physical screen. Does nothing when the gray
|
||||
engine is running.
|
||||
*/
|
||||
void dupdate(void);
|
||||
|
||||
/*
|
||||
dclear()
|
||||
Clears the whole video ram.
|
||||
*/
|
||||
void dclear(void);
|
||||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
|
||||
cleared.
|
||||
*/
|
||||
void dclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
dreverse_area()
|
||||
Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as
|
||||
well.
|
||||
*/
|
||||
void dreverse_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dpixel()
|
||||
Puts a pixel in the vram.
|
||||
*/
|
||||
void dpixel(int x, int y, enum Color color);
|
||||
|
||||
/*
|
||||
dline()
|
||||
Draws a line in the vram. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
|
||||
Uses an algorithm written by PierrotLL for MonochromeLib.
|
||||
*/
|
||||
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays a monochrome image in the vram. Does a real lot of
|
||||
optimization.
|
||||
*/
|
||||
void dimage(int x, int y, struct Image *image);
|
||||
|
||||
/*
|
||||
dimage_part()
|
||||
Draws a portion of an image, defined by its bounding rectangle.
|
||||
Point (left, top) is included, but (left + width, top + height) is
|
||||
excluded.
|
||||
*/
|
||||
void dimage_part(int x, int y, struct Image *img, int left, int top,
|
||||
int width, int height);
|
||||
|
||||
#endif // _DISPLAY_H
|
|
@ -0,0 +1,84 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: events
|
||||
//
|
||||
// Finally some user-friendly API.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _EVENTS_H
|
||||
#define _EVENTS_H
|
||||
|
||||
//---
|
||||
// Type definitions.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum EventType
|
||||
Something user programs will surely use most often.
|
||||
*/
|
||||
enum EventType
|
||||
{
|
||||
EventType_None = 0,
|
||||
ET_None = EventType_None,
|
||||
|
||||
EventType_User = 1,
|
||||
ET_User = EventType_User,
|
||||
|
||||
EventType_KeyPressed = 2,
|
||||
ET_KeyPress = EventType_KeyPressed,
|
||||
|
||||
EventType_KeyReleased = 3,
|
||||
ET_KeyRel = EventType_KeyReleased,
|
||||
};
|
||||
|
||||
/*
|
||||
struct Event
|
||||
Wake up, something's going on. The union member that holds information
|
||||
about the event is implicitly defined by the type attribute.
|
||||
*/
|
||||
struct Event
|
||||
{
|
||||
enum EventType type;
|
||||
|
||||
union
|
||||
{
|
||||
// For ET_User.
|
||||
void *data;
|
||||
// For ET_KeyPress and ET_KeyRel.
|
||||
int key;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Event management.
|
||||
//---
|
||||
|
||||
/*
|
||||
event_push()
|
||||
Queues a user-defined event, allowing it to be retrieved by getevent()
|
||||
or pollevent() later. Most often you will not need to use this, as
|
||||
system events are automatically queued. Pushing ET_None events is not
|
||||
allowed.
|
||||
Returns non-zero on error.
|
||||
*/
|
||||
int event_push(struct Event event);
|
||||
|
||||
/*
|
||||
getevent()
|
||||
Returns the next event. If no one is available, waits for something to
|
||||
happen. This function uses low-level sleep and should be preferred to
|
||||
active waiting using loops.
|
||||
*/
|
||||
struct Event getevent(void);
|
||||
|
||||
/*
|
||||
pollevent()
|
||||
Returns the next event. If no one is available, returns an event whose
|
||||
type is ET_None. This function always returns immediately.
|
||||
*/
|
||||
struct Event pollevent(void);
|
||||
|
||||
#endif // _EVENTS_H
|
|
@ -0,0 +1,192 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: interrupt handler
|
||||
//
|
||||
// Central point of the library. Controls the interrupt handler and
|
||||
// defines a few functions to configure callbacks for some interrupts.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _GINT_H
|
||||
#define _GINT_H 1
|
||||
|
||||
#define GINT_VERSION 0x01000000
|
||||
#define GINT_VERSION_STR "01.00"
|
||||
|
||||
//---
|
||||
// Interrupt handler control.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_getVBR()
|
||||
Returns the current vbr address.
|
||||
*/
|
||||
unsigned int gint_getVBR(void);
|
||||
|
||||
/*
|
||||
gint_systemVBR()
|
||||
Returns the vbr address used by the system (saved when execution
|
||||
starts).
|
||||
*/
|
||||
unsigned int gint_systemVBR(void);
|
||||
|
||||
/*
|
||||
gint_setDefaultHandler()
|
||||
In case gint receives an interrupt it doesn't recognize, it can fall
|
||||
back to a user-provided interrupt handler. Set it to NULL to disable
|
||||
this feature.
|
||||
Be aware that the event code passed to the default handler will either
|
||||
be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each
|
||||
interrupt source is completely platform-dependent. Remember to handle
|
||||
both platforms for increased portability, if possible.
|
||||
*/
|
||||
void gint_setDefaultHandler(void (*default_handler)(int event_code));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Register access.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum Register
|
||||
Represents common registers. Used as identifiers to retrieve their
|
||||
values using gint_register().
|
||||
*/
|
||||
enum Register
|
||||
{
|
||||
Register_EXPEVT,
|
||||
Register_MMUCR,
|
||||
Register_TEA,
|
||||
};
|
||||
|
||||
/*
|
||||
gint_register()
|
||||
Returns the address of a common register. All common registers exist
|
||||
on both platforms but they may hold different values for the same
|
||||
information (f.i. EXPEVT may not return the same value for a given
|
||||
exception on both 7705 and 7305).
|
||||
*/
|
||||
volatile void *gint_reg(enum Register reg);
|
||||
|
||||
/*
|
||||
gint_strerror()
|
||||
Returns a string that describe the error set in EXPEVT in case of
|
||||
general exception of TLB miss exception. This string is platform-
|
||||
independent.
|
||||
Some exception codes represent different errors when invoked inside the
|
||||
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
||||
should be set to zero for general exception meanings, and anything non-
|
||||
zero for TLB error meanings.
|
||||
*/
|
||||
const char *gint_strerror(int is_tlb);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only.
|
||||
// Do NOT call these functions, you'll most probably screw up the whole
|
||||
// interrupt handling system.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_setVBR()
|
||||
Sets the vbr address and calls the configuration function while
|
||||
interrupts are disabled.
|
||||
*/
|
||||
void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void));
|
||||
|
||||
/*
|
||||
gint_callDefaultHandler()
|
||||
Calls the user-provided default interrupt handler.
|
||||
*/
|
||||
void gint_callDefaultHandler(int event_code);
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void);
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void);
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
void gint_setup_7705(void);
|
||||
void gint_setup_7305(void);
|
||||
|
||||
/*
|
||||
gint_stop()
|
||||
Un-configures the interrupt flow to give back the interrupt control to
|
||||
the system.
|
||||
*/
|
||||
void gint_stop_7705(void);
|
||||
void gint_stop_7305(void);
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
gint_strerror()
|
||||
See "Register access" section.
|
||||
*/
|
||||
volatile void *gint_reg_7705(enum Register reg);
|
||||
volatile void *gint_reg_7305(enum Register reg);
|
||||
const char *gint_strerror_7705(int is_tlb);
|
||||
const char *gint_strerror_7305(void);
|
||||
|
||||
|
||||
//---
|
||||
// Exception handling.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_exc()
|
||||
Handles exceptions.
|
||||
*/
|
||||
void gint_exc(void) __attribute__((section(".gint.exc.entry"),
|
||||
interrupt_handler));
|
||||
void gint_exc_7705(void) __attribute__((section(".gint.exc")));
|
||||
void gint_exc_7305(void) __attribute__((section(".gint.exc")));
|
||||
|
||||
/*
|
||||
gint_tlb()
|
||||
Handles TLB misses.
|
||||
*/
|
||||
void gint_tlb(void) __attribute__((section(".gint.tlb.entry"),
|
||||
interrupt_handler));
|
||||
void gint_tlb_7705(void) __attribute__((section(".gint.tlb")));
|
||||
void gint_tlb_7305(void) __attribute__((section(".gint.tlb")));
|
||||
|
||||
/*
|
||||
gint_int()
|
||||
Handles interrupts.
|
||||
*/
|
||||
void gint_int(void) __attribute__((section(".gint.int.entry"),
|
||||
interrupt_handler));
|
||||
void gint_int_7705(void) __attribute__((section(".gint.int")));
|
||||
void gint_int_7305(void) __attribute__((section(".gint.int")));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal platform-independent definitions.
|
||||
//---
|
||||
|
||||
#define GINT_INTP_WDT 4
|
||||
#define GINT_INTP_RTC 12
|
||||
|
||||
#define GINT_INTP_GRAY 15
|
||||
#define GINT_INTP_KEY 8
|
||||
#define GINT_INTP_TIMER 10
|
||||
|
||||
|
||||
|
||||
#endif // _GINT_H
|
|
@ -0,0 +1,160 @@
|
|||
//---
|
||||
//
|
||||
// gint core/drawing module: gray
|
||||
//
|
||||
// Runs the gray engine and handles drawing for the dual-buffer system.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _GRAY_H
|
||||
#define _GRAY_H 1
|
||||
|
||||
#include <display.h>
|
||||
|
||||
//---
|
||||
// Engine control.
|
||||
//---
|
||||
|
||||
/*
|
||||
gray_runs()
|
||||
Returns 1 if the gray engine is running, 0 otherwise.
|
||||
*/
|
||||
int gray_runs(void);
|
||||
|
||||
/*
|
||||
gray_start()
|
||||
Starts the gray engine. The control of the screen is transferred to the
|
||||
gray engine.
|
||||
*/
|
||||
void gray_start(void);
|
||||
|
||||
/*
|
||||
gray_stop()
|
||||
Stops the gray engine. The monochrome display system takes control of
|
||||
the video ram.
|
||||
*/
|
||||
void gray_stop(void);
|
||||
|
||||
/*
|
||||
gray_lightVRAM()
|
||||
Returns the module's light gray vram address.
|
||||
*/
|
||||
void *gray_lightVRAM(void);
|
||||
|
||||
/*
|
||||
gray_darkVRAM()
|
||||
Returns the module's dark gray vram address.
|
||||
*/
|
||||
void *gray_darkVRAM(void);
|
||||
|
||||
/*
|
||||
gray_getDelays()
|
||||
Returns the gray engine delays. Pointers are not set if NULL.
|
||||
*/
|
||||
void gray_getDelays(int *light, int *dark);
|
||||
|
||||
/*
|
||||
gray_setDelays()
|
||||
Changes the gray engine delays. Usually you don't need to call this,
|
||||
because the engine has its default values.
|
||||
Finding values that give proper grays is quite the hard part of the
|
||||
gray engine. Usual values are about 1000, with light being between 75
|
||||
and 90% of dark.
|
||||
|
||||
Typical values:
|
||||
|
||||
values stability stripes colors
|
||||
---------------------------------------------------------
|
||||
860, 1298 excellent worst static good
|
||||
912, 1343 bad none very good (default)
|
||||
993, 1609 medium light fast good
|
||||
1325, 1607 bad light fast excellent
|
||||
---------------------------------------------------------
|
||||
*/
|
||||
void gray_setDelays(int light, int dark);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Global drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
gupdate()
|
||||
Swaps the vram buffer sets.
|
||||
*/
|
||||
void gupdate(void);
|
||||
|
||||
/*
|
||||
gclear()
|
||||
Clears the video ram.
|
||||
*/
|
||||
void gclear(void);
|
||||
|
||||
/*
|
||||
gclear_area()
|
||||
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
||||
included.
|
||||
*/
|
||||
void gclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
greverse_area()
|
||||
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
|
||||
included.
|
||||
*/
|
||||
void greverse_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
gpixel()
|
||||
Puts a pixel in the vram.
|
||||
*/
|
||||
void gpixel(int x, int y, enum Color color);
|
||||
|
||||
/*
|
||||
gline()
|
||||
Draws a line in the vram. Automatically optimizes special cases.
|
||||
*/
|
||||
void gline(int x1, int y1, int x2, int y2, enum Color color);
|
||||
|
||||
/*
|
||||
gimage()
|
||||
Displays a gray image in the vram.
|
||||
*/
|
||||
void gimage(int x, int y, struct Image *image);
|
||||
|
||||
/*
|
||||
gimage_part()
|
||||
Draws a portion of a gray image, defined by its bounding rectangle.
|
||||
Point (left, top) is included, but (left + width, top + height) is
|
||||
excluded.
|
||||
*/
|
||||
void gimage_part(int x, int y, struct Image *image, int left, int top,
|
||||
int width, int height);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//--
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the two buffers.
|
||||
*/
|
||||
void gray_interrupt(void) __attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
void gray_init(void) __attribute__((constructor));
|
||||
|
||||
#endif // _GRAY_H
|
|
@ -0,0 +1,160 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: bopti
|
||||
//
|
||||
// bopti does every job related to display images. There is only one
|
||||
// public function, but there are lots of internal optimizations.
|
||||
//
|
||||
// Some bit-manipulation expressions may look written out of nowhere. The
|
||||
// idea is always the same: get a part of the image in an 'operator',
|
||||
// which is a 32-bit variable, shift this operator so that its bits
|
||||
// correspond to the desired position for the bitmap on the screen, and
|
||||
// edit the video-ram long entry which correspond to this position using
|
||||
// a 'mask' that indicates which bits of the operator contain information.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _INTERNALS_BOPTI_H
|
||||
#define _INTERNALS_BOPTI_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <display.h>
|
||||
|
||||
/*
|
||||
enum Channel
|
||||
Determines the kind of information written into a layer. Every image is
|
||||
made of one or more channels.
|
||||
*/
|
||||
enum Channel
|
||||
{
|
||||
Channel_FullAlpha = 0x01,
|
||||
Channel_LightAlpha = 0x02,
|
||||
Channel_DarkAlpha = 0x04,
|
||||
|
||||
Channel_Mono = 0x08,
|
||||
Channel_Light = 0x10,
|
||||
Channel_Dark = 0x20,
|
||||
};
|
||||
|
||||
/*
|
||||
enum Format
|
||||
Describes the various combination of channels allowed by bopti.
|
||||
*/
|
||||
enum Format
|
||||
{
|
||||
Format_Mono = Channel_Mono,
|
||||
Format_MonoAlpha = Format_Mono | Channel_FullAlpha,
|
||||
Format_Gray = Channel_Light | Channel_Dark,
|
||||
Format_GrayAlpha = Format_Gray | Channel_FullAlpha,
|
||||
Format_GreaterAlpha = Format_Mono | Channel_LightAlpha |
|
||||
Channel_DarkAlpha
|
||||
};
|
||||
|
||||
/*
|
||||
struct Structure
|
||||
Describes an image's structure.
|
||||
*/
|
||||
struct Structure
|
||||
{
|
||||
int width, height;
|
||||
int layer_size;
|
||||
|
||||
const unsigned char *data;
|
||||
int columns;
|
||||
int end_size, end_bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
struct Command
|
||||
Contains a drawing operation's parameters.
|
||||
*/
|
||||
struct Command
|
||||
{
|
||||
// Channel being drawn.
|
||||
enum Channel channel;
|
||||
// Operation used (whether bopti_op_mono() or bopti_op_gray()).
|
||||
void (*op)(int offset, uint32_t operator, struct Command *command);
|
||||
// Portion of the bitmap which is drawn. 'top' and 'bottom' refer to
|
||||
// lines where 'left' and 'right' refer to column ids.
|
||||
int left, right, top, bottom;
|
||||
// Position of the bitmap on the screen.
|
||||
int x, y;
|
||||
// Rectangle masks.
|
||||
uint32_t masks[4];
|
||||
};
|
||||
|
||||
// The video ram addresses are set by the public functions and used internally
|
||||
// by the module.
|
||||
// Monochrome video ram, light and dark buffers (in this order).
|
||||
extern int *bopti_vram, *bopti_v1, *bopti_v2;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Some bopti routines.
|
||||
//---
|
||||
|
||||
/*
|
||||
bopti_op()
|
||||
Operates on a vram long. The operator will often not contain 32 bits of
|
||||
image information. Since neutral bits are not the same for all
|
||||
operations, a mask is used to indicate which bits should be used for
|
||||
the operation. This mask is taken for the image's rectangle masks (see
|
||||
module display for more information on rectangle masks).
|
||||
Which operation is performed is determined by the channel setting.
|
||||
*/
|
||||
void bopti_op_mono(int offset, uint32_t operator, struct Command *c);
|
||||
void bopti_op_gray(int offset, uint32_t operator, struct Command *c);
|
||||
|
||||
/*
|
||||
bopti_grid() -- general form
|
||||
bopti_grid_a32() -- when x is a multiple of 32
|
||||
|
||||
Draws the grid at the beginning of a layer's data. The length of this
|
||||
grid is always a multiple of 32.
|
||||
The need for bopti_grid_a32() is not only linked to optimization,
|
||||
because bopti_grid() will perform a 32-bit shift when x is a multiple
|
||||
of 32, which is undefined behavior.
|
||||
bopti_grid() calls bopti_grid_32() by default.
|
||||
*/
|
||||
void bopti_grid_a32(const uint32_t *layer, int columns, int height,
|
||||
struct Command *c);
|
||||
void bopti_grid(const uint32_t *layer, int columns, int height,
|
||||
struct Command *c);
|
||||
/*
|
||||
bopti_end_get()
|
||||
Returns an operator for the end of a line, whose width is lower than 32
|
||||
(by design: otherwise, it would have been a column). The given pointer
|
||||
is read and updated so that it points to the next line at the end of
|
||||
the operation.
|
||||
*/
|
||||
uint32_t bopti_end_get1(const unsigned char **data);
|
||||
uint32_t bopti_end_get2(const unsigned char **data);
|
||||
|
||||
/*
|
||||
bopti_rest() -- general form
|
||||
bopti_rest_nover() -- when the end does not overlap two vram longs
|
||||
|
||||
Draws the end of a layer, which can be considered as a whole layer
|
||||
whose with is lower than 32. (Actually is it lower or equal to 16;
|
||||
otherwise it would have been a column and the end would be empty). The
|
||||
'size' arguments is in bytes.
|
||||
Unlike bopti_grid_a32(), bopti_end_nover() is not called automatically
|
||||
by bopti_end().
|
||||
*/
|
||||
void bopti_end_nover(const unsigned char *end, int size, struct Command *c);
|
||||
void bopti_end(const unsigned char *end, int size, struct Command *c);
|
||||
|
||||
/*
|
||||
bopti()
|
||||
Draws a layer in the video ram.
|
||||
*/
|
||||
void bopti(const unsigned char *layer, struct Structure *s, struct Command *c);
|
||||
|
||||
/*
|
||||
getStructure()
|
||||
Determines the image size and data pointer.
|
||||
*/
|
||||
void getStructure(struct Image *img, struct Structure *structure);
|
||||
|
||||
#endif // _INTERNALS_BOPTI_H
|
|
@ -0,0 +1,56 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: display
|
||||
//
|
||||
// Handles vram manipulation and drawing.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _INTERNALS_DISPLAY_H
|
||||
#define _INTERNALS_DISPLAY_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern int *vram;
|
||||
|
||||
//---
|
||||
// Rectangle masks.
|
||||
//
|
||||
// The concept of 'rectangle masks' is used several times in this module.
|
||||
// It is based on the fact that an operation that affects a rectangle acts
|
||||
// the same on all its lines. Therefore the behavior of the operation is
|
||||
// determined by its behavior on a single line, which is represented using
|
||||
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
||||
//
|
||||
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
||||
// masks will represent information '16 to 112 on x-axis', and will hold
|
||||
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
||||
// will reverse the pixels in the same rectangle.
|
||||
//
|
||||
// This technique can also be used in more subtle cases with more complex
|
||||
// patterns, but within this module it is unlikely to happen.
|
||||
//
|
||||
//---
|
||||
|
||||
/*
|
||||
adjustRectangle()
|
||||
Adjusts the given rectangle coordinates to ensure that :
|
||||
- the rectangle is entirely contained in the screen
|
||||
- x1 < x2
|
||||
- y1 < y2
|
||||
which is needed when working with screen rectangles.
|
||||
Returns non-zero if the rectangle is outside the screen.
|
||||
*/
|
||||
int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
||||
|
||||
/*
|
||||
getMasks()
|
||||
Computes the rectangle masks needed to affect pixels located between x1
|
||||
and x2 (both included). The four masks are stored in the third argument
|
||||
(seen as an array).
|
||||
*/
|
||||
void getMasks(int x1, int x2, uint32_t *masks);
|
||||
|
||||
#endif // _INTERNALS_DISPLAY_H
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _INTERNALS_EVENTS_H
|
||||
#define _INTERNALS_EVENTS_H
|
||||
|
||||
#include <events.h>
|
||||
|
||||
#ifndef EVENTS_QUEUE_SIZE
|
||||
#define EVENTS_QUEUE_SIZE 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
This module is just a circular-array queue that pushes and pops events
|
||||
like any other queue. Trying to add an event when the queue is full
|
||||
fails, and the operation is ignored.
|
||||
*/
|
||||
extern volatile struct Event event_queue[];
|
||||
extern volatile int queue_start;
|
||||
extern volatile int queue_size;
|
||||
|
||||
#endif // _INTERNALS_EVENT_H
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef _INTERNALS_GINT_H
|
||||
#define _INTERNALS_GINT_H 1
|
||||
|
||||
//---
|
||||
// Exception code strings.
|
||||
//---
|
||||
|
||||
extern const char *gint_str[];
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Register access.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_spc()
|
||||
Returns the saved program counter, which is the last state of execution
|
||||
saved by interrupt processing.
|
||||
*/
|
||||
unsigned int gint_spc(void);
|
||||
|
||||
/*
|
||||
gint_ssr()
|
||||
Returns the saved status register, which is the last configuration
|
||||
saved by interrupt processing.
|
||||
*/
|
||||
unsigned int gint_ssr(void);
|
||||
|
||||
#endif // _INTERNALS_GINT_H
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _INTERNALS_KEYBOARD_H
|
||||
#define _INTERNALS_KEYBOARD_H
|
||||
|
||||
#include <keyboard.h>
|
||||
|
||||
// Keyboard variables.
|
||||
extern volatile unsigned char keyboard_state[10];
|
||||
extern volatile int interrupt_flag;
|
||||
|
||||
// Key statistics.
|
||||
extern int repeat_first, repeat_next;
|
||||
extern int last_key, last_repeats, last_events;
|
||||
|
||||
// RTC callback id.
|
||||
extern unsigned cb_id;
|
||||
|
||||
/*
|
||||
sleep()
|
||||
Puts the CPU into sleep until an interrupt request is accepted.
|
||||
*/
|
||||
void sleep(void);
|
||||
|
||||
/*
|
||||
getPressedKey()
|
||||
Finds a pressed key in the keyboard state and returns it.
|
||||
*/
|
||||
int getPressedKey(volatile unsigned char *keyboard_state);
|
||||
|
||||
/*
|
||||
getPressedKeys()
|
||||
Find 'count' pressed keys in the keyboard state and fills the 'keys'
|
||||
array. Returns the number of keys found.
|
||||
WARNING: keyboard artifacts make this function read as pressed keys
|
||||
that aren't (typically, LEFT + DOWN + SHIFT => ALPHA).
|
||||
*/
|
||||
int getPressedKeys(volatile unsigned char *keyboard_state, int *keys,
|
||||
int count);
|
||||
|
||||
#endif // _INTERNALS_KEYBOARD_H
|
|
@ -0,0 +1,21 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: mmu
|
||||
//
|
||||
// A wise application should avoid tampering with the system's
|
||||
// configuration of the MMU and the TLB. This module implicitly calls the
|
||||
// system but does nothing by itself.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _MMU_H
|
||||
#define _MMU_H 1
|
||||
|
||||
/*
|
||||
mmu_pseudoTLBInit()
|
||||
Tries to have the system load enough data into TLB to allow add-in to
|
||||
execute.
|
||||
*/
|
||||
void mmu_pseudoTLBInit(void);
|
||||
|
||||
#endif // _MMU_H
|
|
@ -0,0 +1,141 @@
|
|||
#ifndef _INTERNALS_RTC_H
|
||||
#define _INTERNALS_RTC_H
|
||||
|
||||
#include <rtc.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef RTC_CB_ARRAY_SIZE
|
||||
#define RTC_CB_ARRAY_SIZE 5
|
||||
#endif
|
||||
|
||||
/*
|
||||
struct rtc_cb
|
||||
An RTC callback.
|
||||
*/
|
||||
struct rtc_cb
|
||||
{
|
||||
enum RTCFrequency freq;
|
||||
int id;
|
||||
|
||||
void (*callback)(void);
|
||||
int repeats;
|
||||
};
|
||||
|
||||
// The callback array.
|
||||
struct rtc_cb cb_array[RTC_CB_ARRAY_SIZE];
|
||||
|
||||
/*
|
||||
struct mod_rtc
|
||||
This structure describes the arrangement of RTC register in the memory.
|
||||
Curious thing, on SH7705, registers RYRAR and RCR3 are at a completely
|
||||
different address than the other ones. This module does not use these
|
||||
registers, so they were not included in the structure.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct mod_rtc
|
||||
{
|
||||
unsigned char const R64CNT;
|
||||
unsigned char _1;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RSECCNT;
|
||||
unsigned char _2;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMINCNT;
|
||||
unsigned char _3;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RHRCNT;
|
||||
unsigned char _4;
|
||||
|
||||
// 0 = Sunday, 1 = Monday, ..., 6 = Saturday, 7 = prohibited setting.
|
||||
unsigned char RWKCNT;
|
||||
unsigned char _5;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RDAYCNT;
|
||||
unsigned char _6;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned TENS :1;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMONCNT;
|
||||
unsigned char _7;
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned THOUSANDS :4;
|
||||
unsigned HUNDREDS :4;
|
||||
unsigned TENS :4;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RYRCNT;
|
||||
unsigned char _8[12];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned CF :1;
|
||||
unsigned :2;
|
||||
unsigned CIE :1;
|
||||
unsigned AIE :1;
|
||||
unsigned :2;
|
||||
unsigned AF :1;
|
||||
};
|
||||
} RCR1;
|
||||
unsigned char _9;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned PEF :1;
|
||||
unsigned PES :3;
|
||||
unsigned :1;
|
||||
unsigned ADJ :1;
|
||||
unsigned RESET :1;
|
||||
unsigned START :1;
|
||||
};
|
||||
} RCR2;
|
||||
} __attribute__((packed));
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/*
|
||||
We don't need to access the registers in a complicated way like the
|
||||
function of the timer module. Let's make it simple.
|
||||
*/
|
||||
#define RTC_SH7705 ((volatile struct mod_rtc *)0xfffffec0)
|
||||
#define RTC_SH7305 ((volatile struct mod_rtc *)0xa413fec0)
|
||||
|
||||
#endif // _INTERNALS_RTC_H
|
|
@ -0,0 +1,32 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: stdio
|
||||
//
|
||||
// Handles most input/output for the program. This module does not
|
||||
// interact with the file system directly.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _INTERNALS_STDIO_H
|
||||
#define _INTERNALS_STDIO_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
//---
|
||||
// Formatted printing.
|
||||
//---
|
||||
|
||||
#ifndef __stdio_buffer_size
|
||||
#define __stdio_buffer_size 256
|
||||
#endif
|
||||
|
||||
extern char __stdio_buffer[];
|
||||
|
||||
/*
|
||||
__printf()
|
||||
Formatted printing to the stdio buffer.
|
||||
*/
|
||||
int __printf(size_t size, const char *format, va_list args);
|
||||
|
||||
#endif // _INTERNALS_STDIO_H
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef _INTERNALS_TALES_H
|
||||
#define _INTERNALS_TALES_H 1
|
||||
|
||||
#include <tales.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
|
||||
|
||||
extern struct Font *font;
|
||||
extern enum Color color;
|
||||
|
||||
/*
|
||||
tales_init()
|
||||
Configures tales with the default font (which is part of gint).
|
||||
*/
|
||||
void tales_init(void) __attribute__((constructor));
|
||||
|
||||
/*
|
||||
getCharacterIndex()
|
||||
Returns the index of a character in a font data area depending on the
|
||||
font format and the size of the characters. Returns the index in the
|
||||
data area, as long array, or -1 when the character does not belong to
|
||||
the font format set.
|
||||
*/
|
||||
int getCharacterIndex(int c);
|
||||
|
||||
/*
|
||||
operate()
|
||||
Operates on the vram using the given operators. The x-coordinate should
|
||||
be a multiple of 32. There should be `height` operators.
|
||||
*/
|
||||
void operate_mono(OPERATE_ARGS);
|
||||
void operate_gray(OPERATE_ARGS);
|
||||
|
||||
/*
|
||||
update()
|
||||
Updates the operators using the given glyph. The operation will not be
|
||||
complete if there are not enough bits available in the operator data.
|
||||
In this case the offset will become negative, which means that the
|
||||
calling procedure has to call operate() and re-call update().
|
||||
`available` represents the number of free bits in the operators (lower
|
||||
bits).
|
||||
Returns the number of bits available after the operation. If it's
|
||||
negative, call operate() and update() again.
|
||||
*/
|
||||
int update(uint32_t *operators, int height, int available, uint32_t *glyph);
|
||||
|
||||
/*
|
||||
render()
|
||||
Renders text without any formatting analysis, using the given operation
|
||||
function.
|
||||
*/
|
||||
void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS));
|
||||
|
||||
#endif // _INTERNALS_TALES_H
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _INTERNALS_TIME_H
|
||||
#define _INTERNALS_TIME_H 1
|
||||
|
||||
/*
|
||||
isLeap()
|
||||
Determines whether the given year is a leap year.
|
||||
*/
|
||||
int isLeap(int year);
|
||||
|
||||
/*
|
||||
daysInMonth()
|
||||
Returns number of days for the given month (between 0 and 11) and year.
|
||||
*/
|
||||
int daysInMonth(int month, int year);
|
||||
|
||||
#endif // _INTERNALS_TIME_H
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef _INTERNALS_TIMER_H
|
||||
#define _INTERNALS_TIMER_H 1
|
||||
|
||||
/*
|
||||
struct Timer
|
||||
This structure holds information for a running timer.
|
||||
*/
|
||||
struct Timer
|
||||
{
|
||||
void (*callback)(void);
|
||||
int repeats;
|
||||
};
|
||||
|
||||
extern struct Timer timers[3];
|
||||
|
||||
/*
|
||||
struct mod_tmu
|
||||
This structure holds information about the timer unit (peripheral
|
||||
module) registers.
|
||||
*/
|
||||
struct mod_tmu
|
||||
{
|
||||
unsigned int TCOR; // Timer constant register.
|
||||
unsigned int TCNT; // Timer counter.
|
||||
|
||||
union
|
||||
{
|
||||
unsigned short WORD;
|
||||
struct
|
||||
{
|
||||
unsigned :7;
|
||||
unsigned UNF :1; // Underflow flag.
|
||||
unsigned :2;
|
||||
unsigned UNIE :1; // Underflow interrupt enable.
|
||||
unsigned CKEG :2; // Clock edge (SH7705 only).
|
||||
unsigned TPSC :3; // Timer prescaler.
|
||||
};
|
||||
} TCR; // Timer control register.
|
||||
};
|
||||
|
||||
/*
|
||||
timer_get()
|
||||
Returns the timer and TSTR register addresses.
|
||||
*/
|
||||
void timer_get(int timer, volatile struct mod_tmu **tmu,
|
||||
volatile unsigned char **tstr);
|
||||
|
||||
#endif // _INTERNALS_TIMER_H
|
|
@ -0,0 +1,303 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: keyboard analyzer
|
||||
//
|
||||
// Probably the most difficult hardware interaction. There is very few
|
||||
// documentation on how the system actually analyzes the keyboard. While
|
||||
// disassembling syscalls reveals the following procedure (which was
|
||||
// already documented by SimonLothar), there is nothing about the
|
||||
// detection problems of the multi-getkey system.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _KEYBOARD_H
|
||||
#define _KEYBOARD_H 1
|
||||
|
||||
#include <rtc.h>
|
||||
|
||||
//---
|
||||
// Keycodes and related.
|
||||
//---
|
||||
|
||||
// The following codes are gint matrix codes. They are not compatible with the
|
||||
// system's.
|
||||
|
||||
#define KEY_F1 0x69
|
||||
#define KEY_F2 0x59
|
||||
#define KEY_F3 0x49
|
||||
#define KEY_F4 0x39
|
||||
#define KEY_F4 0x39
|
||||
#define KEY_F5 0x29
|
||||
#define KEY_F6 0x19
|
||||
|
||||
#define KEY_SHIFT 0x68
|
||||
#define KEY_OPTN 0x58
|
||||
#define KEY_VARS 0x48
|
||||
#define KEY_MENU 0x38
|
||||
#define KEY_LEFT 0x28
|
||||
#define KEY_UP 0x18
|
||||
|
||||
#define KEY_ALPHA 0x67
|
||||
#define KEY_SQUARE 0x57
|
||||
#define KEY_POWER 0x47
|
||||
#define KEY_EXIT 0x37
|
||||
#define KEY_DOWN 0x27
|
||||
#define KEY_RIGHT 0x17
|
||||
|
||||
#define KEY_XOT 0x66
|
||||
#define KEY_LOG 0x56
|
||||
#define KEY_LN 0x46
|
||||
#define KEY_SIN 0x36
|
||||
#define KEY_COS 0x26
|
||||
#define KEY_TAN 0x16
|
||||
|
||||
#define KEY_FRAC 0x65
|
||||
#define KEY_FD 0x55
|
||||
#define KEY_LEFTP 0x45
|
||||
#define KEY_RIGHTP 0x35
|
||||
#define KEY_COMMA 0x25
|
||||
#define KEY_ARROW 0x15
|
||||
|
||||
#define KEY_7 0x64
|
||||
#define KEY_8 0x54
|
||||
#define KEY_9 0x44
|
||||
#define KEY_DEL 0x34
|
||||
#define KEY_AC_ON 0x24
|
||||
|
||||
#define KEY_4 0x63
|
||||
#define KEY_5 0x53
|
||||
#define KEY_6 0x43
|
||||
#define KEY_MUL 0x33
|
||||
#define KEY_DIV 0x23
|
||||
|
||||
#define KEY_1 0x62
|
||||
#define KEY_2 0x52
|
||||
#define KEY_3 0x42
|
||||
#define KEY_PLUS 0x32
|
||||
#define KEY_MINUS 0x22
|
||||
|
||||
#define KEY_0 0x61
|
||||
#define KEY_DOT 0x51
|
||||
#define KEY_EXP 0x41
|
||||
#define KEY_NEG 0x31
|
||||
#define KEY_EXE 0x21
|
||||
|
||||
// Key modifiers.
|
||||
#define MOD_SHIFT 0x80
|
||||
#define MOD_ALPHA 0x100
|
||||
#define MOD_CLEAR ~(MOD_SHIFT | MOD_ALPHA)
|
||||
|
||||
// Key events.
|
||||
#define KEY_NONE 0x00
|
||||
#define KEY_NOEVENT 0xff
|
||||
|
||||
/*
|
||||
enum KeyboardFrequency
|
||||
Possible values for the keyboard frequency.
|
||||
*/
|
||||
enum KeyboardFrequency
|
||||
{
|
||||
KeyboardFreq_500mHz = RTCFreq_500mHz,
|
||||
KeyboardFreq_1Hz = RTCFreq_1Hz,
|
||||
KeyboardFreq_2Hz = RTCFreq_2Hz,
|
||||
KeyboardFreq_4Hz = RTCFreq_4Hz,
|
||||
KeyboardFreq_16Hz = RTCFreq_16Hz,
|
||||
KeyboardFreq_64Hz = RTCFreq_64Hz,
|
||||
KeyboardFreq_256Hz = RTCFreq_256Hz,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard configuration.
|
||||
//---
|
||||
|
||||
/*
|
||||
keyboard_setFrequency()
|
||||
Sets the keyboard frequency. The default frequency is 16 Hz. Very few
|
||||
applications will need to change this setting.
|
||||
At low frequencies, you will miss key hits. At high frequencies, you
|
||||
may lose execution power.
|
||||
*/
|
||||
void keyboard_setFrequency(enum KeyboardFrequency frequency);
|
||||
|
||||
/*
|
||||
keyboard_setRepeatRate()
|
||||
Sets the default repeat rate for key events. The delay before the first
|
||||
repeat may have a different value (usually longer). The unit for the
|
||||
argument is the keyboard period. For example at 32 Hz, values of
|
||||
(20, 4) will imitate the system default.
|
||||
Set to 0 to disable repetition. If first = 0, no repetition will be
|
||||
allowed. If first != 0 and next = 0, only one repetition will be
|
||||
allowed.
|
||||
*/
|
||||
void keyboard_setRepeatRate(int first, int next);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard access.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum GetKeyOpt
|
||||
Options available for use with getkey_opt().
|
||||
*/
|
||||
enum GetkeyOpt
|
||||
{
|
||||
Getkey_NoOption = 0x00,
|
||||
|
||||
// Consider [SHIFT] and [ALPHA] as modifiers instead of returning
|
||||
// KEY_SHIFT and KEY_ALPHA.
|
||||
Getkey_ShiftModifier = 0x01,
|
||||
Getkey_AlphaModifier = 0x02,
|
||||
|
||||
// Key repetition. Notice that modifiers will never be repeated.
|
||||
Getkey_RepeatArrowKeys = 0x10,
|
||||
Getkey_RepeatCharKeys = 0x20,
|
||||
Getkey_RepeatCtrlKeys = 0x40,
|
||||
Getkey_RepeatFuncKeys = 0x80,
|
||||
// Shorthand for the four previous properties.
|
||||
Getkey_RepeatAllKeys = 0xf0,
|
||||
};
|
||||
|
||||
/*
|
||||
keylast()
|
||||
Returns the matrix code of the last pressed key. If repeat_count is
|
||||
non-NULL, it is set to the number of repetitions.
|
||||
*/
|
||||
int keylast(int *repeat_count);
|
||||
|
||||
/*
|
||||
keystate()
|
||||
Returns the address of the keyboard state array. The keyboard state
|
||||
consists in 10 bytes, in which every key is represented as a bit.
|
||||
The returned address is the original buffer address. You should avoid
|
||||
editing the array. It wouldn't influence the behavior of the keyboard
|
||||
functions, but the buffer data is very volatile. Therefore, data
|
||||
written to the buffer could be replaced anytime.
|
||||
*/
|
||||
volatile unsigned char *keystate(void);
|
||||
|
||||
/*
|
||||
getkey()
|
||||
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
||||
Reproduces the behavior of the system's GetKey(). Returns the matrix
|
||||
code with a possible MOD_SHIFT bit.
|
||||
*/
|
||||
int getkey(void);
|
||||
|
||||
/*
|
||||
getkey_opt()
|
||||
Enhances getkey() with most general functionalities. An OR-combination
|
||||
of options may be given as second argument.
|
||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
KEY_NOEVENT if no event occurs during max_cycle analysis.
|
||||
As getkey(), returns the pressed key matrix code, possibly with
|
||||
modifiers depending on the options.
|
||||
*/
|
||||
int getkey_opt(enum GetkeyOpt options, int max_cycles);
|
||||
|
||||
/*
|
||||
multigetkey()
|
||||
|
||||
Listens the keyboard for simultaneous key hits. This functions fills
|
||||
array `keys` with `count` keycodes, adding KEY_NONE at the end if
|
||||
less than `count` keys are pressed.
|
||||
If `max_cycles` is non-zero and nothing happens after `max_cycles`
|
||||
cycles, this function returns an array of KEY_NONE.
|
||||
|
||||
WARNING:
|
||||
Because of hardware limitations, this function generally yields poor
|
||||
results. Rectangle and column effects make it read unpressed keys as
|
||||
pressed (see documentation for more information). The more pressed
|
||||
keys, the more errors.
|
||||
|
||||
The results are guaranteed to be exact if two keys or less are pressed.
|
||||
With three keys or more, column effects (on SH4) and rectangle effects
|
||||
(on both platforms) mess up the results by making this function think
|
||||
that some keys, which are actually unpressed, are pressed.
|
||||
|
||||
This function is designed to make combinations of one or two arrow keys
|
||||
with another key as viable as possible. On SH4, this works pretty well
|
||||
even if combinations like Left + Down + SHIFT trigger ALPHA sometimes.
|
||||
On SH3, rectangle effects are *always* present, making it impossible to
|
||||
use Left + Down or Up + Right with any other key in their rows without
|
||||
having this function return junk.
|
||||
|
||||
Any other combination of keys may quite randomly result in variably
|
||||
incorrect results. Please do not expect multigetkey() to work as an
|
||||
ideal multi-key analyzer.
|
||||
*/
|
||||
void multigetkey(int *keys, int count, int max_cycles);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Key analysis.
|
||||
//---
|
||||
|
||||
enum KeyType
|
||||
{
|
||||
KeyType_Arrow = 1,
|
||||
KeyType_Character = 2,
|
||||
KeyType_Control = 4,
|
||||
KeyType_Function = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
keyid()
|
||||
Returns a non-matrix key code that can be used for array subscript.
|
||||
Ignores modifiers.
|
||||
*/
|
||||
int keyid(int key);
|
||||
|
||||
/*
|
||||
keychar()
|
||||
Returns the ASCII character associated with a character key; 0 for
|
||||
other keys.
|
||||
*/
|
||||
int keychar(int key);
|
||||
|
||||
/*
|
||||
keytype()
|
||||
Returns a key's type. Ignores modifiers.
|
||||
*/
|
||||
enum KeyType keytype(int key);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Reference here for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
keyboard_interrupt()
|
||||
Notifies the keyboard module that an interrupt request has been issued,
|
||||
and updates the keyboard state.
|
||||
*/
|
||||
void keyboard_interrupt(void) __attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
keyboard_updateState()
|
||||
Updates the keyboard state.
|
||||
*/
|
||||
void keyboard_updateState_7705(volatile unsigned char *state)
|
||||
__attribute__((section(".gint.int")));
|
||||
void keyboard_updateState_7305(volatile unsigned char *state)
|
||||
__attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
keyboard_init()
|
||||
Starts the keyboard timer.
|
||||
*/
|
||||
void keyboard_init(void) __attribute__((constructor));
|
||||
|
||||
/*
|
||||
keyboard_quit()
|
||||
Stops the keyboard timer.
|
||||
*/
|
||||
void keyboard_quit(void) __attribute__((destructor));
|
||||
|
||||
#endif // _KEYBOARD_H
|
|
@ -0,0 +1,76 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: mpu
|
||||
//
|
||||
// Determines which kind of MPU is running the program. This module
|
||||
// provides macro tests isSH3(), isSH4(), and the identifier of the MPU,
|
||||
// which is stored in a global variable MPU_CURRENT.
|
||||
//
|
||||
// If you need to do MPU-dependant jobs, prefer the following alternative:
|
||||
//
|
||||
// if(isSH3())
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _MPU_H
|
||||
#define _MPU_H 1
|
||||
|
||||
/*
|
||||
enum MPU
|
||||
This type holds information about the calculator's MPU.
|
||||
*/
|
||||
enum MPU
|
||||
{
|
||||
MPU_Unknown = 0,
|
||||
// fx-9860G SH3.
|
||||
MPU_SH7337 = 1,
|
||||
// fx-9860G II SH3.
|
||||
MPU_SH7355 = 2,
|
||||
// fx-9860G II SH4.
|
||||
MPU_SH7305 = 3,
|
||||
// Just for reference.
|
||||
MPU_SH7724 = 4
|
||||
};
|
||||
|
||||
// Global MPU variable, accessible for direct tests. Initialized at the
|
||||
// beginning of execution.
|
||||
extern enum MPU MPU_CURRENT;
|
||||
|
||||
// Quick SH3 test. It is safer to assume that an unknown model is SH4 because
|
||||
// SH3-based models are not produced anymore.
|
||||
#define isSH3() (MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355)
|
||||
#define isSH4() !isSH3()
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
getMPU()
|
||||
Determines the MPU type and returns it. MPU_CURRENT is not updated.
|
||||
*/
|
||||
enum MPU getMPU(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
mpu_init()
|
||||
Determines the MPU type and stores the result into MPU_CURRENT.
|
||||
*/
|
||||
void mpu_init(void) __attribute__((constructor));
|
||||
|
||||
#endif // _MPU_H
|
|
@ -0,0 +1,121 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: rtc
|
||||
//
|
||||
// Manages RTC. This module is used behind standard module time.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _RTC_H
|
||||
#define _RTC_H 1
|
||||
|
||||
//---
|
||||
// Time access.
|
||||
//---
|
||||
|
||||
/*
|
||||
struct RTCTime
|
||||
Defines a point in time.
|
||||
*/
|
||||
struct RTCTime
|
||||
{
|
||||
int seconds; // Seconds in range 0-59
|
||||
int minutes; // Minutes in range 0-59
|
||||
int hours; // Hours in range 0-23
|
||||
int month_day; // Day of month in range 1-31
|
||||
int month; // Month in range 0-11
|
||||
int year; // Years (full value)
|
||||
int week_day; // Day of week in range 0(Sunday)-6(Saturday).
|
||||
};
|
||||
|
||||
/*
|
||||
rtc_getTime()
|
||||
Reads the current time from the RTC. There is no guarantee that the
|
||||
week day is correct (use the time API for that).
|
||||
*/
|
||||
struct RTCTime rtc_getTime(void);
|
||||
|
||||
/*
|
||||
rtc_setTime()
|
||||
Sets the time in the RTC registers. The week day is set to 0 if greater
|
||||
than 6. Other fields are not checked.
|
||||
*/
|
||||
void rtc_setTime(struct RTCTime time);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Callback API.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum RTCFrequency
|
||||
Describes the possible frequencies available for the real-time clock
|
||||
interrupt.
|
||||
*/
|
||||
enum RTCFrequency
|
||||
{
|
||||
RTCFreq_500mHz = 7,
|
||||
RTCFreq_1Hz = 6,
|
||||
RTCFreq_2Hz = 5,
|
||||
RTCFreq_4Hz = 4,
|
||||
RTCFreq_16Hz = 3,
|
||||
RTCFreq_64Hz = 2,
|
||||
RTCFreq_256Hz = 1,
|
||||
RTCFreq_None = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
rtc_cb_add()
|
||||
Registers a new callback for the RTC. Returns the callback id on
|
||||
success (positive integer), or one of the following error codes:
|
||||
-1 Array is full
|
||||
-2 Invalid parameter
|
||||
The number of repeats may be set to 0, in which case the callback is
|
||||
called indefinitely unless the user calls rtc_cb_end().
|
||||
*/
|
||||
int rtc_cb_add(enum RTCFrequency freq, void (*function)(void), int repeats);
|
||||
|
||||
/*
|
||||
rtc_cb_end()
|
||||
Removes the callback with the given id (as returned by rtc_cb_add())
|
||||
from the callback array.
|
||||
*/
|
||||
void rtc_cb_end(int id);
|
||||
|
||||
/*
|
||||
rtc_cb_edit()
|
||||
Changes information related to a callback. This function returns 0 on
|
||||
success, or one of the following error codes:
|
||||
-1 Callback does not exist
|
||||
-2 Invalid parameters
|
||||
This function never removes a callback. Call rtc_cb_end() for this. One
|
||||
can set the function to NULL or the frequency to RTCFreq_None to
|
||||
temporarily disable the callback.
|
||||
*/
|
||||
int rtc_cb_edit(int id, enum RTCFrequency new_freq,
|
||||
void (*new_function)(void));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
rtc_interrupt()
|
||||
Handles an RTC interrupt by calling the callback.
|
||||
*/
|
||||
void rtc_interrupt(void) __attribute__((section(".gint.int")));
|
||||
void rtc_interrupt_7705(void) __attribute__((section(".gint.int")));
|
||||
void rtc_interrupt_7305(void) __attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
rtc_cb_interrupt()
|
||||
Handles an RTC interrupt. Calls the RTC callbacks if necessary, and
|
||||
updates the repeat counts.
|
||||
*/
|
||||
void rtc_cb_interrupt(void);
|
||||
|
||||
#endif // _RTC_H
|
|
@ -0,0 +1,23 @@
|
|||
//---
|
||||
//
|
||||
// gint display module: screen
|
||||
//
|
||||
// Interacts with the physical screen. See other display modules for video
|
||||
// ram management and drawing.
|
||||
//
|
||||
// The screen basically has two input values, which are a register
|
||||
// selector and the selected register's value. What this module does is
|
||||
// essentially selecting registers by setting *selector and assigning them
|
||||
// values by setting *data.
|
||||
//---
|
||||
|
||||
#ifndef _SCREEN_H
|
||||
#define _SCREEN_H 1
|
||||
|
||||
/*
|
||||
screen_display()
|
||||
Displays contents on the full screen. Expects a 1024-byte buffer.
|
||||
*/
|
||||
void screen_display(const void *vram);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
//---
|
||||
//
|
||||
// gint standard module: setjmp
|
||||
//
|
||||
// Long jumps. The register contents are saved in a buffer when setjmp()
|
||||
// is called and restored at any time when longjmp() performs the jump.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H 1
|
||||
|
||||
// There are 16 CPU registers that *must* be saved to ensure a basically
|
||||
// safe jump.
|
||||
typedef unsigned int jmp_buf[16];
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Long jump functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
setjmp() O(1)
|
||||
Configures a jump by saving data to the given jump buffer.
|
||||
*/
|
||||
int setjmp(jmp_buf env);
|
||||
|
||||
/*
|
||||
longjmp() O(1)
|
||||
Performs a long jump.
|
||||
*/
|
||||
void longjmp(jmp_buf env, int value);
|
||||
|
||||
#endif // _SETJMP_H
|
|
@ -0,0 +1,44 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: stdio
|
||||
//
|
||||
// Handles most input/output for the program. This module does not
|
||||
// interact with the file system directly.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _STDIO_H
|
||||
#define _STDIO_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
//---
|
||||
// Formatted printing.
|
||||
//---
|
||||
|
||||
/*
|
||||
sprintf()
|
||||
Prints to a string.
|
||||
*/
|
||||
int sprintf(char *str, const char *format, ...);
|
||||
|
||||
/*
|
||||
snprintf()
|
||||
Prints to a string with a size limit.
|
||||
*/
|
||||
int snprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
/*
|
||||
vsprintf()
|
||||
Prints to a string from an argument list.
|
||||
*/
|
||||
int vsprintf(char *str, const char *format, va_list args);
|
||||
|
||||
/*
|
||||
vsnprintf()
|
||||
The most generic formatted printing function around there.
|
||||
*/
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list args);
|
||||
|
||||
#endif // _STDIO_H
|
|
@ -0,0 +1,149 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: stdlib
|
||||
//
|
||||
// Provides standard functionalities such as dynamic allocation,
|
||||
// string/numeric conversion, and abort calls.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H 1
|
||||
|
||||
//---
|
||||
// Common definitions.
|
||||
//---
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
// Common exit codes.
|
||||
#define EXIT_SUCCESS 1
|
||||
#define EXIT_FAILURE 0
|
||||
|
||||
// Number of atexit() registrations guaranteed.
|
||||
#ifndef ATEXIT_MAX
|
||||
#define ATEXIT_MAX 16
|
||||
#endif
|
||||
|
||||
// Maximum value returned by rand().
|
||||
#define RAND_MAX INT_MAX
|
||||
|
||||
// Integer division result.
|
||||
typedef struct
|
||||
{
|
||||
int quot, rem;
|
||||
} div_t;
|
||||
typedef struct
|
||||
{
|
||||
long quot, rem;
|
||||
} ldiv_t;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Program exit functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
abort()
|
||||
Aborts the program execution without calling the exit handlers.
|
||||
*/
|
||||
void abort(void);
|
||||
|
||||
/*
|
||||
exit()
|
||||
Stops the program execution with the given status code, after calling
|
||||
the exit handlers.
|
||||
*/
|
||||
void exit(int status);
|
||||
|
||||
/*
|
||||
atexit()
|
||||
Registers a function to be called at normal program termination.
|
||||
*/
|
||||
int atexit(void (*function)(void));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Dynamic storage allocation.
|
||||
//---
|
||||
|
||||
/*
|
||||
malloc()
|
||||
Allocates 'size' bytes and returns a pointer to a free memory area.
|
||||
Returns NULL on error.
|
||||
*/
|
||||
void *malloc(size_t size);
|
||||
|
||||
/*
|
||||
calloc()
|
||||
Allocates 'n' elements of size 'size' and wipes the memory area.
|
||||
Returns NULL on error.
|
||||
*/
|
||||
void *calloc(size_t n, size_t size);
|
||||
|
||||
/*
|
||||
realloc()
|
||||
Reallocates a memory block and moves its data.
|
||||
*/
|
||||
void *realloc(void *ptr, size_t size);
|
||||
|
||||
/*
|
||||
free()
|
||||
Frees a memory block allocated by malloc(), calloc() or realloc().
|
||||
*/
|
||||
void free(void *ptr);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Random number generation.
|
||||
//---
|
||||
|
||||
/*
|
||||
rand()
|
||||
Returns a pseudo-random number.
|
||||
*/
|
||||
int rand(void);
|
||||
|
||||
/*
|
||||
srand()
|
||||
Changes the seed used by rand().
|
||||
*/
|
||||
void srand(unsigned int seed);
|
||||
|
||||
//---
|
||||
// Integer arithmetic.
|
||||
//---
|
||||
|
||||
/*
|
||||
abs()
|
||||
Returns the absolute value of an integer.
|
||||
*/
|
||||
int abs(int x);
|
||||
// Use a macro instead, when possible.
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
/*
|
||||
labs()
|
||||
Returns the absolute value of a long integer.
|
||||
*/
|
||||
long labs(long x);
|
||||
// Use a macro instead.
|
||||
#define labs(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
/*
|
||||
div()
|
||||
Computes the integer division of numerator by denominator.
|
||||
*/
|
||||
div_t div(int numerator, int denominator);
|
||||
|
||||
/*
|
||||
ldiv()
|
||||
Computes the integer division of two long integers.
|
||||
*/
|
||||
ldiv_t ldiv(long numerator, long denominator);
|
||||
|
||||
#endif // _STDLIB_H
|
|
@ -0,0 +1,63 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: string
|
||||
//
|
||||
// String manipulation using NUL-terminated byte arrays, without extended
|
||||
// characters.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Memory manipulation.
|
||||
//---
|
||||
|
||||
/*
|
||||
memcpy() O(byte_number)
|
||||
Copies a memory area. The two areas must not overlap (if they do, use
|
||||
memmove()). A smart copy is performed when possible. To enhance
|
||||
performance, make sure than destination and source are both 4-aligned.
|
||||
*/
|
||||
void *memcpy(void *destination, const void *source, size_t byte_number);
|
||||
|
||||
/*
|
||||
memset() O(byte_number)
|
||||
Sets the contents of a memory area. A smart copy is performed.
|
||||
*/
|
||||
void *memset(void *destination, int byte, size_t byte_number);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// String manipulation.
|
||||
//---
|
||||
|
||||
/*
|
||||
strlen() O(len(str))
|
||||
Returns the length of a string.
|
||||
*/
|
||||
size_t strlen(const char *str);
|
||||
|
||||
/*
|
||||
strcpy() O(len(source))
|
||||
Copies a string to another.
|
||||
*/
|
||||
char *strcpy(char *destination, const char *source);
|
||||
|
||||
/*
|
||||
strchr() O(len(str))
|
||||
Searches a character in a string.
|
||||
*/
|
||||
const char *strchr(const char *str, int value);
|
||||
|
||||
/*
|
||||
strncpy() O(min(len(source), size))
|
||||
Copies part of a string to another.
|
||||
*/
|
||||
char *strncpy(char *destination, const char *source, size_t size);
|
||||
|
||||
#endif // _STRING_H
|
|
@ -0,0 +1,123 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: tales
|
||||
//
|
||||
// Text displaying. Does some pretty good optimization, though requires
|
||||
// dynamic allocation. The stack is used.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _TALES_H
|
||||
#define _TALES_H 1
|
||||
|
||||
#include <display.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//---
|
||||
// Types and constants.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum ImageFormat
|
||||
This type holds information about the characters in the font. Each bit
|
||||
represents various characters, and the type itself is a combination of
|
||||
several of those bits.
|
||||
Bits represent the following characters (lsb right):
|
||||
-- -- -- non-print | special capitals lower numbers
|
||||
*/
|
||||
enum FontFormat
|
||||
{
|
||||
FontFormat_Unknown = 0x00,
|
||||
FontFormat_Numeric = 0x01,
|
||||
FontFormat_LowerCase = 0x02,
|
||||
FontFormat_UpperCase = 0x04,
|
||||
FontFormat_Letters = 0x06,
|
||||
FontFormat_Common = 0x07,
|
||||
FontFormat_Print = 0x0f,
|
||||
FontFormat_Ascii = 0x1f,
|
||||
};
|
||||
|
||||
/*
|
||||
struct FontGlyph
|
||||
Holds a glyph's data. The width is used for spacing, and the raw data
|
||||
is encoded line after line, from to to bottom, by appending bits
|
||||
without consideration of the byte boundaries.
|
||||
This structure is actually never used, because data is read directly
|
||||
as a longword array (hence the 4-byte alignment).
|
||||
*/
|
||||
struct FontGlyph
|
||||
{
|
||||
unsigned char width;
|
||||
|
||||
const unsigned char data[];
|
||||
} __attribute__((aligned(4)));
|
||||
|
||||
/*
|
||||
struct Font
|
||||
Holds a font's data. Data is accessed using longword operations, hence
|
||||
the 4-alignment attributes. The line height is the one given in the
|
||||
font image header line, which may be used by applications that write
|
||||
strings on several lines. The data height is the height of the biggest
|
||||
glyph. Every glyph is encoded on 'data_height' lines, for optimization
|
||||
considerations.
|
||||
The index field is used to reduce character access time.
|
||||
The name field may not be NUL-terminated when the name contains 28
|
||||
characters. When the name is shorter, the field is padded with zeros.
|
||||
*/
|
||||
struct Font
|
||||
{
|
||||
unsigned char magic;
|
||||
|
||||
unsigned char format;
|
||||
unsigned char line_height;
|
||||
unsigned char data_height;
|
||||
|
||||
// Warning : this field may not be NUL-terminated.
|
||||
char name[28];
|
||||
|
||||
uint16_t index[16];
|
||||
|
||||
__attribute__((aligned(4))) const uint32_t glyphs[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
// Useful shorthand for user code.
|
||||
typedef struct Font Font;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
text_configure()
|
||||
Sets the font and color to use for subsequent text operations. Pass
|
||||
font = NULL to use the default font.
|
||||
*/
|
||||
void text_configure(struct Font *font, enum Color color);
|
||||
|
||||
/*
|
||||
dtext()
|
||||
Prints the given string, without any analysis.
|
||||
*/
|
||||
void dtext(int x, int y, const char *str);
|
||||
|
||||
/*
|
||||
gtext()
|
||||
Prints the given raw string.
|
||||
*/
|
||||
void gtext(int x, int y, const char *str);
|
||||
|
||||
/*
|
||||
dprint()
|
||||
Prints a formatted string. Works the same as printf().
|
||||
*/
|
||||
void dprint(int x, int y, const char *format, ...);
|
||||
|
||||
/*
|
||||
gprint()
|
||||
Prints a formatted string. Works the same as printf().
|
||||
*/
|
||||
void gprint(int x, int y, const char *format, ...);
|
||||
|
||||
#endif // _TALES_H
|
|
@ -0,0 +1,126 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: time
|
||||
//
|
||||
// Provides time manipulation and representation functions.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _TIME_H
|
||||
#define _TIME_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Some related types.
|
||||
//---
|
||||
|
||||
/*
|
||||
struct tm
|
||||
Represents a point in time and gives some date information.
|
||||
*/
|
||||
struct tm
|
||||
{
|
||||
int tm_sec; // Seconds in range 0-59
|
||||
int tm_min; // Minutes in range 0-59
|
||||
int tm_hour; // Hours in range 0-23
|
||||
int tm_mday; // Day of month in range 1-31
|
||||
int tm_mon; // Month in range 0-11
|
||||
int tm_year; // Number of years since 1900
|
||||
int tm_wday; // Day of week in range 0(Sunday)-6(Saturday).
|
||||
int tm_yday; // Day of the year in range 0-365.
|
||||
int tm_isdst; // This will always be 0.
|
||||
};
|
||||
|
||||
/*
|
||||
clock_t
|
||||
Only used by clock().
|
||||
*/
|
||||
typedef signed int clock_t;
|
||||
|
||||
/*
|
||||
time_t
|
||||
Number of seconds elapsed since 1970-01-01 00:00:00.
|
||||
*/
|
||||
typedef signed int time_t;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Time access.
|
||||
//---
|
||||
|
||||
/*
|
||||
clock()
|
||||
Should return elapsed CPU time since beginning of program execution.
|
||||
This is currently not implemented and returns -1.
|
||||
*/
|
||||
clock_t clock(void);
|
||||
|
||||
/*
|
||||
time()
|
||||
Returns the current time as calendar time. If you need a broken-down
|
||||
time, either use the RTC API or gmtime(). However, this function is
|
||||
already based on mktime() (for hardware reasons) so it would be much
|
||||
faster to use the RTC API if possible.
|
||||
If timeptr is not NULL, it is set to the current time, that is, the
|
||||
value that is returned.
|
||||
*/
|
||||
time_t time(time_t *timeptr);
|
||||
|
||||
/*
|
||||
difftime()
|
||||
Returns the number of seconds between the given points.
|
||||
*/
|
||||
double difftime(time_t end, time_t beginning);
|
||||
// But this macro should do.
|
||||
#define difftime(end, beginning) ((double)((end) - (beginning)))
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Time representation.
|
||||
//---
|
||||
|
||||
/*
|
||||
asctime()
|
||||
Converts broken-down time to string representation on the form
|
||||
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
|
||||
allocated and may be overwritten by any subsequent call to a time
|
||||
function.
|
||||
*/
|
||||
char *asctime(const struct tm *time);
|
||||
|
||||
/*
|
||||
ctime()
|
||||
Converts calendar time to string representation on the form
|
||||
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
|
||||
allocated and may be overwritten by any subsequent call to a time
|
||||
function.
|
||||
*/
|
||||
char *ctime(const time_t *timer);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Time conversion.
|
||||
//---
|
||||
|
||||
/*
|
||||
mktime()
|
||||
Converts broken-down time to calendar time. Computes structure fields
|
||||
tm_wday and tm_yday using the other fields. Member structures outside
|
||||
their range are normalized (e.g. 40 October becomes 9 November) and
|
||||
tm_isdst is set.
|
||||
*/
|
||||
time_t mktime(struct tm *time);
|
||||
|
||||
/*
|
||||
gmtime()
|
||||
Converts calendar time to broken-down time. The returned pointer is
|
||||
statically allocated and may be overwritten by any subsequent call to
|
||||
a time function.
|
||||
*/
|
||||
struct tm *gmtime(const time_t *t);
|
||||
|
||||
#endif // _TIME_H
|
|
@ -0,0 +1,89 @@
|
|||
//---
|
||||
//
|
||||
// gint core module: timer
|
||||
//
|
||||
// Basic timer unit manipulation. Starts and stops timers with variable
|
||||
// number of repeats, and allows timer reloads without pause.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H 1
|
||||
|
||||
#include <clock.h>
|
||||
|
||||
//---
|
||||
// Constants.
|
||||
//---
|
||||
|
||||
// Timer identifiers.
|
||||
#define TIMER_0 0
|
||||
#define TIMER_TMU0 TIMER_0
|
||||
#define TIMER_1 1
|
||||
#define TIMER_TMU1 TIMER_1
|
||||
#define TIMER_2 2
|
||||
#define TIMER_TMU2 TIMER_2
|
||||
// Timer function identifiers.
|
||||
#define TIMER_KEYBOARD TIMER_TMU0
|
||||
#define TIMER_GRAY TIMER_TMU1
|
||||
#define TIMER_USER TIMER_TMU2
|
||||
|
||||
// Timer prescalers.
|
||||
#define TIMER_Po_4 0
|
||||
#define TIMER_Po_16 1
|
||||
#define TIMER_Po_64 2
|
||||
#define TIMER_Po_256 3
|
||||
#define TIMER_TCLK 5
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
timer_start()
|
||||
Configures and starts a timer. The timer argument expects a timer name.
|
||||
You can use TIMER_USER anytime. You may also use TIMER_GRAY if you're
|
||||
not running the gray engine.
|
||||
The delay is in clock counts unit. The possible values for the
|
||||
prescaler are dividers of the peripheral clock frequency Po:
|
||||
- TIMER_Po_4
|
||||
- TIMER_Po_16
|
||||
- TIMER_Po_64
|
||||
- TIMER_Po_256
|
||||
- TIMER_TCLK
|
||||
The number of repeats may to set to 0. In this case, the timer will not
|
||||
stop until timer_stop() is explicitly called.
|
||||
*/
|
||||
void timer_start(int timer, int delay, int prescaler, void (*callback)(void),
|
||||
int repeats);
|
||||
|
||||
/*
|
||||
timer_stop()
|
||||
Stops the given timer. This function may be called even if the timer is
|
||||
not running.
|
||||
*/
|
||||
void timer_stop(int timer);
|
||||
|
||||
/*
|
||||
timer_reload()
|
||||
Reloads the given timer with the given constant. Starts the timer if
|
||||
it was stopped. The new delay uses the same unit as in timer_start().
|
||||
*/
|
||||
void timer_reload(int timer, int new_delay);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
timer_interrupt()
|
||||
Handles the interrupt for the given timer.
|
||||
*/
|
||||
void timer_interrupt(int timer) __attribute__((section(".gint.int")));
|
||||
|
||||
#endif // _TIMER_H
|
|
@ -0,0 +1,329 @@
|
|||
#include <internals/bopti.h>
|
||||
|
||||
// Monochrome video ram, light and dark buffers (in this order).
|
||||
int *bopti_vram, *bopti_v1, *bopti_v2;
|
||||
|
||||
/*
|
||||
bopti_op()
|
||||
Operates on a vram long. The operator will often not contain 32 bits of
|
||||
image information. Since neutral bits are not the same for all
|
||||
operations, a mask is used to indicate which bits should be used for
|
||||
the operation. This mask is taken for the image's rectangle masks (see
|
||||
module display for more information on rectangle masks).
|
||||
Which operation is performed is determined by the channel setting.
|
||||
*/
|
||||
void bopti_op_mono(int offset, uint32_t operator, struct Command *c)
|
||||
{
|
||||
operator &= c->masks[offset & 3];
|
||||
|
||||
switch(c->channel)
|
||||
{
|
||||
case Channel_FullAlpha:
|
||||
bopti_vram[offset] &= ~operator;
|
||||
break;
|
||||
|
||||
case Channel_Mono:
|
||||
bopti_vram[offset] |= operator;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
|
||||
{
|
||||
operator &= c->masks[offset & 3];
|
||||
|
||||
switch(c->channel)
|
||||
{
|
||||
case Channel_FullAlpha:
|
||||
bopti_v1[offset] &= ~operator;
|
||||
bopti_v2[offset] &= ~operator;
|
||||
break;
|
||||
|
||||
case Channel_LightAlpha:
|
||||
case Channel_DarkAlpha:
|
||||
break;
|
||||
|
||||
case Channel_Mono:
|
||||
bopti_v1[offset] |= operator;
|
||||
bopti_v2[offset] |= operator;
|
||||
break;
|
||||
|
||||
case Channel_Light:
|
||||
bopti_v1[offset] |= operator;
|
||||
break;
|
||||
|
||||
case Channel_Dark:
|
||||
bopti_v2[offset] |= operator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bopti_grid() -- general form
|
||||
bopti_grid_a32() -- when x is a multiple of 32
|
||||
|
||||
Draws the grid at the beginning of a layer's data. The length of this
|
||||
grid is always a multiple of 32.
|
||||
The need for bopti_grid_a32() is not only linked to optimization,
|
||||
because bopti_grid() will perform a 32-bit shift when x is a multiple
|
||||
of 32, which is undefined behavior.
|
||||
*/
|
||||
void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
|
||||
struct Command *c)
|
||||
{
|
||||
int vram_column_offset = (c->y << 2) + (c->x >> 5);
|
||||
int vram_offset = vram_column_offset;
|
||||
int column, row;
|
||||
|
||||
for(column = 0; column < column_count; column++)
|
||||
{
|
||||
for(row = c->top; row < c->bottom; row++)
|
||||
{
|
||||
(*c->op)(vram_offset, layer[row], c);
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
vram_column_offset++;
|
||||
vram_offset = vram_column_offset;
|
||||
layer += height;
|
||||
}
|
||||
}
|
||||
void bopti_grid(const uint32_t *layer, int column_count, int height,
|
||||
struct Command *c)
|
||||
{
|
||||
if(!column_count) return;
|
||||
if(!(c->x & 31))
|
||||
{
|
||||
bopti_grid_a32(layer, column_count, height, c);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t *p1, *p2;
|
||||
uint32_t l1, l2, operator;
|
||||
int right_column, line;
|
||||
int actual_column_count;
|
||||
|
||||
int vram_column_offset = (c->y << 2) + (c->x >> 5) + (c->x < 0);
|
||||
int vram_offset = vram_column_offset;
|
||||
|
||||
int shift1 = 32 - (c->x & 31);
|
||||
int shift2 = (c->x & 31);
|
||||
|
||||
// Initializing two pointers. They will read two adjacent columns at
|
||||
// the same time (p2 is column ahead of p1). Since the columns are
|
||||
// written one after another, incrementing them will suffice when
|
||||
// reaching the end of two columns, to move them to the next ones.
|
||||
p1 = layer - height;
|
||||
p2 = layer;
|
||||
|
||||
// We don't want to write the first vram column when x is negative
|
||||
// because it's outside the screen.
|
||||
if(c->x < 0) p1 += height, p2 += height;
|
||||
right_column = (c->x < 0);
|
||||
// For the same reason, we don't to draw the additional rightmost
|
||||
// column when it begins after 96.
|
||||
if(c->x + (column_count << 5) > 128)
|
||||
actual_column_count = column_count - 1;
|
||||
else
|
||||
actual_column_count = column_count;
|
||||
|
||||
// Drawing vram longwords, using pairs of columns.
|
||||
while(right_column <= actual_column_count)
|
||||
{
|
||||
for(line = c->top; line < c->bottom; line++)
|
||||
{
|
||||
l1 = (right_column > 0) ? p1[line] : (0);
|
||||
l2 = (right_column < column_count) ? p2[line] : (0);
|
||||
|
||||
operator = (l1 << shift1) | (l2 >> shift2);
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
p1 += height;
|
||||
p2 += height;
|
||||
vram_column_offset++;
|
||||
vram_offset = vram_column_offset;
|
||||
right_column++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bopti_end_get()
|
||||
Returns an operator for the end of a line, whose width is lower than 32
|
||||
(by design: otherwise, it would have been a column). The given pointer
|
||||
is read and updated so that it points to the next line at the end of
|
||||
the operation.
|
||||
*/
|
||||
uint32_t bopti_end_get1(const unsigned char **data)
|
||||
{
|
||||
uint32_t operator = **data;
|
||||
*data += 1;
|
||||
return operator;
|
||||
}
|
||||
uint32_t bopti_end_get2(const unsigned char **data)
|
||||
{
|
||||
uint32_t operator = *((uint16_t *)*data);
|
||||
*data += 2;
|
||||
return operator;
|
||||
}
|
||||
|
||||
/*
|
||||
bopti_rest() -- general form
|
||||
bopti_rest_nover() -- when the end does not overlap two vram longs
|
||||
|
||||
Draws the end of a layer, which can be considered as a whole layer
|
||||
whose with is lower than 32. (Actually is it lower or equal to 16;
|
||||
otherwise it would have been a column and the end would be empty).
|
||||
*/
|
||||
void bopti_end_nover(const unsigned char *end, int size, struct Command *c)
|
||||
{
|
||||
uint32_t (*get)(const unsigned char **data) =
|
||||
(size == 2) ? bopti_end_get2 : bopti_end_get1;
|
||||
|
||||
// We *have* shift >= 0 because of this function's 'no overlap'
|
||||
// requirement.
|
||||
int shift = (32 - (size << 3)) - (c->x & 31);
|
||||
int vram_offset = (c->y << 2) + (c->x >> 5);
|
||||
uint32_t operator;
|
||||
int row;
|
||||
|
||||
// Skipping c->top lines (because get() function only allows sequential
|
||||
// access).
|
||||
end += c->top * size;
|
||||
|
||||
for(row = c->top; row < c->bottom; row++)
|
||||
{
|
||||
operator = (*get)(&end);
|
||||
operator <<= shift;
|
||||
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
void bopti_end(const unsigned char *end, int size, struct Command *c)
|
||||
{
|
||||
uint32_t (*get)(const unsigned char **data) =
|
||||
(size == 2) ? (bopti_end_get2) : (bopti_end_get1);
|
||||
|
||||
int vram_offset = (c->y << 2) + (c->x >> 5);
|
||||
uint32_t row_data, operator;
|
||||
int row;
|
||||
|
||||
int shift_base = (32 - (size << 3));
|
||||
int shift1 = (c->x & 31) - shift_base;
|
||||
int shift2 = shift_base + 32 - (c-> x & 31);
|
||||
|
||||
// Skipping c->top lines (because get() function only allows sequential
|
||||
// access).
|
||||
end += c->top * size;
|
||||
|
||||
for(row = c->top; row < c->bottom; row++)
|
||||
{
|
||||
row_data = (*get)(&end);
|
||||
|
||||
operator = row_data >> shift1;
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
|
||||
operator = row_data << shift2;
|
||||
(*c->op)(vram_offset + 1, operator, c);
|
||||
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Wrappers and various functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
bopti()
|
||||
Draws a layer in the video ram.
|
||||
*/
|
||||
void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
|
||||
{
|
||||
const unsigned char *grid, *end;
|
||||
int grid_columns, has_end;
|
||||
|
||||
// Skipping columns at the beginning.
|
||||
grid = layer + ((c->left * s->height) << 2);
|
||||
|
||||
// Updating the command arguments to eliminate some information about
|
||||
// parts that are not being drawn.
|
||||
c->x += (c->left << 5);
|
||||
c->y += c->top;
|
||||
|
||||
// Columns are identified by ids 0 to s->columns - 1, and the end has
|
||||
// id s->columns. So the end is drawn if this last column is included.
|
||||
has_end = (c->right == s->columns);
|
||||
// Computing number of grid columns to draw.
|
||||
grid_columns = c->right - c->left + 1 - has_end;
|
||||
|
||||
bopti_grid((const uint32_t *)grid, grid_columns, s->height, c);
|
||||
|
||||
if(has_end)
|
||||
{
|
||||
end = layer + ((s->columns * s->height) << 2);
|
||||
c->x += (grid_columns << 5);
|
||||
|
||||
if((c->x & 31) + s->end_size <= 32)
|
||||
bopti_end_nover(end, s->end_bytes, c);
|
||||
else
|
||||
bopti_end(end, s->end_bytes, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
getStructure()
|
||||
Determines the image size and data pointer.
|
||||
*/
|
||||
void getStructure(struct Image *img, struct Structure *s)
|
||||
{
|
||||
int column_count, end, end_bytes, layer;
|
||||
|
||||
// Large images.
|
||||
if(!img->width && !img->height)
|
||||
{
|
||||
s->width = (img->data[0] << 8) | img->data[1];
|
||||
s->height = (img->data[2] << 8) | img->data[3];
|
||||
s->data = img->data + 4;
|
||||
|
||||
column_count = (s->width + 31) >> 5;
|
||||
end = 0;
|
||||
end_bytes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->width = img->width;
|
||||
s->height = img->height;
|
||||
s->data = img->data;
|
||||
|
||||
column_count = img->width >> 5;
|
||||
end = img->width & 31;
|
||||
end_bytes =
|
||||
!end ? 0 :
|
||||
end <= 8 ? 1 :
|
||||
end <= 16 ? 2 :
|
||||
4;
|
||||
|
||||
if(end_bytes == 4)
|
||||
{
|
||||
column_count++;
|
||||
end = 0;
|
||||
end_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The layer size must be rounded to a multiple of 4.
|
||||
layer = s->height * ((column_count << 2) + end_bytes);
|
||||
if(layer & 3) layer += 4 - (layer & 3);
|
||||
|
||||
s->columns = column_count;
|
||||
s->end_bytes = end_bytes;
|
||||
s->end_size = end;
|
||||
s->layer_size = layer;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#include <internals/bopti.h>
|
||||
#include <internals/display.h>
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays a monochrome image in the video ram.
|
||||
*/
|
||||
void dimage(int x, int y, struct Image *img)
|
||||
{
|
||||
if(!img || img->magic != 0xb7) return;
|
||||
|
||||
struct Structure s;
|
||||
struct Command command;
|
||||
int actual_width;
|
||||
int format = img->format, i = 0;
|
||||
|
||||
if(format != Format_Mono && format != Format_MonoAlpha) return;
|
||||
getStructure(img, &s);
|
||||
|
||||
//---
|
||||
// Adjusting image parameters.
|
||||
//---
|
||||
|
||||
if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return;
|
||||
|
||||
command.top = (y < 0) ? (-y) : (0);
|
||||
command.bottom = (y + s.height > 64) ? (64 - y) : (s.height);
|
||||
command.left = ((x < 0) ? (-x) : (0)) >> 5;
|
||||
actual_width = (x + s.width > 128) ? (128 - x) : (s.width);
|
||||
command.right = ((actual_width + 31) >> 5) - 1;
|
||||
|
||||
command.op = bopti_op_mono;
|
||||
|
||||
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
||||
else getMasks(0, actual_width + x - 1, command.masks);
|
||||
|
||||
bopti_vram = display_getCurrentVRAM();
|
||||
|
||||
while(format)
|
||||
{
|
||||
// Drawing every layer, in order of formats.
|
||||
if(format & 1)
|
||||
{
|
||||
// These members are modified by bopti()!
|
||||
command.x = x;
|
||||
command.y = y;
|
||||
command.channel = (1 << i);
|
||||
|
||||
bopti(s.data, &s, &command);
|
||||
s.data += s.layer_size;
|
||||
}
|
||||
|
||||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#include <internals/bopti.h>
|
||||
#include <internals/display.h>
|
||||
|
||||
/*
|
||||
dimage_part()
|
||||
Draws a portion of an image, defined by its bounding rectangle.
|
||||
Point (left, top) is included, but (left + width, top + height) is
|
||||
excluded.
|
||||
*/
|
||||
void dimage_part(int x, int y, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
{
|
||||
if(!img || img->magic != 0xb7) return;
|
||||
|
||||
struct Structure s;
|
||||
struct Command command;
|
||||
int actual_width;
|
||||
int format = img->format, i = 0;
|
||||
|
||||
if(format != Format_Mono && format != Format_MonoAlpha) return;
|
||||
getStructure(img, &s);
|
||||
|
||||
//---
|
||||
// Adjusting the bounding rectangle.
|
||||
//---
|
||||
|
||||
// This is what happens when the bounding rectangle overflows from the
|
||||
// image...
|
||||
if(left < 0) left = 0;
|
||||
if(top < 0) top = 0;
|
||||
if(left + width > s.width) width = s.width - left;
|
||||
if(top + height > s.height) height = s.height - top;
|
||||
|
||||
if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
|
||||
return;
|
||||
|
||||
command.top = (y < 0) ? (top - y) : top;
|
||||
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
|
||||
command.left = ((x < 0) ? (left - x) : left) >> 5;
|
||||
actual_width = (x + width > 128) ? (128 - x) : width;
|
||||
command.right = ((left + actual_width + 31) >> 5) - 1;
|
||||
|
||||
command.op = bopti_op_mono;
|
||||
|
||||
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
||||
else getMasks(0, actual_width + x - 1, command.masks);
|
||||
|
||||
bopti_vram = display_getCurrentVRAM();
|
||||
|
||||
while(format)
|
||||
{
|
||||
if(format & 1)
|
||||
{
|
||||
command.x = x - left;
|
||||
command.y = y - top;
|
||||
command.channel = (1 << i);
|
||||
|
||||
bopti(s.data, &s, &command);
|
||||
s.data += s.layer_size;
|
||||
}
|
||||
|
||||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
}
|