Skip to content

Commit

Permalink
INITIAL COMMIT
Browse files Browse the repository at this point in the history
  • Loading branch information
dkgitdev committed Nov 28, 2022
0 parents commit 7e96886
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
lib/
build/
nimcache/
.idea/
3 changes: 3 additions & 0 deletions nim.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://nim-lang.org/docs/nimc.html#crossminuscompilation-for-nintendo-switch
--mm:orc
--d:nimAllocPagesViaMalloc
17 changes: 17 additions & 0 deletions nimLibnx.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Package

version = "0.1.0"
author = "Dmitry Arkhipenko"
description = "LibNX port to be used in Nim"
license = "MIT"
srcDir = "src"


# Dependencies

requires "nim >= 1.6.6"

# Most of the things are better with this one :D
requires "switch_build"

# In production you should pin the versions, like with the nim above
55 changes: 55 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
NimNX
=====

Basic nim template for skipping all the "how-tos" straight to a working example!

This project can also be used to start new NX projects.
Feel free to skim through the code and see how it works.

# Usage
Step #0: install nim :D

First, install devkitpro (and export env vars too).

Then, build your *.nro:

```shell
nimble install
switch_build src/nimNx.nim
```

Copy `build/nimNx/nimNx.nro` to `/switch/nimNx/`.

Launch using Switch

# Description

This project consists of two parts:
+ C `FFI` to get all the libNX parts available for nim (under `src/NimNx`)
+ The actual nim code that uses this stuff

This project was made using following technique:

OPEN C PROJECT
FIND DEFINITION OF C VAR / FUNC / STRUCT
IMPORT IT CORRECTLY IN NIM
USE IN A SAME MANNER

So I highly recommend finding same identifiers
in original libNx C code and see how it got translated to nim.

# FAQ

### Why `type`s + `const` for C `enums` (like under `src/nimNx/libnx/hid`)?

[https://forum.nim-lang.org/t/5768](Nim forum)

### Why specify `discardable` pragma in `importc` `proc`s?

As we mostly never use their results

### Why recreating BitFlags instead of importing them?

You actually need to recreate it one way or another, as it's using #define to work with bitmaps.
There's a pretty low chance it would change in future releases of libNx, so I decided to recreate them.

54 changes: 54 additions & 0 deletions src/nimNx.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# These bitand and bitor functions gotta be taken from somewhere :D
import std/bitops

# This allows to access members ONLY using `module.member` syntax
from nimNx/libnx/hid/HidNpadStyleTag import nil
from nimNx/libnx/hid/HidNpadButton import nil
import nimNx/libnx


proc main() :int {.raises: [].}=

# Let cannot be used for chainging (or later-initialized) objects
var
pad: PadState
kDown: HidNpadButton.HidNpadButton

# Open console
consoleInit(nil)

# Echo works correctly!
echo "Hello from nim!"
echo "Press + (PLUS) button to exit"

# Set possible button layouts
# Use this module + const name to emulate enum syntax
padConfigureInput(1, HidNpadStyleTag.HidNpadStyleSet_NpadStandard)

# To supply `&pad` we use `pad`'s memory `addr`
padInitializeDefault(addr pad)

# Run main loop
while (appletMainLoop()):

# Get new data from hids
padUpdate(addr pad)

# Get Buttons pressed
kDown = padGetButtonsDown(addr pad)

#echo their bitmasks (as regular cuints)
# echo "kDown: ", kDown.cuint, " HidNpadButton.HidNpadButton_Plus: ", HidNpadButton.HidNpadButton_Plus.cuint

# If plus -- exit
if (bitand[culong](kDown, HidNpadButton.HidNpadButton_Plus)): break

# Show next frame
consoleUpdate(nil)

# Exit app
consoleExit(nil);
0

# Run our code
discard main()
11 changes: 11 additions & 0 deletions src/nimNx/c/bits.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Stuff for working with c code

# Using func where possible, port of actual c code
func bit*(n: uint8): cuint = 1.cuint shl n
func bitl*(n: uint8): culong = 1.culong shl n

# This converters allows us to use these types in while loops and ifs
converter culong2bool*(cu: culong): bool =
if cu == 0: false else: true
converter cint2bool*(ci: cint): bool =
if ci == 0: false else: true
24 changes: 24 additions & 0 deletions src/nimNx/libnx.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import libnx/hid/HidNpadButton

# We don't need to specify fields we're not going to use
type
PrintConsole* {.importc, header: "switch.h".} = object
PadState* {.importc, header: "switch.h".} = object

# Console-related stuff
# pointer can be NULL (or `nil`) :D
proc consoleInit*(console: pointer): pointer {.importc, varargs, header: "switch.h", discardable.}
proc consoleUpdate*(console: pointer): void {.importc, varargs, header: "switch.h", discardable.}
proc consoleExit*(console: pointer): void {.importc, varargs, header: "switch.h", discardable.}

proc padConfigureInput*(max_players: cint, styleset: cuint): void {.importc, varargs, header: "switch.h", discardable.}

# It's type is `ptr PadState`, not `PadState`,
# as we need `addr`, not the value,
# as the functions will go and modify that obj "in-place"
proc padInitializeDefault*(pad: ptr PadState): void {.importc, varargs, header: "switch.h", discardable.}
proc padUpdate*(pad: ptr PadState): void {.importc, varargs, header: "switch.h", discardable.}
proc padGetButtonsDown*(pad: ptr PadState): HidNpadButton {.importc, varargs, header: "switch.h".}

# Applet main loop
proc appletMainLoop*(): cint {.importc, varargs, header: "switch.h".}
7 changes: 7 additions & 0 deletions src/nimNx/libnx/hid/HidNpadButton.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ../../c/bits

type HidNpadButton* = culong

# You may specify only fraction of the whole variables list
const
HidNpadButton_Plus* = HidNpadButton(bitl(10))
34 changes: 34 additions & 0 deletions src/nimNx/libnx/hid/HidNpadStyleTag.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import std/bitops

import ../../c/bits

# *'s are marking these symbols as exported (public, if you want)
type HidNpadStyleTag* = cuint

const
HidNpadStyleTag_NpadFullKey* = HidNpadStyleTag(bit(0))
HidNpadStyleTag_NpadHandheld* = HidNpadStyleTag(bit(1))
HidNpadStyleTag_NpadJoyDual* = HidNpadStyleTag(bit(2))
HidNpadStyleTag_NpadJoyLeft* = HidNpadStyleTag(bit(3))
HidNpadStyleTag_NpadJoyRight* = HidNpadStyleTag(bit(4))
HidNpadStyleTag_NpadGc* = HidNpadStyleTag(bit(5))
HidNpadStyleTag_NpadPalma* = HidNpadStyleTag(bit(6))
HidNpadStyleTag_NpadLark* = HidNpadStyleTag(bit(7))
HidNpadStyleTag_NpadHandheldLark* = HidNpadStyleTag(bit(8))
HidNpadStyleTag_NpadLucia* = HidNpadStyleTag(bit(9))
HidNpadStyleTag_NpadLagon* = HidNpadStyleTag(bit(10))
HidNpadStyleTag_NpadLager* = HidNpadStyleTag(bit(11))
HidNpadStyleTag_NpadSystemExt* = HidNpadStyleTag(bit(29))
HidNpadStyleTag_NpadSystem* = HidNpadStyleTag(bit(30))

# bitor to replace a | b | c operators for C's BitFlags
HidNpadStyleSet_NpadFullCtrl* = HidNpadStyleTag(bitor[cuint](
HidNpadStyleTag_NpadFullKey,
HidNpadStyleTag_NpadHandheld,
HidNpadStyleTag_NpadJoyDual
))
HidNpadStyleSet_NpadStandard* = HidNpadStyleTag(bitor[cuint](
HidNpadStyleSet_NpadFullCtrl,
HidNpadStyleTag_NpadJoyLeft,
HidNpadStyleTag_NpadJoyRight
))

0 comments on commit 7e96886

Please sign in to comment.