mirror of
https://github.com/switchbrew/switch-examples.git
synced 2025-06-20 21:12:38 +02:00
Added alarm-notifications example.
This commit is contained in:
parent
afb3d2132f
commit
b9df83b93d
222
alarm-notifications/Makefile
Normal file
222
alarm-notifications/Makefile
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITPRO)/libnx/switch_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||||
|
#
|
||||||
|
# NO_ICON: if set to anything, do not use icon.
|
||||||
|
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||||
|
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||||
|
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.jpg
|
||||||
|
# - icon.jpg
|
||||||
|
# - <libnx folder>/default_icon.jpg
|
||||||
|
#
|
||||||
|
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.json
|
||||||
|
# - config.json
|
||||||
|
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
||||||
|
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||||
|
# NACP building is skipped as well.
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := $(notdir $(CURDIR))
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include
|
||||||
|
#ROMFS := romfs
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS := -lnx
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
ifeq ($(strip $(CONFIG_JSON)),)
|
||||||
|
jsons := $(wildcard *.json)
|
||||||
|
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||||
|
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring config.json,$(jsons)))
|
||||||
|
export APP_JSON := $(TOPDIR)/config.json
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.jpg)
|
||||||
|
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_ICON)),)
|
||||||
|
export NROFLAGS += --icon=$(APP_ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(APP_TITLEID),)
|
||||||
|
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ROMFS),)
|
||||||
|
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
ifeq ($(strip $(APP_JSON)),)
|
||||||
|
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||||
|
else
|
||||||
|
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(APP_JSON)),)
|
||||||
|
|
||||||
|
all : $(OUTPUT).nro
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||||
|
else
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf
|
||||||
|
endif
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
all : $(OUTPUT).nsp
|
||||||
|
|
||||||
|
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||||
|
|
||||||
|
$(OUTPUT).nso : $(OUTPUT).elf
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
181
alarm-notifications/source/main.c
Normal file
181
alarm-notifications/source/main.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Include the most common headers from the C standard library
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
// Include the main libnx system header, for Switch development
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
// This example shows how to use Alarm Notifications, see libnx notif.h.
|
||||||
|
// This must be run under a host Application. To avoid conflicts with official apps, normally you should not run under a host Application where the official Application also uses Alarm Notifications.
|
||||||
|
|
||||||
|
// Parse the ApplicationParameter and verify that it belongs to the current hb app. You can store any data you want in the ApplicationParameter.
|
||||||
|
bool parse_app_param(u8 *outdata, size_t outdata_size, u64 out_size, u8 *app_param_header, size_t app_param_header_size) {
|
||||||
|
printf("out_size=0x%lx\n", out_size);
|
||||||
|
if (out_size != outdata_size) // Adjust this check if needed.
|
||||||
|
printf("out_size is invalid, ignoring data since it doesn't belong to the current app.\n");
|
||||||
|
else {
|
||||||
|
if(memcmp(outdata, app_param_header, app_param_header_size)==0) {
|
||||||
|
printf("data: %s\n", (char*)&outdata[0x8]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("ApplicationParameter header mismatch, ignoring data since it doesn't belong to the current app.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main program entrypoint
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// This example uses a text console, as a simple way to output text to the screen.
|
||||||
|
// If you want to write a software-rendered graphics application,
|
||||||
|
// take a look at the graphics/simplegfx example, which uses the libnx Framebuffer API instead.
|
||||||
|
// If on the other hand you want to write an OpenGL based application,
|
||||||
|
// take a look at the graphics/opengl set of examples, which uses EGL instead.
|
||||||
|
consoleInit(NULL);
|
||||||
|
|
||||||
|
printf("alarm-notifications example\n");
|
||||||
|
|
||||||
|
Result rc=0, rc2=0;
|
||||||
|
bool tmpflag=0;
|
||||||
|
u16 alarm_setting_id=0;
|
||||||
|
s32 total_out=0;
|
||||||
|
NotifAlarmSetting alarm_setting;
|
||||||
|
NotifAlarmSetting alarm_settings[NOTIF_MAX_ALARMS];
|
||||||
|
Event alarmevent={0};
|
||||||
|
|
||||||
|
// To avoid conflicts with other hb apps, use some sort of header to verify that the ApplicationParameter belongs to the current hb app. Replace this with your own data. Note that official apps don't do this.
|
||||||
|
// Note that ApplicationParameter is optional, see notif.h - you can disable/remove code using it you want.
|
||||||
|
u8 app_param_header[0x8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
|
||||||
|
u8 app_param[0x20]={0};
|
||||||
|
|
||||||
|
u8 outdata[0x21]; // Since we're handling this as a string, make sure it's NUL-terminated.
|
||||||
|
|
||||||
|
memcpy(app_param, app_param_header, sizeof(app_param_header));
|
||||||
|
strncpy((char*)&app_param[0x8], "app param", sizeof(app_param)-9); // This example stores a string in the app_param - replace this with whatever data you want.
|
||||||
|
|
||||||
|
rc = notifInitialize(NotifServiceType_Application);
|
||||||
|
if (R_FAILED(rc)) printf("notifInitialize(): 0x%x\n", rc);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) { // Some official apps don't use this. See libnx notif.h for this.
|
||||||
|
rc = notifGetNotificationSystemEvent(&alarmevent);
|
||||||
|
printf("notifGetNotificationSystemEvent(): 0x%x\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
printf("Press A to register the Alarm.\n");
|
||||||
|
printf("Press B to list the Alarms.\n");
|
||||||
|
printf("Press X to delete the registered Alarm.\n");
|
||||||
|
}
|
||||||
|
printf("Press + to exit.\n");
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
while (appletMainLoop())
|
||||||
|
{
|
||||||
|
// Scan all the inputs. This should be done once for each frame
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
// hidKeysDown returns information about which buttons have been
|
||||||
|
// just pressed in this frame compared to the previous one
|
||||||
|
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||||
|
|
||||||
|
if (kDown & KEY_PLUS)
|
||||||
|
break; // break in order to return to hbmenu
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && R_SUCCEEDED(eventWait(&alarmevent, 0))) { // Some official apps don't use this. See libnx notif.h for this.
|
||||||
|
u64 out_size=0;
|
||||||
|
memset(outdata, 0, sizeof(outdata));
|
||||||
|
rc = notifTryPopNotifiedApplicationParameter(outdata, sizeof(outdata)-1, &out_size);
|
||||||
|
printf("notifTryPopNotifiedApplicationParameter(): 0x%x\n", rc);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
parse_app_param(outdata, sizeof(outdata)-1, out_size, app_param_header, sizeof(app_param_header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (kDown & KEY_A) {
|
||||||
|
// Setup an alarm with {current local-time} + {2 minutes}. You can use any weekday/time you want.
|
||||||
|
// See libnx notif.h for more notifAlarmSetting*() funcs.
|
||||||
|
|
||||||
|
notifAlarmSettingCreate(&alarm_setting);
|
||||||
|
|
||||||
|
time_t unixTime = time(NULL) + 60*2;
|
||||||
|
struct tm* timeStruct = localtime((const time_t *)&unixTime);
|
||||||
|
|
||||||
|
u32 day = timeStruct->tm_wday;
|
||||||
|
s32 hour = timeStruct->tm_hour;
|
||||||
|
s32 minute = timeStruct->tm_min;
|
||||||
|
|
||||||
|
printf("Using the following schedule setting: weekday = %u, %02d:%02d.\n", day, hour, minute);
|
||||||
|
|
||||||
|
// You can also use this multiple times if you want for multiple days - this example only uses it once for a single day.
|
||||||
|
rc = notifAlarmSettingEnable(&alarm_setting, day, hour, minute);
|
||||||
|
printf("notifAlarmSettingEnable(): 0x%x\n", rc);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rc = notifRegisterAlarmSetting(&alarm_setting_id, &alarm_setting, app_param, sizeof(app_param));
|
||||||
|
printf("notifRegisterAlarmSetting(): 0x%x\n", rc);
|
||||||
|
if (R_SUCCEEDED(rc)) printf("alarm_setting_id = 0x%x\n", alarm_setting_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (kDown & KEY_B) {
|
||||||
|
// List the Alarms.
|
||||||
|
|
||||||
|
total_out=0;
|
||||||
|
memset(alarm_settings, 0, sizeof(alarm_settings));
|
||||||
|
rc = notifListAlarmSettings(alarm_settings, NOTIF_MAX_ALARMS, &total_out);
|
||||||
|
printf("notifListAlarmSettings(): 0x%x\n", rc);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
printf("total_out: %d\n", total_out);
|
||||||
|
|
||||||
|
for (s32 alarmi=0; alarmi<total_out; alarmi++) {
|
||||||
|
printf("[%d]: muted=%d.\n", alarmi, alarm_settings[alarmi].muted);
|
||||||
|
|
||||||
|
// Verify that the Alarm belongs to the current app via the ApplicationParameter / parse the data from there.
|
||||||
|
u32 actual_size=0;
|
||||||
|
memset(outdata, 0, sizeof(outdata));
|
||||||
|
rc2 = notifLoadApplicationParameter(alarm_settings[alarmi].alarm_setting_id, outdata, sizeof(outdata)-1, &actual_size);
|
||||||
|
printf("notifLoadApplicationParameter(): 0x%x\n", rc2);
|
||||||
|
if (R_FAILED(rc2) || !parse_app_param(outdata, sizeof(outdata)-1, actual_size, app_param_header, sizeof(app_param_header))) continue;
|
||||||
|
|
||||||
|
// If you want to update an AlarmSetting/ApplicationParameter from the alarm-listing, you can use this. notifAlarmSetting*() funcs can be used to update it if wanted.
|
||||||
|
// rc2 = notifUpdateAlarmSetting(&alarm_settings[alarmi], outdata, sizeof(outdata)-1);
|
||||||
|
// printf("notifUpdateAlarmSetting(): 0x%x\n", rc2);
|
||||||
|
|
||||||
|
// Print the schedule settings.
|
||||||
|
for (u32 day_of_week=0; day_of_week<7; day_of_week++) {
|
||||||
|
rc2 = notifAlarmSettingIsEnabled(&alarm_settings[alarmi], day_of_week, &tmpflag);
|
||||||
|
if (R_SUCCEEDED(rc2) && tmpflag) {
|
||||||
|
NotifAlarmTime alarmtime={0};
|
||||||
|
rc2 = notifAlarmSettingGet(&alarm_settings[alarmi], day_of_week, &alarmtime);
|
||||||
|
if (R_SUCCEEDED(rc2)) {
|
||||||
|
printf("weekday %d = %02d:%02d. ", day_of_week, alarmtime.hour, alarmtime.minute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((kDown & KEY_X) && alarm_setting_id) {
|
||||||
|
// Delete the AlarmSetting which was registered with the KEY_A block.
|
||||||
|
// If wanted, you can also use this with alarm_settings[alarmi].alarm_setting_id with the output from notifListAlarmSettings.
|
||||||
|
rc = notifDeleteAlarmSetting(alarm_setting_id);
|
||||||
|
printf("notifDeleteAlarmSetting(): 0x%x\n", rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the console, sending a new frame to the display
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventClose(&alarmevent);
|
||||||
|
notifExit();
|
||||||
|
|
||||||
|
// Deinitialize and clean up resources used by the console (important!)
|
||||||
|
consoleExit(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user