Example #1
0
void aptEventHandler(void *arg)
{
	bool runThread = true;

	while(runThread)
	{
		s32 syncedID = 0;
		svcWaitSynchronizationN(&syncedID, aptEvents, 3, 0, U64_MAX);
		svcClearEvent(aptEvents[syncedID]);
		switch(syncedID)
		{
			// Event 0 means we got a signal from NS (home button, power button etc).
			case 0x0:
				__handle_notification();
				break;
			// Event 1 means we got an incoming parameter.
			case 0x1:
				runThread = __handle_incoming_parameter();
				break;
			// Event 2 means we should exit the thread.
			case 0x2:
				runThread = false;
				break;
		}
	}
}
Example #2
0
int main(void)
{
    Handle handles[10] = {0}; //notification handle + service handles
    MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};

    for(u32 i = 0; i < 9; i++)
        assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1));

    assertSuccess(MyThread_Create(&receiverThread, receiver, receiverStack, THREAD_STACK_SIZE, 0x2D, -2));
    assertSuccess(MyThread_Create(&senderThread, sender, senderStack, THREAD_STACK_SIZE, 0x2D, -2));
    assertSuccess(MyThread_Create(&PXISRV11HandlerThread, PXISRV11Handler, PXISRV11HandlerStack, THREAD_STACK_SIZE, 0x2D, -2));

    assertSuccess(srvEnableNotification(&handles[0]));

    while(!shouldTerminate)
    {
        s32 index = 0;
        assertSuccess(svcWaitSynchronizationN(&index, handles, 10, false, -1LL));

        if(index == 0)
        {
            u32 notificationId;
            assertSuccess(srvReceiveNotification(&notificationId));
            if(notificationId == 0x100) shouldTerminate = true;
        }

        else
        {
            Handle session = 0;
            SessionData *data = &sessionManager.sessionData[index - 1];
            assertSuccess(svcAcceptSession(&session, handles[index]));

            RecursiveLock_Lock(&sessionManager.senderLock);
            if(data->handle != 0)
                svcBreak(USERBREAK_PANIC);

            data->handle = session;
            assertSuccess(svcSignalEvent(sessionManager.sendAllBuffersToArm9Event));

            RecursiveLock_Unlock(&sessionManager.senderLock);
        }

    }

    u32 PXIMC_OnPXITerminate = 0x10000; //TODO: see if this is correct
    sessionManager.sessionData[0].state = STATE_SENT_TO_ARM9;
    sendPXICmdbuf(NULL, 0, &PXIMC_OnPXITerminate);

    assertSuccess(MyThread_Join(&receiverThread, -1LL));
    assertSuccess(MyThread_Join(&senderThread, -1LL));
    assertSuccess(MyThread_Join(&PXISRV11HandlerThread, -1LL));

    for(u32 i = 0; i < 10; i++)
        svcCloseHandle(handles[i]);

    return 0;
}
Example #3
0
static inline void initPXI(void)
{
    Result res;

    Handle handles[2] = {0};

    PXIReset();

    if(PXISyncInterrupt != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
    assertSuccess(svcCreateEvent(&PXISyncInterrupt, RESET_ONESHOT));

    if(PXITransferMutex != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
    assertSuccess(svcCreateMutex(&PXITransferMutex, false));

    assertSuccess(svcCreateEvent(&handles[0], RESET_ONESHOT)); //receive FIFO not empty
    assertSuccess(svcCreateEvent(&handles[1], RESET_ONESHOT)); //send FIFO empty
    assertSuccess(bindPXIInterrupts(&PXISyncInterrupt, &handles[0], &handles[1]));

    s32 handleIndex;
    do
    {
        while(!PXIIsSendFIFOFull()) PXISendWord(0);

        res = assertSuccess(svcWaitSynchronization(handles[0], 0LL));
        if(R_DESCRIPTION(res) == RD_TIMEOUT)
            assertSuccess(svcWaitSynchronizationN(&handleIndex, handles, 2, false, -1LL));
        else
            handleIndex = 0;
    } while(handleIndex != 0);



    unbindPXIInterrupts(NULL, &handles[0], &handles[1]);

    PXISendByte(1);
    while(PXIReceiveByte() < 1);

    while (!PXIIsReceiveFIFOEmpty())
        PXIReceiveWord();

    PXISendByte(2);
    while(PXIReceiveByte() < 2);

    svcCloseHandle(handles[0]);
    svcCloseHandle(handles[1]);
}
Example #4
0
static void task_populate_titledb_thread(void* arg) {
    populate_titledb_data* data = (populate_titledb_data*) arg;

    Result res = 0;

    linked_list titles;
    linked_list_init(&titles);

    json_t* root = NULL;
    if(R_SUCCEEDED(res = http_download_json("https://api.titledb.com/v1/entry?nested=true"
                                                    "&only=id&only=name&only=author&only=headline&only=category"
                                                    "&only=cia.id&only=cia.mtime&only=cia.version&only=cia.size&only=cia.titleid"
                                                    "&only=tdsx.id&only=tdsx.mtime&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id",
                                            &root, 1024 * 1024))) {
        if(json_is_array(root)) {
            for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) {
                svcWaitSynchronization(task_get_pause_event(), U64_MAX);
                if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                    break;
                }

                json_t* entry = json_array_get(root, i);
                if(json_is_object(entry)) {
                    list_item* item = (list_item*) calloc(1, sizeof(list_item));
                    if(item != NULL) {
                        titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info));
                        if(titledbInfo != NULL) {
                            titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0);
                            string_copy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category));
                            string_copy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription));
                            string_copy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher));

                            json_t* headline = json_object_get(entry, "headline");
                            if(json_is_string(headline)) {
                                const char* val = json_string_value(headline);

                                if(json_string_length(headline) > sizeof(titledbInfo->headline) - 1) {
                                    snprintf(titledbInfo->headline, sizeof(titledbInfo->headline), "%.508s...", val);
                                } else {
                                    string_copy(titledbInfo->headline, val, sizeof(titledbInfo->headline));
                                }
                            } else {
                                titledbInfo->headline[0] = '\0';
                            }

                            json_t* cias = json_object_get(entry, "cia");
                            if(json_is_array(cias)) {
                                for(u32 j = 0; j < json_array_size(cias); j++) {
                                    json_t* cia = json_array_get(cias, j);
                                    if(json_is_object(cia)) {
                                        const char* mtime = json_object_get_string(cia, "mtime", "Unknown");
                                        if(!titledbInfo->cia.exists || task_populate_titledb_compare_dates(mtime, titledbInfo->cia.mtime, sizeof(titledbInfo->cia.mtime)) >= 0) {
                                            titledbInfo->cia.exists = true;

                                            titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0);
                                            string_copy(titledbInfo->cia.mtime, mtime, sizeof(titledbInfo->cia.mtime));
                                            string_copy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version));
                                            titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0);
                                            titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16);
                                        }
                                    }
                                }
                            }

                            json_t* tdsxs = json_object_get(entry, "tdsx");
                            if(json_is_array(tdsxs)) {
                                for(u32 j = 0; j < json_array_size(tdsxs); j++) {
                                    json_t* tdsx = json_array_get(tdsxs, j);
                                    if(json_is_object(tdsx)) {
                                        const char* mtime = json_object_get_string(tdsx, "mtime", "Unknown");
                                        if(!titledbInfo->tdsx.exists || task_populate_titledb_compare_dates(mtime, titledbInfo->tdsx.mtime, sizeof(titledbInfo->tdsx.mtime)) >= 0) {
                                            titledbInfo->tdsx.exists = true;

                                            titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0);
                                            string_copy(titledbInfo->tdsx.mtime, mtime, sizeof(titledbInfo->tdsx.mtime));
                                            string_copy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version));
                                            titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0);

                                            json_t* smdh = json_object_get(tdsx, "smdh");
                                            if(json_is_object(smdh)) {
                                                titledbInfo->tdsx.smdh.exists = true;

                                                titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0);
                                            }
                                        }
                                    }
                                }
                            }

                            char* latestTime = "Unknown";
                            if(titledbInfo->cia.exists && titledbInfo->tdsx.exists) {
                                if(task_populate_titledb_compare_dates(titledbInfo->cia.mtime, titledbInfo->tdsx.mtime, sizeof(titledbInfo->cia.mtime)) >= 0) {
                                    latestTime = titledbInfo->cia.mtime;
                                } else {
                                    latestTime = titledbInfo->tdsx.mtime;
                                }
                            } else if(titledbInfo->cia.exists) {
                                latestTime = titledbInfo->cia.mtime;
                            } else if(titledbInfo->tdsx.exists) {
                                latestTime = titledbInfo->tdsx.mtime;
                            }

                            string_copy(titledbInfo->mtime, latestTime, sizeof(titledbInfo->mtime));

                            if((titledbInfo->cia.exists || titledbInfo->tdsx.exists) && (data->filter == NULL || data->filter(data->userData, titledbInfo))) {
                                string_copy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX);
                                item->data = titledbInfo;

                                task_populate_titledb_update_status(item);

                                linked_list_add_sorted(&titles, item, data->userData, data->compare);
                            } else {
                                free(titledbInfo);
                                free(item);
                            }
                        } else {
                            free(item);

                            res = R_APP_OUT_OF_MEMORY;
                        }
                    } else {
                        res = R_APP_OUT_OF_MEMORY;
                    }
                }
            }

            linked_list_iter iter;
            linked_list_iterate(&titles, &iter);

            while(linked_list_iter_has_next(&iter)) {
                list_item* item = linked_list_iter_next(&iter);

                if(R_SUCCEEDED(res)) {
                    linked_list_add(data->items, item);
                } else {
                    task_free_titledb(item);
                    linked_list_iter_remove(&iter);
                }
            }
        } else {
            res = R_APP_BAD_DATA;
        }

        json_decref(root);
    }

    data->itemsListed = true;

    if(R_SUCCEEDED(res)) {
        linked_list_iter iter;
        linked_list_iterate(&titles, &iter);

        while(linked_list_iter_has_next(&iter)) {
            svcWaitSynchronization(task_get_pause_event(), U64_MAX);

            Handle events[2] = {data->resumeEvent, data->cancelEvent};
            s32 index = 0;
            svcWaitSynchronizationN(&index, events, 2, false, U64_MAX);

            if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                break;
            }

            list_item* item = (list_item*) linked_list_iter_next(&iter);
            titledb_info* titledbInfo = (titledb_info*) item->data;

            char url[128];
            if(titledbInfo->cia.exists) {
                snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id);
            } else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) {
                snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id);
            } else {
                continue;
            }

            u8 icon[0x1200];
            u32 iconSize = 0;
            if(R_SUCCEEDED(http_download(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) {
                titledbInfo->meta.texture = screen_allocate_free_texture();
                screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false);
            }
        }
    }

    linked_list_destroy(&titles);

    svcCloseHandle(data->resumeEvent);
    svcCloseHandle(data->cancelEvent);

    data->result = res;
    data->finished = true;
}
Example #5
0
static void task_capture_cam_thread(void* arg) {
    capture_cam_data* data = (capture_cam_data*) arg;

    Handle events[EVENT_COUNT] = {0};
    events[EVENT_CANCEL] = data->cancelEvent;

    Result res = 0;

    u32 bufferSize = data->width * data->height * sizeof(u16);
    u16* buffer = (u16*) calloc(1, bufferSize);
    if(buffer != NULL) {
        if(R_SUCCEEDED(res = camInit())) {
            u32 cam = data->camera == CAMERA_OUTER ? SELECT_OUT1 : SELECT_IN1;

            if(R_SUCCEEDED(res = CAMU_SetSize(cam, SIZE_CTR_TOP_LCD, CONTEXT_A))
               && R_SUCCEEDED(res = CAMU_SetOutputFormat(cam, OUTPUT_RGB_565, CONTEXT_A))
               && R_SUCCEEDED(res = CAMU_SetFrameRate(cam, FRAME_RATE_30))
               && R_SUCCEEDED(res = CAMU_SetNoiseFilter(cam, true))
               && R_SUCCEEDED(res = CAMU_SetAutoExposure(cam, true))
               && R_SUCCEEDED(res = CAMU_SetAutoWhiteBalance(cam, true))
               && R_SUCCEEDED(res = CAMU_Activate(cam))) {
                u32 transferUnit = 0;

                if(R_SUCCEEDED(res = CAMU_GetBufferErrorInterruptEvent(&events[EVENT_BUFFER_ERROR], PORT_CAM1))
                   && R_SUCCEEDED(res = CAMU_SetTrimming(PORT_CAM1, true))
                   && R_SUCCEEDED(res = CAMU_SetTrimmingParamsCenter(PORT_CAM1, data->width, data->height, 400, 240))
                   && R_SUCCEEDED(res = CAMU_GetMaxBytes(&transferUnit, data->width, data->height))
                   && R_SUCCEEDED(res = CAMU_SetTransferBytes(PORT_CAM1, transferUnit, data->width, data->height))
                   && R_SUCCEEDED(res = CAMU_ClearBuffer(PORT_CAM1))
                   && R_SUCCEEDED(res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit))
                   && R_SUCCEEDED(res = CAMU_StartCapture(PORT_CAM1))) {
                    bool cancelRequested = false;
                    while(!task_is_quit_all() && !cancelRequested && R_SUCCEEDED(res)) {
                        svcWaitSynchronization(task_get_pause_event(), U64_MAX);

                        s32 index = 0;
                        if(R_SUCCEEDED(res = svcWaitSynchronizationN(&index, events, EVENT_COUNT, false, U64_MAX))) {
                            switch(index) {
                                case EVENT_CANCEL:
                                    cancelRequested = true;
                                    break;
                                case EVENT_RECV:
                                    svcCloseHandle(events[EVENT_RECV]);
                                    events[EVENT_RECV] = 0;

                                    svcWaitSynchronization(data->mutex, U64_MAX);
                                    memcpy(data->buffer, buffer, bufferSize);
                                    GSPGPU_FlushDataCache(data->buffer, bufferSize);
                                    svcReleaseMutex(data->mutex);

                                    res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit);
                                    break;
                                case EVENT_BUFFER_ERROR:
                                    svcCloseHandle(events[EVENT_RECV]);
                                    events[EVENT_RECV] = 0;

                                    if(R_SUCCEEDED(res = CAMU_ClearBuffer(PORT_CAM1))
                                       && R_SUCCEEDED(res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit))) {
                                        res = CAMU_StartCapture(PORT_CAM1);
                                    }

                                    break;
                                default:
                                    break;
                            }
                        }
                    }

                    CAMU_StopCapture(PORT_CAM1);

                    bool busy = false;
                    while(R_SUCCEEDED(CAMU_IsBusy(&busy, PORT_CAM1)) && busy) {
                        svcSleepThread(1000000);
                    }

                    CAMU_ClearBuffer(PORT_CAM1);
                }

                CAMU_Activate(SELECT_NONE);
            }

            camExit();
        }

        free(buffer);
    } else {
        res = R_APP_OUT_OF_MEMORY;
    }

    for(int i = 0; i < EVENT_COUNT; i++) {
        if(events[i] != 0) {
            svcCloseHandle(events[i]);
            events[i] = 0;
        }
    }

    svcCloseHandle(data->mutex);

    data->result = res;
    data->finished = true;
}