GodMode9/resources/lua-doc.md
Tage Mellemstrand 584b68b7b1
Add support for reading and writing to I2C devices from lua (#934)
* Add i2c read support to lua

* Add i2c write support to lua

With memory permissions before write

* Adjust i2c write

* Fix inverted id check, better permissions

* Change write to not return anything on success

* Add some documentation for lua i2c

* Change write length from 1024 to 64

* Add whitelist for i2c writing

* Move i2c module into preload

* Add registers and bitmasks for mcu

Add documentation to lua-doc

* Fix missing column divider in lua-doc

* Add ~= 0 then to lua example

* Add some more registers
2026-03-25 23:18:03 +01:00

46 KiB
Raw Blame History

GodMode9 Lua documentation

GodMode9 includes a Lua 5.4.8 implementation.

Running scripts

There are four ways to run Lua scripts:

  • Select it in the file browser and choose "Execute Lua script"
  • Place it in 0:/gm9/luascripts, then open the HOME menu, choose "Lua scripts...", then choose the script
  • Place it in data/luascripts, then build GodMode9 from source
    • This takes precedence over 0:/gm9/luascripts
  • Place it at data/autorun.lua, then build GodMode9 from source with SCRIPT_RUNNER=1 to automatically run it at launch

Packages

Lua scripts can load custom modules. The default search path (defined as package.path) is:

0:/gm9/luapackages/?.lua;0:/gm9/luapackages/?/init.lua;V:/luapackages/?.lua;V:/luapackages/?/init.lua

For example, when a script calls require("foobar"), the package searcher will look for the module in this order:

  • 0:/gm9/luapackages/foobar.lua
  • 0:/gm9/luapackages/foobar/init.lua
  • V:/luapackages/foobar.lua
  • V:/luapackages/foobar/init.lua

Comparison with GM9Script

These tables are provided to assist with converting from GM9Script to Lua.

Commands

GM9 Lua Notes
goto http://lua-users.org/wiki/GotoStatement  
labelsel ui.ask_selection  
for fs.find_all Recursive searching does not work exactly the same, it will search for the filename in all directories
keychk ui.check_key  
echo ui.echo  
qr ui.show_qr  
ask ui.ask  
input ui.ask_input  
filesel fs.ask_select_file  
dirsel fs.ask_select_dir  
set local var = value More details on variables and scoping: https://www.lua.org/pil/4.2.html
strsplit string.find and string.sub  
strrep string.gsub https://www.lua.org/manual/5.4/manual.html#pdf-string.gsub
allow fs.allow  
cp fs.copy  
mv fs.move  
inject fs.write_file  
fill fs.fill_file  
fdummy fs.make_dummy_file  
rm fs.remove  
mkdir fs.mkdir  
mount fs.img_mount  
umount fs.img_umount  
find fs.find  
findnot fs.find_not  
fget fs.read_file  
fset fs.write_file  
sha fs.hash_file OR fs.verify_with_sha_file hash_file simply returns a hash, verify_with_sha_file compares it with a corresponding .sha file
shaget fs.hash_file  
dumptxt fs.write_file Use "end" for offset to append data
fixcmac fs.fix_cmacs  
verify fs.verify  
decrypt title.decrypt  
encrypt title.encrypt  
buildcia title.build_cia  
install title.install  
extrcode title.extract_code  
cmprcode title.compress_code  
sdump fs.key_dump  
applyips target.apply_ips  
applybps target.apply_bps  
applybpm target.apply_bpm  
textview fs.show_file_text_viewer fs.show_text_viewer can be used to show text from a variable
cartdump fs.cart_dump  
isdir fs.is_dir  
exist fs.exists  
boot sys.boot  
switchsd fs.sd_switch  
nextemu sys.next_emu  
reboot sys.reboot  
poweroff sys.power_off  
bkpt bkpt  

PREVIEW_MODE variable

Unlike the PREVIEW_MODE GM9Script variable, this has been split into multiple functions.

Setting Lua
“quick" and “full" (There is no alternative to view a Lua script as its running.)
“off" ui.clear
text ui.show_text
png file ui.show_png
game icon ui.show_game_info

Other constants

GM9 Lua Notes
DATESTAMP util.get_datestamp() Formatted like “241202", equivalent to os.date("%y%m%d")
TIMESTAMP util.get_timestamp() Formatted like “010828", equivalent to os.date("%H%M%S")
SYSID0 sys.sys_id0  
EMUID0 sys.emu_id0  
EMUBASE sys.emu_base  
SERIAL sys.serial  
REGION sys.region  
SDSIZE fs.stat_fs("0:/").total int instead of string (use ui.format_bytes to format it)
SDFREE fs.stat_fs("0:/").free int instead of string (use ui.format_bytes to format it)
NANDSIZE NANDSIZE int instead of string (use ui.format_bytes to format it)
GM9OUT GM9OUT  
CURRDIR CURRDIR nil instead of “(null)" if it cant be found
ONTYPE CONSOLE_TYPE “O3DS" or “N3DS"
RDTYPE IS_DEVKIT boolean instead of a string
HAX HAX  
GM9VER GM9VER  
GYROMODEL GYROMODEL int instead of string

Comparisons with standard Lua

These original Lua 5.4 modules are fully available:

These modules are partially available:

  • os
    • Only os.clock, os.time, os.date, os.difftime, and os.remove
  • io
    • Only io.open; for open files, all but file:setvbuf and file:lines
    • This is a custom compatibility module that uses fs functions. If there are differences compared to the original io implementation, please report them as issues.

These modules work differently:

  • package
    • package.cpath and package.loadlib are nonfunctional due to GM9 having no ability to load dynamic libraries.

Third-party libraries

rxi's json.lua is pre-included. To use it, first load it:

local json = require("json")

API reference

Constants

GM9VER

The version such as "v2.1.1-159-gff2cb913", the same string that is shown on the main screen.

GYROMODEL

The type of Gyro sensor present

  • 1: ITG-3270, used in O3DS and some O2DS
  • 2: ITG-1010, used in late model O2DS and N3DS
  • 3: Unknown name, used in late model N3DS
  • nil: Unknown model

SCRIPT

Path to the executed script, such as "0:/gm9/luascripts/myscript.lua".

CURRDIR

Directory of the executed script, such as "0:/gm9/luascripts".

GM9OUT

The value "0:/gm9/out".

HAX

Warning

This needs checking if it's accurate. One of three values:

  • "ntrboot" if started from an ntrboot cart
  • "sighax" if booted directly from a FIRM partition
  • Empty string otherwise

NANDSIZE

Total size of SysNAND in bytes.

CONSOLE_TYPE

The string "O3DS" or "N3DS".

IS_DEVKIT

true if the console is a developer unit.


ui module

Note

This assumes the default build is used, where the bottom screen is the main screen. If GodMode9 is compiled with SWITCH_SCREENS=1, then every instance where something appears on the bottom screen will actually be on the top screen and vice versa.

ui.echo

  • void ui.echo(string text)

Display text on the bottom screen and wait for the user to press A.

  • Arguments
    • text - Text to show the user

ui.ask

  • bool ui.ask(string text)

Prompt the user with a yes/no question.

  • Arguments
    • text - Text to ask the user
  • Returns: true if the user accepts

ui.ask_hex

  • int ui.ask_hex(string text, int initial, int n_digits)

Ask the user to input a hex number.

  • Arguments
    • text - Text to ask the user
    • initial - Starting value
    • n_digits - Amount of hex digits allowed
  • Returns: the number the user entered, or nil if canceled

ui.ask_number

  • int ui.ask_number(string text, int initial)

Ask the user to input a number.

  • Arguments
    • text - Text to ask the user
    • initial - Starting value
  • Returns: the number the user entered, or nil if canceled

ui.ask_text

  • string ui.ask_text(string prompt, string initial, int max_length)

Ask the user to input text.

  • Arguments
    • prompt - Text to ask the user
    • initial - Starting value
    • max_length - Maximum length of the string
  • Returns: the text the user entered, or nil if canceled

ui.ask_selection

  • int ui.ask_selection(string prompt, table options)

Ask the user to choose an option from a list. A maximum of 256 options are allowed.

  • Arguments
    • prompt - Text to ask the user
    • options - Table of options
  • Returns: index of selected option, or nil if canceled

ui.clear

  • void ui.clear()

Clears the top screen.

ui.show_png

  • void ui.show_png(string path)

Displays a PNG file on the top screen.

The image must not be larger than 400 pixels horizontal or 240 pixels vertical. If SWITCH_SCREENS=1 is used, it must not be larger than 320 pixels horizontal.

  • Arguments
    • path - Path to PNG file
  • Throws
    • "Could not read (file)" - file does not exist or there was another read error
    • "Invalid PNG file" - file is not a valid PNG
    • "PNG too large" - too large horizontal or vertical, or an out-of-memory error

ui.show_text

  • void ui.show_text(string text)

Displays text on the top screen.

  • Arguments
    • text - Text to show the user

ui.show_game_info

  • void ui.show_game_info(string path)

Shows game file info. Accepts any files that include an SMDH, a DS game file, or GBA file.

  • Arguments
    • path - Path to game file (CIA, CCI/".3ds", SMDH, TMD, TIE (DSiWare export), Ticket, NDS, GBA)
  • Throws
    • "ShowGameFileIcon failed on <path>" - failed to get game info from path

ui.show_qr

  • void ui.show_qr(string text, string data)

Displays a QR code on the top screen, and a prompt on the bottom screen, and waits for the user to press A.

  • Arguments
    • text - Text to show the user
    • data - Data to encode into the QR code
  • Throws
    • "could not allocate memory" - out-of-memory error when attempting to generate the QR code

ui.show_text_viewer

  • void ui.show_text_viewer(string text)

Display a scrollable text viewer.

  • Arguments
    • text - Text to display
  • Throws
    • "text validation failed" - given string contains invalid characters
    • "failed to run MemTextViewer" - internal memory viewer error

ui.show_file_text_viewer

  • void ui.show_file_text_viewer(string path)

Display a scrollable text viewer from a text file.

  • Arguments
    • path - Path to text file
  • Throws
    • "could not allocate memory" - out-of-memory error when attempting to create the text buffer
    • "text validation failed" - text file contains invalid characters
    • "failed to run MemTextViewer" - internal memory viewer error

ui.format_bytes

  • string ui.format_bytes(int bytes[, table opts {bool use_locale}])

Format a number with Byte, kB, MB, or GB. By default this will always use English style formatting. Enable use_locale to format in the user's selected language.

  • Arguments
    • bytes - Size to format
    • opts (optional) - Option flags
      • use_locale - Format in the user's selected locale
  • Returns: formatted string

ui.check_key

  • bool ui.check_key(string key)

Checks if the user is holding down a key.

  • Arguments
    • key - A button string: "A", "B", "SELECT", "START", "RIGHT", "LEFT", "UP", "DOWN", "R", "L", "X", "Y"
  • Returns: true if currently held, false if not

fs module

fs.move

  • void fs.move(string src, string dst[, table opts {bool no_cancel, bool silent, bool overwrite, bool skip_all}])

Moves or renames a file or directory.

  • Arguments
    • src - Item to move
    • dst - Destination name
    • opts (optional) - Option flags
      • no_cancel - Dont allow user to cancel
      • silent - Dont show progress
      • overwrite - Overwrite files
      • skip_all - Skip existing files
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "destination already exists on <src> -> <dst> and {overwrite=true} was not used" - attempted to move an item over an existing one without using overwrite
    • "PathMoveCopy failed on <src> -> <dst>" - error when moving, or user canceled

fs.remove

  • void fs.remove(string path[, table opts {bool recursive}])

Delete a file or directory.

  • Arguments
    • path - Path to delete
    • opts (optional) - Option flags
      • recursive - Remove directories recursively
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "requested directory remove without {recursive=true} on <path>" - attempted to delete a directory without using recursive
    • "PathDelete failed on %s" - error when deleting

fs.copy

  • void fs.copy(string src, string dst[, table opts {bool calc_sha, bool sha1, bool no_cancel, bool silent, bool overwrite, bool skip_all, bool append, bool recursive}])

Copy a file or directory.

  • Arguments
    • src - Item to copy
    • dst - Destination name
    • opts (optional) - Option flags
      • calc_sha - Write .sha files containing a SHA-256 (default) or SHA-1 hash
      • sha1 - Use SHA-1
      • no_cancel - Dont allow user to cancel
      • silent - Dont show progress
      • overwrite - Overwrite files
      • skip_all - Skip existing files
      • append - Append to the end of existing files instead of overwriting
      • recursive - Copy directories recursively
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "requested directory copy without {recursive=true} on <src> -> <dst>" - attempted to copy a directory without using recursive
    • "destination already exists on <src> -> <dst> and {overwrite=true} was not used" - attempted to copy an item over an existing one without using overwrite
    • "PathMoveCopy failed on <src> -> <dst>" - error when copying, or user canceled

fs.mkdir

  • void fs.mkdir(string path)

Create a directory. This creates intermediate directories as required, so fs.mkdir("a/b/c") would create a, then b, then c.

  • Arguments
    • path - Directory to create
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "could not mkdir (<path>)" - error when creating directories

fs.stat

  • table fs.stat(string path)

Get information about a file or directory. The result is a stat table with these keys:

  • Arguments
    • path - Directory to stat
  • Returns: A stat table with keys:
    • name (string)
    • type (string) - "dir" or "file"
    • size (number)
    • read_only (bool)
  • Throws
    • "could not stat <path> (##)" - error when attempting to stat item, with FatFs error number

fs.list_dir

  • table fs.list_dir(string path)

Get the contents of a directory. The result is a list of stat tables with these keys:

  • name (string)

  • type (string) - "dir" or "file"

  • size (number)

  • read_only (bool)

  • Arguments

    • path - Directory to list
  • Returns: A list of stat tables, each with keys:

    • name (string)
    • type (string) - "dir" or "file"
    • size (number)
    • read_only (bool)
  • Throws

    • "could not opendir <path> (##)" - error when attempting to open directory, with FatFs error number
    • "could not readdir <path> (##)" - error when attempting to read directory, with FatFs error number

fs.stat_fs

  • table fs.stat_fs(string path)

Get information about a filesystem.

Note

This function can take several seconds before it returns an answer.

  • Arguments
    • path - Filesystem to stat
  • Returns: A stat table with keys:
    • free (number)
    • total (number)
    • used (number)

fs.dir_info

  • table fs.dir_info(string path)

Get information about a directory.

Note

This function can take several seconds before it returns an answer.

  • Arguments
    • path - Directory to check
  • Returns: An info table with keys:
    • size (number)
    • dirs (number)
    • files (number)
  • Throws
    • "error when running DirInfo" - error when scanning directory

fs.ask_select_file

  • string fs.ask_select_file(string prompt, string path[, bool opts {bool include_dirs, bool explorer}])

Prompt the user to select a file based on a pattern. Accepts a wildcard pattern like "0:/gm9/in/*_ctrtransfer_n3ds.bin".

  • Arguments
    • prompt - Text to ask the user
    • path - Wildcard pattern to search for
    • opts (optional) - Option flags
      • include_dirs - Include directories in selection
      • explorer - Use file explorer, including navigating subdirectories
  • Returns: path selected, or nil if user canceled
  • Throws
    • "forbidden drive" - attempted search on Z:
    • "invalid path" - could not find / in path

fs.ask_select_dir

  • string fs.ask_select_dir(string prompt, string path[, bool opts {bool explorer}])

Prompt the user to select a directory.

  • Arguments
    • prompt - Text to ask the user
    • path - Directory to search
    • opts (optional) - Option flags
      • explorer - Use file explorer, including navigating subdirectories
  • Returns: path selected, or nil if user canceled
  • Throws
    • "forbidden drive" - attempted search on Z:

fs.find

  • string fs.find(string pattern[, bool opts {bool first}])

Searches for a file based on a wildcard pattern. Returns the last result, unless first is specified, or nil if nothing was found.

Pattern can use ? for search values, for example 00017?02 will match 00017002, 00017102, etc. Wildcards are also accepted.

  • Arguments
    • pattern - Pattern to search for
    • opts (optional) - Option flags
      • first - Return first result instead of last
  • Returns: found file, or nil if nothing is found
  • Throws
    • "failed to find <path> (##)" - error when attempting to find path, with FatFs error number

fs.find_not

  • string fs.find(string pattern)

Searches for a free filename based on a pattern.

Pattern can use ? for search values, for example nand_??.bin will check to see if nand_00.bin exists. If it doesn't, it returns this string. Otherwise, it checks if nand_01.bin exists and keeps going until an unused filename can be found.

  • Arguments
    • pattern - Pattern to search for
  • Returns: found file
  • Throws
    • "failed to find <path> (##)" - error when attempting to find path, with FatFs error number

fs.find_all

  • table fs.find_all(string dir, string pattern[, table opts {bool recursive}])

Search for all files that match a pattern.

  • Arguments
    • dir - Directory to search
    • pattern - Filename pattern
    • opts (optional) - Option flags
      • recursive - Remove directories recursively
  • Returns: table of found files
  • Throws
    • "could not open directory" - failed to open directory

fs.allow

  • bool fs.allow(string path[, table flags {bool ask_all}])

Check for and request permission to write to a sensitive path.

  • Arguments
    • path - Path to request permission for
    • opts (optional) - Option flags
      • ask_all - Request to write to all files in directory
  • Returns: true if granted, false if user declines

fs.img_mount

  • void fs.img_mount(string path)

Mount an image file. Can be anything mountable through the file browser.

  • Arguments
    • path - Path to image file
  • Throws
    • "failed to mount <path>" - not a valid image file

fs.img_umount

  • void fs.img_umount()

Unmount the currently mounted image file.

fs.get_img_mount

  • string fs.get_img_mount()

Get the currently mounted image file.

  • Returns: path to file, or nil if none is mounted

fs.hash_file

  • string fs.hash_file(string path, int offset, int size[, table opts {bool sha1}])

Calculate the hash for a file. Uses SHA-256 unless sha1 is specified. To hash an entire file, size should be 0.

Tip

  • Use fs.verify_with_sha_file to compare with a corresponding .sha file.
  • Use util.bytes_to_hex to convert the result to printable hex characters.

Note

Using an offset that is not 0, with a size of 0 (to hash to end of file), is currently undefined behavior. In the future this should work properly.

  • Arguments
    • path - File to hash
    • offset - Data offset
    • size - Amount of data to hash, or 0 to hash to end of file
    • opts (optional) - Option flags
      • sha1 - Use SHA-1
  • Returns: SHA-256 or SHA-1 hash as byte string
  • Throws
    • "failed to stat <path>" - could not stat file to get size
    • "FileGetSha failed on <path>" - could not read file or user canceled

fs.hash_data

  • string fs.hash_data(string data[, table opts {bool sha1}])

Calculate the hash for some data. Uses SHA-256 unless sha1 is specified.

Tip

  • Use util.bytes_to_hex to convert the result to printable hex characters.
  • Arguments
    • data - Data to hash
    • opts (optional) - Option flags
      • sha1 - Use SHA-1
  • Returns: SHA-256 or SHA-1 hash as byte string

fs.verify

  • bool fs.verify(string path[, table opts {bool sig_check}])

Verify the integrity of a file.

Note

This is for files that have their own hashes built-in. For verifying against a corresponding .sha file, use fs.verify_with_sha_file.

  • Arguments
    • path - File to verify
    • opts (optional) - Option flags
      • sig_check - Verify NCSD/NCCH signature
  • Returns: true if successful, false if failed or not verifiable

fs.verify_with_sha_file

  • bool fs.verify_with_sha_file(string path)

Calculate the hash of a file and compare it with a corresponding .sha file.

Important

This currently assumes SHA-256. In the future this may automatically use SHA-1 when appropriate, based on the .sha file size.

  • Argumens
    • path - File to hash
  • Returns: true if successful, false if failed, nil if .sha file could not be read
  • Throws
    • "failed to stat <path>" - could not stat file to get size
    • "FileGetSha failed on <path>" - could not read file or user canceled

fs.exists

  • bool fs.exists(string path)

Check if an item exists.

  • Arguments
    • path - Path to file or directory
  • Returns: true if exists, false otherwise

fs.is_dir

  • bool fs.is_dir(string path)

Check if an item exists, and is a directory.

  • Arguments
    • path - Path to directory
  • Returns: true if exists and is a directory, false otherwise

fs.is_file

  • bool fs.is_file(string path)

Check if an item exists, and is a file.

  • Arguments
    • path - Path to file
  • Returns: true if exists and is a file, false otherwise

fs.sd_is_mounted

  • bool fs.sd_is_mounted()

Check if the SD card is mounted.

  • Returns: true if SD card is mounted

fs.sd_switch

  • void fs.sd_switch([string message])

Prompt the user to remove and insert an SD card.

  • Arguments
    • message (optional) - Text to prompt the user, defaults to "Please switch the SD card now."
  • Throws
    • "user canceled" - user canceled the switch

fs.fix_cmacs

  • void fs.fix_cmacs(string path)

Fix CMACs for a directory.

  • Arguments
    • path - Path to recursively fix CMACs for
  • Throws
    • fixcmac failed - user denied permission, or fixing failed

fs.read_file

  • string fs.read_file(string path, int offset, int/string size)

Read data from a file.

  • Arguments
    • path - File to read
    • offset - Data offset
    • size - Amount of data to read
  • Returns: string of data
  • Throws
    • "could not allocate memory to read file" - out-of-memory error when attempting to create the data buffer
    • "could not read <path> (##)" - error when attempting to read file, with FatFs error number

fs.write_file

  • int fs.write_file(string path, int offset, string data)

Write data to a file.

  • Arguments
    • path - File to write
    • offset - Offset to write to, or the string "end" to write at the end of file
    • data - Data to write
  • Returns: amount of bytes written
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "error writing <path> (##)" - error when attempting to write file, with FatFs error number

fs.fill_file

  • void fs.fill_file(string path, int offset, int size, int byte)

Fill a file with a specified byte.

  • Arguments
    • path - File to write
    • offset - Offset to write to
    • size - Amount of data to write
    • byte - Number between 0x00 and 0xFF (0 and 255) indicating the byte to write
    • opts (optional) - Option flags
      • no_cancel - Dont allow user to cancel
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "byte is not between 0x00 and 0xFF (got: ##)" - byte value is not a single byte
    • "FileSetByte failed on <path>" - writing failed or user canceled

fs.make_dummy_file

  • void fs.make_dummy_file(string path, int size)

Create a dummy file.

Note

The file will contain data from the unused parts of the filesystem. If you need to ensure it's clean, use fs.fill_file.

  • Arguments
    • path - File to create
    • size - File size to set
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "FileCreateDummy failed on <path>" - dummy creation failed

fs.truncate

  • void fs.truncate(string path, int size)

Truncate a file to a specific size.

Important

Does not work for virtual filesystems.

  • Arguments
    • path - File to create
    • size - File size to set
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "failed to open <path> (note: this only works on FAT filesystems, not virtual)" - opening file failed, or a virtual filesystem was used
    • "failed to seek on <path>" - seeking file failed
    • "failed to truncate on <path>" - truncating file failed

fs.key_dump

  • void fs.key_dump(string file[, table opts {bool overwrite}])

Dumps title keys or seeds. Taken from both SysNAND and EmuNAND. The resulting file is saved to 0:/gm9/out.

  • Arguments
    • file - One of three supported filenames: seeddb.bin, encTitleKeys.bin, decTitleKeys.bin
    • opts (optional) - Option flags
      • overwrite - Overwrite files
  • Throws
    • "building <file> failed" - building failed or file already exists and overwrite was not used

fs.cart_dump

  • void fs.cart_dump(string path, int size[, table opts {bool encrypted}])

Dump the raw data from the inserted game card. No modifications are made to the data. This means for example, Card2 games will not have the save area cleared.

  • Arguments
    • path - File to write data to
    • size - Amount of data to read
    • opts (optional) - Option flags
      • encrypted - Dump game encrypted, only for DS/DSi games?
  • Throws
    • "out of memory" - out-of-memory error when attempting to create the data buffer
    • "cart init fail" - card is not inserted or some other failure when attempting to initialize
    • "cart dump failed or canceled" - cart read failed or used canceled

title module

title.decrypt, title.encrypt

  • void title.decrypt(string path)
  • void title.decrypt(string path)

Decrypt or encrypt a title or key database, done in-place.

  • Arguments
    • path - Path to title or key database
  • Throws
    • "CryptAesKeyDb failed on <path>" - could not crypt key database
    • "CryptGameFile failed on <path>" - could not crypt title

title.install

  • void title.install(string path[, table opts {bool to_emunand}])

Install a title.

  • Arguments
    • path - File to install
    • opts (optional) - Option flags
      • to_emunand - Install to EmuNAND
  • Throws
    • "InstallGameFile failed on <path>" - install failed or user canceled

title.build_cia

  • void title.build_cia(string path[, table opts {bool legit}])

Build title as a CIA. Resulting file is put in 0:/gm9/out.

  • Arguments
    • path - File to build as CIA
    • opts (optional) - Option flags
      • legit - Build as legit CIA if possible
  • Throws
    • "BuildCiaFromGameFile failed on <path>" - build failed or user canceled

title.extract_code

  • void title.extract_code(string src, string dst)

Extracts the .code from a title and decompresses it.

  • Arguments
    • src - File containing .code
    • dst - Destination to write decompressed .code
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "<path> does not have code" - invalid file type
    • "failed to extract code from <path>" - extraction failed

title.compress_code

  • void title.compress_code(string src, string dst)

Compress a .code file.

  • Arguments
    • src - Extracted .code, like from title.extract_code
    • dst - Destination to write compressed .code
  • Throws
    • "writing not allowed: <path>" - user denied permission
    • "failed to compress code from <path>" - compression failed

title.apply_ips, title.apply_bps, title.apply_bpm

  • void title.apply_ips(string patch, string src, string target)
  • void title.apply_bps(string patch, string src, string target)
  • void title.apply_bpm(string patch, string src, string target)

Apply an IPS, BPS, or BPM patch.

  • Arguments
    • patch - IPS, BPS, or BPM patch file
    • src - File to patch
    • target - Destination to write patched file to
  • Throws
    • "ApplyIPSPatch failed" - failed to apply IPS patch
    • "ApplyBPSPatch failed" - failed to apply BPS patch
    • "ApplyBPMPatch failed" - failed to apply BPM patch

sys module

sys.boot

  • void sys.boot(string path)

Boot a FIRM file.

  • Arguments
    • path - FIRM file
  • Throws
    • "out of memory" - out-of-memory error when attempting to create the data buffer
    • "not a bootable firm" - file cannot be booted

sys.reboot

  • void sys.reboot()

Reboots the console.

sys.power_off

  • void sys.power_off()

Powers off the console.

sys.region

  • string sys.region

System region, based on SysNAND's SecureInfo_[AB] file. Not affected by SecureInfo_C.

Possible values: "JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN", nil (if it does not exist, or the region byte is invalid)

sys.serial

  • string sys.serial

Serial number, based on SysNAND's SecureInfo_[AB] file. Not affected by SecureInfo_C.

Can be nil if the file does not exist.

sys.secureinfo_letter

  • string sys.secureinfo_letter

The letter at the end of the console's SecureInfo_[AB] file.

Possible values: "A", "B", nil (if it does not exist)

sys.sys_id0

  • string sys.sys_id0

ID0 of SysNAND as a printable hex string.

Can be nil if the file does not exist.

sys.emu_id0

  • string sys.emu_id0

ID0 of EmuNAND as a printable hex string.

Can be nil if the file does not exist.

sys.emu_base

  • int sys.emu_base

Current EmuNAND base.

sys.refresh_info

  • void sys.refresh_info()

Refresh the following variables:

  • sys.region
  • sys.serial
  • sys.secureinfo_letter
  • sys.sys_id0
  • sys.emu_id0
  • sys.emu_base

This function is automatically called at the beginning of Lua's execution, but errors are caught to prevent a premature exit. This could leave some of the variables at nil.

  • Throws
    • "could not read SecureInfo" - SecureInfo_[AB] is missing
    • "SecureInfo region byte is invalid" - SecureInfo_[AB] is not between 0 and 6 inclusive

sys.next_emu

  • void sys.next_emu()

Switch to the next available EmuNAND.

This will automatically call sys.refresh_info.

sys.check_embedded_backup

  • bool sys.check_embedded_backup()

Check if essential.exefs is embedded into SysNAND, and prompts the user if it isn't. This is the same as the check that is done at boot for GodMode9, but this can be called in a build compiled with SCRIPT_RUNNER=1 for autorun scripts that require essential.exefs to exist.

  • Returns: true if it exists or was created, false if user declines, nil if console fails genuine NCSD check (modified partition table)

sys.check_raw_rtc

  • bool sys.check_raw_rtc()

Check if the Raw RTC is set correctly, and prompts the user if it isn't. This is the same as the check that is done at boot for GodMode9, but this can be called in a build compiled with SCRIPT_RUNNER=1 for autorun scripts that require essential.exefs to exist.

  • Returns: true if set, false if user declines

util module

util.bytes_to_hex

  • string util.bytes_to_hex(string data)

Convert a byte string to printable hex characters.

Example: "test\xaa\xbb\xcc\xdd" -> "74657374aabbccdd"

  • Arguments
    • data - Data to convert
  • Returns: Hex characters

util.hex_to_bytes

  • string util.hex_to_bytes(string hexstring)

Convert hex characters to a byte string.

Example: "74657374aabbccdd" -> "test\xaa\xbb\xcc\xdd"

  • Arguments
    • hexstring - Hex characters to convert
  • Returns: Byte string
  • Throws
    • "bad argument #1 to 'char' (number expected, got nil)" - invalid hex characters

util.get_datestamp

  • string util.get_datestamp()

Returns a date stamp formatted like "241202" for 2024 December 02. Equivalent to os.date("%y%m%d").

  • Returns: Date stamp

util.get_timestamp

  • string util.get_timestamp()

Returns a date stamp formatted like "010828" for 01:08:28. Equivalent to os.date("%H%M%S").

  • Returns: Time stamp

util.running_as_module

  • bool util.running_as_module()

Determines if the currently executing script was directly run, or was imported by another script. Useful for scripts that want to be usable directly, while also importable.

Note

This is not well tested.

  • Returns: true if the current script was imported as a module

i2c module

i2c.dev

A list of devices for use with i2c.read and i2c.write

Lua Value
POWER 0
POWER 1
CAMERA2 2
MCU 3
CAMERA3 4
LCD1 5
LCD2 6
GYRO3 9
GYRO 10
GYRO2 11
DEBUG_PAD 12
IR 13
EEPROM 14
NFC 15
QTM 16
N3DS_HID 17

i2c.mcu

i2c.mcu contains registers and bitmasks for registers

i2c.mcu.reg

Contains some registers in the MCU

Lua Value Notes
VERSION_HIGH 0x0 Major version of the MCU firmware.
VERSION_LOW 0x1 Minor version of the MCU firmware.
RESET_EVENTS 0x2 @ref mcu.reset_event_flags
VCOM_TOP 0x3 Flicker/VCOM value for the top screen.
VCOM_BOTTOM 0x4 Flicker/VCOM value for the bottom screen.
FIRMWARE_UPLOAD_0 0x5 Firmware upload register.
FIRMWARE_UPLOAD_1 0x6 Firmware upload register.
FIRMWARE_UPLOAD_2 0x7 Firmware upload register.
RAW_3D_SLIDER_POSITION 0x8 Position of the 3D slider.
VOLUME_SLIDER_POSITION 0x9 Position of the volume slider.
BATTERY_PCB_TEMPERATURE 0xA Temperature of the battery, measured on a sensor on the PCB.
BATTERY_PERCENTAGE_INT 0xB Integer part of the battery percentage.
BATTERY_PERCENTAGE_FRAC 0xC Fractional part of the battery percentage.
BATTERY_VOLTAGE 0xD Voltage of the battery, in units of 20 mV.
HW_STATUS 0xE Hardware status bits
POWER_STATUS 0xF @ref mcu.power_status_flags
LEGACY_VERSION_HIGH 0xF (Old MCU_FIRM only) Major firmware version.
LEGACY_VERSION_LOW 0x10 (Old MCU_FIRM only) Minor firmware version.
LEGACY_FIRM_UPLOAD 0x3B (Old MCU_FIRM only) Firmware upload register.
RECEIVED_IRQS_1 0x10 Bitmask of received IRQs. @ref mcu.interrupt_1
RECEIVED_IRQS_2 0x11 Bitmask of received IRQs. @ref mcu.interrupt_2
RECEIVED_IRQS_3 0x12 Bitmask of received IRQs. @ref mcu.interrupt_3
RECEIVED_IRQS_4 0x13 Bitmask of received IRQs. @ref mcu.interrupt_4
UNUSED_RO_14 0x14 Unused read-only register.
USERDATA_RAM_15 0x15 Unused register, supports writing
USERDATA_RAM_16 0x16 Unused register, supports writing
USERDATA_RAM_17 0x17 Unused register, supports writing
IRQ_MASK_1 0x18 Bitmask of enabled IRQs. @ref mcu.interrupt_1
IRQ_MASK_2 0x19 Bitmask of enabled IRQs. @ref mcu.interrupt_2
IRQ_MASK_3 0x1A Bitmask of enabled IRQs. @ref mcu.interrupt_3
IRQ_MASK_4 0x1B Bitmask of enabled IRQs. @ref mcu.interrupt_4
USERDATA_RAM_1C 0x1C Unused register, supports writing
USERDATA_RAM_1D 0x1D Unused register, supports writing
USERDATA_RAM_1E 0x1E Unused register, supports writing
USERDATA_RAM_1F 0x1F Unused register, supports writing
PWR_CTL 0x20 @ref mcu.power_trigger
LCD_PWR_CTL 0x22 LCD Power control
MCU_RESET_CTL 0x23 Writing 'r' to this register resets the MCU. Stubbed on retail.
FORCE_SHUTDOWN_DELAY 0x24 The amount of time, in units of 0.125s, for which the power button needs to be held to trigger a hard shutdown.
VOLUME_UNK_25 0x25 Unknown register. Used in mcu::SND
UNK_26 0x26 Unknown register. Used in mcu::CDC
VOLUME_SLIDER_RAW 0x27 Raw value of the volume slider, in the range of 0-255
LED_BRIGHTNESS_STATE 0x28 Brightness of the status LEDs.
POWER_LED_STATE 0x29 @ref mcu.power_led_state
WLAN_LED_STATE 0x2A Controls the WiFi LED.
CAMERA_LED_STATE 0x2B Controls the camera LED (on models that have one).
LED_3D_STATE 0x2C Controls the 3D LED (on models that have one).
NOTIFICATION_LED_STATE 0x2D Controls the info (notification) LED.
NOTIFICATION_LED_CYCLE_STATE 0x2E Bit 0 is set if the info (notification) LED has started a new cycle of its pattern.
RTC_TIME_SECOND 0x30 RTC second.
RTC_TIME_MINUTE 0x31 RTC minute.
RTC_TIME_HOUR 0x32 RTC hour.
RTC_TIME_WEEKDAY 0x33 RTC day of the week.
RTC_TIME_DAY 0x34 RTC day of the month.
RTC_TIME_MONTH 0x35 RTC month.
RTC_TIME_YEAR 0x36 RTC year.
RTC_TIME_CORRECTION 0x37 RTC subsecond (RSUBC) correction value.
RTC_ALARM_MINUTE 0x38 RTC alarm minute.
RTC_ALARM_HOUR 0x39 RTC alarm hour.
RTC_ALARM_DAY 0x3A RTC alarm day.
RTC_ALARM_MONTH 0x3B RTC alarm month.
RTC_ALARM_YEAR 0x3C RTC alarm year.
TICK_COUNTER_LSB 0x3D MCU tick counter value (low byte).
TICK_COUNTER_MSB 0x3E MCU tick counter value (high byte).
UNK_3F 0x3F Unknown register
SENSOR_CONFIG 0x40 @ref mcu.sensor_config
ACCELEROMETER_MANUAL_REGID_R 0x41 Hardware register ID for use in manual accelerometer I²C reads.
ACCELEROMETER_MANUAL_REGID_W 0x43 Hardware reigster ID for use in manual accelerometer I²C writes.
ACCELEROMETER_MANUAL_IO 0x44 Data register for manual accelerometer reads/writes.
ACCELEROMETER_OUTPUT_X_LSB 0x45 Accelerometer X coordinate (low byte).
ACCELEROMETER_OUTPUT_X_MSB 0x46 Accelerometer X coordinate (high byte).
ACCELEROMETER_OUTPUT_Y_LSB 0x47 Accelerometer Y coordinate (low byte).
ACCELEROMETER_OUTPUT_Y_MSB 0x48 Accelerometer Y coordinate (high byte).
ACCELEROMETER_OUTPUT_Z_LSB 0x49 Accelerometer Z coordinate (low byte).
ACCELEROMETER_OUTPUT_Z_MSB 0x4A Accelerometer Z coordinate (high byte).
PEDOMETER_STEPS_LOWBYTE 0x4B Pedometer step count (low byte).
PEDOMETER_STEPS_MIDDLEBYTE 0x4C Pedometer step count (middle byte).
PEDOMETER_STEPS_HIGHBYTE 0x4D Pedometer step count (high byte).
PEDOMETER_CNT 0x4E @ref mcu.pedometer_control
PEDOMETER_STEP_DATA 0x4F Step history and time of last update.
PEDOMETER_WRAP_MINUTE 0x50 The minute within each RTC hour at which the step history should roll into the next hour.
PEDOMETER_WRAP_SECOND 0x51 The second within each RTC hour at which the step history should roll into the next hour.
VOLUME_CALIBRATION_MIN 0x58 Lower bound of sound volume.
VOLUME_CALIBRATION_MAX 0x59 Upper bound of sound volume.
STORAGE_AREA_OFFSET 0x60 Offset within the storage area to read/write to.
STORAGE_AREA 0x61 Input/output byte for write/read operations in the storage area.
INFO 0x7F System information register.
i2c.mcu.interrupt_1

Bitmask for interrupts (1)

Lua Bit Notes
POWER_BUTTON_PRESS 0 The power button was pressed
POWER_BUTTON_HELD 1 The power button was held
HOME_BUTTON_PRESS 2 The HOME button was pressed
HOME_BUTTON_RELEASE 3 The HOME button was released
WLAN_SWITCH_TRIGGER 4 The WiFi switch was triggered
SHELL_CLOSE 5 The shell was closed (or sleep switch turned off)
SHELL_OPEN 6 The shell was opened (or sleep switch turned on)
FATAL_HW_ERROR 7 MCU watchdog reset occurred
i2c.mcu.interrupt_2

Bitmask for interrupts (2)

Lua Bit Notes
AC_ADAPTER_REMOVED 0 The AC adapter was disconnected
AC_ADAPTER_PLUGGED_IN 1 The AC adapter was connected
RTC_ALARM 2 The RTC alarm time has been reached
ACCELEROMETER_I2C_MANUAL_IO 3 The manual accelerometer I²C read/write operation has completed
ACCELEROMETER_NEW_SAMPLE 4 A new accelerometer sample is available
CRITICAL_BATTERY 5 The battery is critically low
CHARGING_STOP 6 The battery stopped charging
CHARGING_START 7 The battery started charging
i2c.mcu.interrupt_3

Bitmask for interrupts (3)

Lua Bit Notes
VOL_SLIDER 6 The position of the volume slider changed
i2c.mcu.interrupt_4

Bitmask for interrupts (4)

Lua Bit Notes
LCD_OFF 0 The LCDs turned off.
LCD_ON 1 The LCDs turned on.
BOT_BACKLIGHT_OFF 2 The bottom screen backlight turned off.
BOT_BACKLIGHT_ON 3 The bottom screen backlight turned on.
TOP_BACKLIGHT_OFF 4 The top screen backlight turned off.
TOP_BACKLIGHT_ON 5 The top screen backlight turned on.
i2c.mcu.reset_event_flags

Bitmasks for the reset event flags

Lua Bit Notes
RTC_TIME_LOST 0 RTC time was lost (as is the case when the battery is removed).
WATCHDOG_RESET 1 MCU Watchdog reset occurred.
i2c.mcu.power_status_flags

Bitmasks for the power status

Lua Bit Notes
SHELL_OPEN 1 Set if the shell is open.
ADAPTER_CONNECTED 3 Set if the AC adapter is connected.
CHARGING 4 Set if the battery is charging.
BOTTOM_BL_ON 5 Set if the bottom backlight is on.
TOP_BL_ON 6 Set if the top backlight is on.
LCD_ON 7 Set if the LCDs are on.
i2c.mcu.pedometer_control

Bitmasks for the pedometer control

Lua Bit Notes
CLEAR 0 Clear the step history.
STEPS_FULL 4 Set when the step history is full.
i2c.mcu.power_trigger

Bitmasks for the power signal triggers

Lua Bit Notes
SHUTDOWN 0 Turn off the system.
RESET 1 Reset the MCU.
REBOOT 2 Reboot the system.
LGY_SHUTDOWN 3 Turn off the system. (Used by LgyBg)
SLEEP 4 Signal to enter sleep mode.
OLDMCU_BL_OFF 4 (Old MCU_FIRM only) turn the backlights off.
OLDMCU_BL_ON 5 (Old MCU_FIRM only) turn the backlights on.
OLDMCU_LCD_OFF 6 (Old MCU_FIRM only) turn the LCDs off.
OLDMCU_LCD_ON 7 (Old MCU_FIRM only) turn the LCDs on.
i2c.mcu.power_led_state
Lua Value Notes
NORMAL 0 Fade power LED to blue, while checking for battery percentage.
FADE_BLUE 1 Fade power LED to blue.
SLEEP_MODE 2 The power LED pulses blue slowly, as it does in sleep mode.
OFF 3 Power LED fades off.
RED 4 Power LED instantaneously turns red.
BLUE 5 Power LED instantaneously turns blue.
BLINK_RED 6 Power LED and info (notification) LED blink red, as they do when the battery is critically low.
i2c.mcu.wifi_mode

WiFi mode register values

Lua Value Notes
CTR 0 3DS WiFi mode.
MP 1 DS[i] WiFi mode ("MP").
i2c.mcu.sensor_config

Sensor configuration register values

Lua Bit Notes
ACCELEROMETER_ENABLE 0 If set, the accelerometer is enabled.
PEDOMETER_ENABLE 1 If set, the pedometer is enabled.
i2c.mcu.accelerometer_scale

Accelerometer scale settings

Lua Value Notes
SCALE_2G 0x0 -2G to 2G
SCALE_4G 0x1 -4G to 4G
SCALE_8G 0x3 -8G to 8G

i2c.read

  • table i2c.read(int device_id, int register_address, int length)

Read data from an I²C device register. Returns the data as a table of integers (0-255) for direct math operations.

  • Arguments
    • device_id - I²C device ID (0-17).
    • register_address - Register address to read from (0-255)
    • length - Number of bytes to read (1-64)
  • Returns: Table of byte values as integers
  • Throws
    • "Invalid device ID: ## (must be 0-17)" - device ID is outside valid range
    • "Invalid register address: ## (must be 0-255)" - register address is outside valid range
    • "Invalid length: ## (must be 1-64)" - length is outside valid range
    • "I2C read failed" - hardware I²C operation failed

Example:

-- Read voltage from MCU device
local voltage_raw = i2c.read(i2c.dev.MCU, i2c.mcu.reg.BATTERY_VOLTAGE, 1)
local voltage = voltage_raw[1] * 5 / 256.0
print("System voltage:", voltage, "V")

-- Read Power status
local power_state = i2c.read(i2c.dev.MCU, i2c.mcu.reg.POWER_STATUS, 1)
if power_state[1] & i2c.mcu.power_status_flags.SHELL_OPEN ~= 0 then
  print("Shell is open")
end
if power_state[1] & i2c.mcu.power_status_flags.CHARGING ~= 0 then
  print("Charging")
end

i2c.write

  • void i2c.write(int device_id, int register_address, table data)

Warning

Writing data to random registers can lead to bricking!.

Write data to an I²C device register. Requires memory write permissions. Not all registers are supported for writing.

  • Allowed registers (MCU)
    • mcu.reg.USERDATA_RAM_ - Registers 0x15-0x17 and 0x1C-0x1F
    • mcu.reg.LED_BRIGHTNESS_STATE - Brightness of the status LEDs.
    • mcu.reg.POWER_LED_STATE - Sets the state of the power LED
    • mcu.reg.WLAN_LED_STATE - Sets the state of the wifi LED
    • mcu.reg.CAMERA_LED_STATE - Sets the state of the camera LED
    • mcu.reg.LED_3D_STATE - Sets the state of the 3D LED
    • mcu.reg.NOTIFICATION_LED_STATE - Sets the state of the info (notification) LED
  • Arguments
    • device_id - I²C device ID (0-17).
    • register_address - Register address to write to (0-255)
    • data - Table of byte values to write (each value must be 0-255)
  • Throws
    • "Invalid device ID: ## (must be 0-17)" - device ID is outside valid range
    • "Invalid register address: ## (must be 0-255)" - register address is outside valid range
    • "Write to device ##, register ## is not allowed" - The device/register is not on the allowed write list
    • "Third parameter must be a table of byte values" - data parameter is not a table
    • "Invalid data length: ## (must be 1-64)" - data table length is outside valid range
    • "Table element ## is not an integer" - data table contains non-integer values
    • "Table element ## is out of range: ## (must be 0-255)" - data table contains values outside byte range
    • "I2C write failed" - hardware I²C operation failed
    • Permission errors if memory write access is denied