Make accounts, service, and result more Nim friendly
This commit is contained in:
parent
3256600653
commit
83a79afb3d
8 changed files with 435 additions and 15 deletions
28
examples/accounts/account_ex.nim
Normal file
28
examples/accounts/account_ex.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import libnx/wrapper/gfx
|
||||||
|
import libnx/wrapper/hid
|
||||||
|
import libnx/wrapper/console
|
||||||
|
import libnx/account
|
||||||
|
import libnx/utils
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
gfxInitDefault()
|
||||||
|
discard consoleInit(nil)
|
||||||
|
|
||||||
|
echo "\x1b[5;2H" & "Account info:"
|
||||||
|
|
||||||
|
withAccountService:
|
||||||
|
try:
|
||||||
|
let user = getActiveUser()
|
||||||
|
echo "\x1b[6;2HUsername: " & user.username
|
||||||
|
echo "\x1b[7;2HMiiID: " & $user.miiID
|
||||||
|
echo "\x1b[8;2HIconID: " & $user.iconID
|
||||||
|
except AccountError:
|
||||||
|
echo "\x1b[6;2HNo user currently selected!"
|
||||||
|
|
||||||
|
mainLoop:
|
||||||
|
let keysDown = hidKeysDown(CONTROLLER_P1_AUTO)
|
||||||
|
|
||||||
|
if (keysDown and KEY_PLUS.uint64) > 0.uint64:
|
||||||
|
break
|
||||||
|
|
||||||
|
main()
|
||||||
1
examples/accounts/account_ex.nim.cfg
Normal file
1
examples/accounts/account_ex.nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path="../../src"
|
||||||
|
|
@ -1,30 +1,17 @@
|
||||||
import libnx/wrapper/gfx
|
import libnx/wrapper/gfx
|
||||||
import libnx/wrapper/console
|
import libnx/wrapper/console
|
||||||
import libnx/wrapper/hid
|
import libnx/wrapper/hid
|
||||||
import libnx/wrapper/applet
|
import libnx/utils
|
||||||
|
|
||||||
proc printf(formatstr: cstring) {.importc: "printf", varargs,
|
|
||||||
header: "<stdio.h>".}
|
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
gfxInitDefault()
|
gfxInitDefault()
|
||||||
|
|
||||||
discard consoleInit(nil)
|
discard consoleInit(nil)
|
||||||
|
|
||||||
printf("\x1b[16;20HHello World From NIM!")
|
|
||||||
echo "\x1b[17;20HHELLO FROM NIM"
|
echo "\x1b[17;20HHELLO FROM NIM"
|
||||||
while appletMainLoop():
|
mainLoop:
|
||||||
hidScanInput()
|
|
||||||
|
|
||||||
let keysDown = hidKeysDown(CONTROLLER_P1_AUTO)
|
let keysDown = hidKeysDown(CONTROLLER_P1_AUTO)
|
||||||
|
|
||||||
if (keysDown and KEY_PLUS.uint64) > 0.uint64:
|
if (keysDown and KEY_PLUS.uint64) > 0.uint64:
|
||||||
break
|
break
|
||||||
|
|
||||||
gfxFlushBuffers()
|
|
||||||
gfxSwapBuffers()
|
|
||||||
gfxWaitForVsync()
|
|
||||||
|
|
||||||
gfxExit()
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
158
src/libnx/account.nim
Normal file
158
src/libnx/account.nim
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
import strutils
|
||||||
|
import libnx/wrapper/acc
|
||||||
|
import libnx/results
|
||||||
|
import libnx/wrapper/types
|
||||||
|
import libnx/service
|
||||||
|
|
||||||
|
type
|
||||||
|
AccountError* = object of Exception
|
||||||
|
|
||||||
|
User* = ref object
|
||||||
|
id*: u128
|
||||||
|
selected*: bool
|
||||||
|
username*: string
|
||||||
|
lastEdited*: uint64
|
||||||
|
iconID*: uint32
|
||||||
|
iconBgColorID*: uint8
|
||||||
|
miiID*: array[0x10, uint8]
|
||||||
|
|
||||||
|
Profile* = ref object
|
||||||
|
service*: Service
|
||||||
|
|
||||||
|
AccountImage* = ref object
|
||||||
|
data: seq[uint8]
|
||||||
|
imageSize: int
|
||||||
|
|
||||||
|
var enabled = false
|
||||||
|
|
||||||
|
template raiseEx(message: string) =
|
||||||
|
raise newException(AccountError, message)
|
||||||
|
|
||||||
|
proc getService*(): Service =
|
||||||
|
let serv = accountGetService()[]
|
||||||
|
result = newService(serv)
|
||||||
|
|
||||||
|
proc init() =
|
||||||
|
let service = getService()
|
||||||
|
if service.isActive:
|
||||||
|
return
|
||||||
|
|
||||||
|
let code = accountInitialize().newResult
|
||||||
|
if code.failed:
|
||||||
|
raiseEx("Error, account api could not be initialized: " & code.description)
|
||||||
|
|
||||||
|
proc exit() =
|
||||||
|
let service = getService()
|
||||||
|
if not service.isActive:
|
||||||
|
return
|
||||||
|
accountExit()
|
||||||
|
|
||||||
|
proc close*(profile: AccountProfile) =
|
||||||
|
accountProfileClose(profile.unsafeAddr)
|
||||||
|
|
||||||
|
template withAccountService*(code: untyped): typed =
|
||||||
|
enabled = true
|
||||||
|
init()
|
||||||
|
code
|
||||||
|
exit()
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
proc ensureEnabled() =
|
||||||
|
if not enabled:
|
||||||
|
raiseEx("Use withAccountService to access account functions.")
|
||||||
|
|
||||||
|
proc getImageSize*(profile: AccountProfile): int =
|
||||||
|
ensureEnabled()
|
||||||
|
var res = 0.csize
|
||||||
|
result = 0
|
||||||
|
let code = accountProfileGetImageSize(profile.unsafeAddr, res.addr).newResult
|
||||||
|
if code.failed:
|
||||||
|
raiseEx("Error, image size could not be received: " & code.description)
|
||||||
|
result = res.int
|
||||||
|
|
||||||
|
proc imageSize*(user: User): int =
|
||||||
|
var prof: AccountProfile
|
||||||
|
var size: csize
|
||||||
|
let res = accountProfileGetImageSize(prof.addr, size.addr).newResult
|
||||||
|
|
||||||
|
if res.failed:
|
||||||
|
raiseEx("Error, could not get image size: " & res.description)
|
||||||
|
|
||||||
|
result = size.int
|
||||||
|
|
||||||
|
proc getProfileHelper(userID: u128): AccountProfile =
|
||||||
|
let res = accountGetProfile(result.addr, userID).newResult
|
||||||
|
|
||||||
|
if res.failed:
|
||||||
|
raiseEx("Error, could not get user profile: " & res.description)
|
||||||
|
|
||||||
|
|
||||||
|
proc loadImage*(user: User): AccountImage =
|
||||||
|
ensureEnabled()
|
||||||
|
result = new(AccountImage)
|
||||||
|
let imSize = user.imageSize()
|
||||||
|
var size: csize
|
||||||
|
|
||||||
|
var prof = getProfileHelper(user.id)
|
||||||
|
|
||||||
|
result.data = newSeq[uint8](imSize)
|
||||||
|
|
||||||
|
let res = accountProfileLoadImage(
|
||||||
|
prof.addr, result.data[0].addr,
|
||||||
|
imSize, result.imageSize.addr
|
||||||
|
).newResult
|
||||||
|
|
||||||
|
if res.failed:
|
||||||
|
prof.close()
|
||||||
|
raiseEx("Error, could not load image: " & res.description)
|
||||||
|
|
||||||
|
prof.close()
|
||||||
|
|
||||||
|
proc getActiveUser*(): User =
|
||||||
|
ensureEnabled()
|
||||||
|
result = new(User)
|
||||||
|
var
|
||||||
|
userID: u128
|
||||||
|
selected: bool
|
||||||
|
|
||||||
|
var res = accountGetActiveUser(userID.addr, selected.addr).newResult
|
||||||
|
|
||||||
|
if res.failed:
|
||||||
|
raiseEx("Error, could not get active user ID: " & res.description)
|
||||||
|
|
||||||
|
if not selected:
|
||||||
|
raiseEx("No user currently selected!")
|
||||||
|
|
||||||
|
result.id = userID
|
||||||
|
result.selected = selected
|
||||||
|
|
||||||
|
var
|
||||||
|
prof: AccountProfile = getProfileHelper(userID)
|
||||||
|
userData: AccountUserData
|
||||||
|
profBase: AccountProfileBase
|
||||||
|
|
||||||
|
res = accountProfileGet(prof.addr, userData.addr, profBase.addr).newResult
|
||||||
|
|
||||||
|
if res.failed:
|
||||||
|
raiseEx("Error, could not get user data: " & res.description)
|
||||||
|
|
||||||
|
result.username = profBase.username.join("")
|
||||||
|
result.lastEdited = profBase.lastEditTimestamp
|
||||||
|
result.iconID = userData.iconID
|
||||||
|
result.iconBgColorID = userData.iconBackgroundColorID
|
||||||
|
result.miiID = userData.miiID
|
||||||
|
|
||||||
|
prof.close()
|
||||||
|
|
||||||
|
|
||||||
|
proc getProfile*(user: User): Profile =
|
||||||
|
ensureEnabled()
|
||||||
|
result = new(Profile)
|
||||||
|
var prof: AccountProfile
|
||||||
|
|
||||||
|
let res = accountGetProfile(prof.addr, user.id).newResult
|
||||||
|
if res.failed:
|
||||||
|
raiseEx("Error, could not get account profile: " & res.description)
|
||||||
|
|
||||||
|
result.service = newService(prof.s)
|
||||||
|
prof.close()
|
||||||
1
src/libnx/nim.cfg
Normal file
1
src/libnx/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path="../"
|
||||||
127
src/libnx/results.nim
Normal file
127
src/libnx/results.nim
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
import
|
||||||
|
libnx/wrapper/result,
|
||||||
|
libnx/wrapper/types
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
Module {.pure.} = enum
|
||||||
|
Invalid = 0, # This is just so the nim compiler is happy
|
||||||
|
Kernel = 1,
|
||||||
|
Libnx = 345,
|
||||||
|
LibnxNvidia = 348
|
||||||
|
|
||||||
|
Result* = ref object
|
||||||
|
code*: uint32
|
||||||
|
module*: string
|
||||||
|
description*: string
|
||||||
|
case kind*: Module
|
||||||
|
of Module.Kernel:
|
||||||
|
kernelError*: KernelError
|
||||||
|
of Module.Libnx:
|
||||||
|
libnxError*: LibnxError
|
||||||
|
of Module.LibnxNvidia:
|
||||||
|
libnxNvidiaError*: LibnxNvidiaError
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
KernelError* {.pure.} = enum
|
||||||
|
Timeout = 117
|
||||||
|
|
||||||
|
LibnxError* {.pure.} = enum
|
||||||
|
BadReloc=1,
|
||||||
|
OutOfMemory,
|
||||||
|
AlreadyMapped,
|
||||||
|
BadGetInfo_Stack,
|
||||||
|
BadGetInfo_Heap,
|
||||||
|
BadQueryMemory,
|
||||||
|
AlreadyInitialized,
|
||||||
|
NotInitialized,
|
||||||
|
NotFound,
|
||||||
|
IoError,
|
||||||
|
BadInput,
|
||||||
|
BadReent,
|
||||||
|
BufferProducerError,
|
||||||
|
HandleTooEarly,
|
||||||
|
HeapAllocFailed,
|
||||||
|
TooManyOverrides,
|
||||||
|
ParcelError,
|
||||||
|
BadGfxInit,
|
||||||
|
BadGfxEventWait,
|
||||||
|
BadGfxQueueBuffer,
|
||||||
|
BadGfxDequeueBuffer,
|
||||||
|
AppletCmdidNotFound,
|
||||||
|
BadAppletReceiveMessage,
|
||||||
|
BadAppletNotifyRunning,
|
||||||
|
BadAppletGetCurrentFocusState,
|
||||||
|
BadAppletGetOperationMode,
|
||||||
|
BadAppletGetPerformanceMode,
|
||||||
|
BadUsbCommsRead,
|
||||||
|
BadUsbCommsWrite,
|
||||||
|
InitFail_SM,
|
||||||
|
InitFail_AM,
|
||||||
|
InitFail_HID,
|
||||||
|
InitFail_FS,
|
||||||
|
BadGetInfo_Rng,
|
||||||
|
JitUnavailable,
|
||||||
|
WeirdKernel,
|
||||||
|
IncompatSysVer,
|
||||||
|
InitFail_Time,
|
||||||
|
TooManyDevOpTabs
|
||||||
|
|
||||||
|
LibnxNvidiaError* {.pure.} = enum
|
||||||
|
Unknown=1,
|
||||||
|
NotImplemented, #///< Maps to Nvidia: 1
|
||||||
|
NotSupported, #///< Maps to Nvidia: 2
|
||||||
|
NotInitialized, #///< Maps to Nvidia: 3
|
||||||
|
BadParameter, #///< Maps to Nvidia: 4
|
||||||
|
Timeout, #///< Maps to Nvidia: 5
|
||||||
|
InsufficientMemory, #///< Maps to Nvidia: 6
|
||||||
|
ReadOnlyAttribute, #///< Maps to Nvidia: 7
|
||||||
|
InvalidState, #///< Maps to Nvidia: 8
|
||||||
|
InvalidAddress, #///< Maps to Nvidia: 9
|
||||||
|
InvalidSize, #///< Maps to Nvidia: 10
|
||||||
|
BadValue, #///< Maps to Nvidia: 11
|
||||||
|
AlreadyAllocated, #///< Maps to Nvidia: 13
|
||||||
|
Busy, #///< Maps to Nvidia: 14
|
||||||
|
ResourceError, #///< Maps to Nvidia: 15
|
||||||
|
CountMismatch, #///< Maps to Nvidia: 16
|
||||||
|
SharedMemoryTooSmall, #///< Maps to Nvidia: 0x1000
|
||||||
|
FileOperationFailed, #///< Maps to Nvidia: 0x30003
|
||||||
|
IoctlFailed #///< Maps to Nvidia: 0x3000F
|
||||||
|
|
||||||
|
|
||||||
|
proc succeeded*(res: Result): bool = res.code.R_SUCCEEDED
|
||||||
|
proc failed*(res: Result): bool = res.code.R_FAILED
|
||||||
|
|
||||||
|
proc newResult*(code: uint32): Result =
|
||||||
|
result = new(Result)
|
||||||
|
|
||||||
|
result.code = code
|
||||||
|
if code.R_SUCCEEDED:
|
||||||
|
return
|
||||||
|
|
||||||
|
let moduleCode = code.R_MODULE
|
||||||
|
let module = Module(moduleCode)
|
||||||
|
|
||||||
|
result.kind = module
|
||||||
|
|
||||||
|
let descCode = code.R_DESCRIPTION
|
||||||
|
let resCode = MAKERESULT(moduleCode, descCode)
|
||||||
|
|
||||||
|
var description = ""
|
||||||
|
|
||||||
|
case module
|
||||||
|
of Module.Invalid:
|
||||||
|
discard
|
||||||
|
of Module.Kernel:
|
||||||
|
result.kernelError = KernelError(resCode)
|
||||||
|
description = $result.kernelError
|
||||||
|
of Module.Libnx:
|
||||||
|
result.libnxError = LibnxError(resCode)
|
||||||
|
description = $result.libnxError
|
||||||
|
of Module.LibnxNvidia:
|
||||||
|
result.libnxNvidiaError = LibnxNvidiaError(resCode)
|
||||||
|
description = $result.libnxNvidiaError
|
||||||
|
|
||||||
|
result.module = $module
|
||||||
|
result.description = description
|
||||||
105
src/libnx/service.nim
Normal file
105
src/libnx/service.nim
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
import
|
||||||
|
libnx/results,
|
||||||
|
libnx/wrapper/sm
|
||||||
|
|
||||||
|
from libnx/wrapper/types import Handle
|
||||||
|
|
||||||
|
type
|
||||||
|
Service* = ref object
|
||||||
|
serv: sm.Service
|
||||||
|
|
||||||
|
|
||||||
|
proc newService*(serv: sm.Service): Service =
|
||||||
|
result = Service(serv: serv)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Returns whether a service is overriden in the homebrew environment.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return true if overriden.
|
||||||
|
##
|
||||||
|
proc isOverride*(service: Service): bool =
|
||||||
|
serviceIsOverride(service.serv.addr)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Returns whether a service has been initialized.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return true if initialized.
|
||||||
|
##
|
||||||
|
proc isActive*(service: Service): bool =
|
||||||
|
serviceIsActive(service.serv.addr)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Returns whether a service is a domain.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return true if a domain.
|
||||||
|
##
|
||||||
|
proc isDomain*(service: Service): bool =
|
||||||
|
serviceIsDomain(service.serv.addr)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Returns whether a service is a domain subservice.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return true if a domain subservice.
|
||||||
|
##
|
||||||
|
proc isDomainSubservice*(service: Service): bool =
|
||||||
|
serviceIsDomainSubservice(service.serv.addr)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief For a domain/domain subservice, return the associated object ID.
|
||||||
|
## @param[in] s Service object, necessarily a domain or domain subservice.
|
||||||
|
## @return The object ID.
|
||||||
|
##
|
||||||
|
proc objectId*(service: Service): uint32 =
|
||||||
|
serviceGetObjectId(service.serv.addr)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Closes a domain object by ID.
|
||||||
|
## @param[in] s Service object, necessarily a domain or domain subservice.
|
||||||
|
## @param object_id ID of the object to close.
|
||||||
|
## @return Result code.
|
||||||
|
##
|
||||||
|
proc close*(service: Service; objectId: uint32): Result =
|
||||||
|
serviceCloseObjectById(service.serv.addr, objectId).newResult
|
||||||
|
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Dispatches an IPC request to a service.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return Result code.
|
||||||
|
##
|
||||||
|
proc ipcDispatch*(service: Service): Result =
|
||||||
|
serviceIpcDispatch(service.serv.addr).newResult
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Creates a service object from an IPC session handle.
|
||||||
|
## @param[out] s Service object.
|
||||||
|
## @param[in] h IPC session handle.
|
||||||
|
##
|
||||||
|
proc createService*(handle: Handle): Service =
|
||||||
|
result = new(Service)
|
||||||
|
serviceCreate(result.serv.addr, handle)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Creates a domain subservice object from a parent service.
|
||||||
|
## @param[out] s Service object.
|
||||||
|
## @param[in] parent Parent service, necessarily a domain or domain subservice.
|
||||||
|
## @param[in] object_id Object ID for this subservice.
|
||||||
|
##
|
||||||
|
proc createDomainSubservice*(parent: Service; objectId: uint32): Service =
|
||||||
|
result = new(Service)
|
||||||
|
serviceCreateDomainSubservice(result.serv.addr, parent.serv.addr, objectId)
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Converts a regular service to a domain.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
## @return Result code.
|
||||||
|
##
|
||||||
|
proc convertToDomain*(service: Service): Result =
|
||||||
|
serviceConvertToDomain(service.serv.addr).newResult
|
||||||
|
|
||||||
|
## *
|
||||||
|
## @brief Closes a service.
|
||||||
|
## @param[in] s Service object.
|
||||||
|
##
|
||||||
|
proc close*(service: Service) =
|
||||||
|
serviceClose(service.serv.addr)
|
||||||
13
src/libnx/utils.nim
Normal file
13
src/libnx/utils.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import libnx/wrapper/gfx, libnx/wrapper/hid, libnx/wrapper/applet
|
||||||
|
|
||||||
|
template mainLoop*(code: untyped): untyped =
|
||||||
|
while appletMainLoop():
|
||||||
|
hidScanInput()
|
||||||
|
|
||||||
|
code
|
||||||
|
|
||||||
|
gfxFlushBuffers()
|
||||||
|
gfxSwapBuffers()
|
||||||
|
gfxWaitForVSync()
|
||||||
|
|
||||||
|
gfxExit()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue