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/console
|
||||
import libnx/wrapper/hid
|
||||
import libnx/wrapper/applet
|
||||
|
||||
proc printf(formatstr: cstring) {.importc: "printf", varargs,
|
||||
header: "<stdio.h>".}
|
||||
import libnx/utils
|
||||
|
||||
proc main() =
|
||||
gfxInitDefault()
|
||||
|
||||
discard consoleInit(nil)
|
||||
|
||||
printf("\x1b[16;20HHello World From NIM!")
|
||||
echo "\x1b[17;20HHELLO FROM NIM"
|
||||
while appletMainLoop():
|
||||
hidScanInput()
|
||||
|
||||
mainLoop:
|
||||
let keysDown = hidKeysDown(CONTROLLER_P1_AUTO)
|
||||
|
||||
if (keysDown and KEY_PLUS.uint64) > 0.uint64:
|
||||
break
|
||||
|
||||
gfxFlushBuffers()
|
||||
gfxSwapBuffers()
|
||||
gfxWaitForVsync()
|
||||
|
||||
gfxExit()
|
||||
|
||||
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