diff --git a/include/camera.h b/include/camera.h index 405bbab..ec123ac 100644 --- a/include/camera.h +++ b/include/camera.h @@ -29,10 +29,20 @@ #include "common.h" -void init_qr(void); -void exit_qr(void); +typedef struct { + u16 *camera_buffer; + u32 *texture_buffer; + Handle mutex; + volatile bool finished; + Handle cancel; + + bool capturing; + struct quirc* context; +} qr_data; + +void init_qr(EntryMode current_mode); +void exit_qr(qr_data *data); void take_picture(void); -bool scan_qr(EntryMode current_mode); Result http_get(char *url, const char *path); #endif \ No newline at end of file diff --git a/include/draw.h b/include/draw.h index e394ea8..dba47cc 100644 --- a/include/draw.h +++ b/include/draw.h @@ -88,6 +88,7 @@ void draw_preview(int preview_offset); void draw_install(InstallType type); +void draw_base_interface(void); void draw_interface(Entry_List_s* list, Instructions_s instructions); #endif \ No newline at end of file diff --git a/source/camera.c b/source/camera.c index 7cb9804..2d9889c 100644 --- a/source/camera.c +++ b/source/camera.c @@ -33,111 +33,184 @@ #include "fs.h" #include "loading.h" +/* static u32 transfer_size; static Handle event; static struct quirc* context; static u16 * camera_buf = NULL; +*/ -void init_qr(void) +void exit_qr(qr_data *data) { - camInit(); - CAMU_SetSize(SELECT_OUT1_OUT2, SIZE_CTR_TOP_LCD, CONTEXT_A); - CAMU_SetOutputFormat(SELECT_OUT1_OUT2, OUTPUT_RGB_565, CONTEXT_A); - CAMU_SetFrameRate(SELECT_OUT1_OUT2, FRAME_RATE_10); + svcSignalEvent(data->cancel); + while(!data->finished) + svcSleepThread(1000000); + data->capturing = false; - CAMU_SetNoiseFilter(SELECT_OUT1_OUT2, true); - CAMU_SetAutoExposure(SELECT_OUT1_OUT2, true); - CAMU_SetAutoWhiteBalance(SELECT_OUT1_OUT2, true); - CAMU_SetTrimming(PORT_CAM1, false); - CAMU_SetTrimming(PORT_CAM2, false); - - CAMU_GetMaxBytes(&transfer_size, 400, 240); - CAMU_SetTransferBytes(PORT_BOTH, transfer_size, 400, 240); - - CAMU_Activate(SELECT_OUT1_OUT2); - event = 0; - - CAMU_ClearBuffer(PORT_BOTH); - CAMU_SynchronizeVsyncTiming(SELECT_OUT1, SELECT_OUT2); - CAMU_StartCapture(PORT_BOTH); - - context = quirc_new(); - quirc_resize(context, 400, 240); + free(data->camera_buffer); + free(data->texture_buffer); + quirc_destroy(data->context); + free(data); } -void exit_qr(void) +void capture_cam_thread(void *arg) { - CAMU_StopCapture(PORT_BOTH); + qr_data *data = (qr_data *) arg; + Handle events[3] = {0}; + events[0] = data->cancel; + u32 transferUnit; + + u16 *buffer = calloc(1, 400 * 240 * sizeof(u16)); + camInit(); + CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A); + CAMU_SetOutputFormat(SELECT_OUT1, OUTPUT_RGB_565, CONTEXT_A); + CAMU_SetFrameRate(SELECT_OUT1, FRAME_RATE_30); + CAMU_SetNoiseFilter(SELECT_OUT1, true); + CAMU_SetAutoExposure(SELECT_OUT1, true); + CAMU_SetAutoWhiteBalance(SELECT_OUT1, true); + CAMU_Activate(SELECT_OUT1); + CAMU_GetBufferErrorInterruptEvent(&events[2], PORT_CAM1); + CAMU_SetTrimming(PORT_CAM1, false); + CAMU_GetMaxBytes(&transferUnit, 400, 240); + CAMU_SetTransferBytes(PORT_CAM1, transferUnit, 400, 240); + CAMU_ClearBuffer(PORT_CAM1); + CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), (s16) transferUnit); + CAMU_StartCapture(PORT_CAM1); + bool cancel = false; + while (!cancel) + { + s32 index = 0; + svcWaitSynchronizationN(&index, events, 3, false, U64_MAX); + switch(index) { + case 0: + cancel = true; + break; + case 1: + svcCloseHandle(events[1]); + events[1] = 0; + svcWaitSynchronization(data->mutex, U64_MAX); + memcpy(data->camera_buffer, buffer, 400 * 240 * sizeof(u16)); + GSPGPU_FlushDataCache(data->camera_buffer, 400 * 240 * sizeof(u16)); + svcReleaseMutex(data->mutex); + CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit); + break; + case 2: + svcCloseHandle(events[1]); + events[1] = 0; + CAMU_ClearBuffer(PORT_CAM1); + CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit); + 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(); - quirc_destroy(context); - free(camera_buf); - camera_buf = NULL; -} - -bool scan_qr(EntryMode current_mode) -{ - if(camera_buf == NULL) return false; - - int w; - int h; - - u8 *image = (u8*) quirc_begin(context, &w, &h); - - for (ssize_t x = 0; x < w; x++) - { - for (ssize_t y = 0; y < h; y++) - { - u16 px = camera_buf[y * 400 + x]; - image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); + free(buffer); + for(int i = 0; i < 3; i++) { + if(events[i] != 0) { + svcCloseHandle(events[i]); + events[i] = 0; } } - - quirc_end(context); - - if (quirc_count(context) > 0) - { - struct quirc_code code; - struct quirc_data data; - quirc_extract(context, 0, &code); - if (!quirc_decode(&code, &data)) - { - http_get((char*)data.payload, main_paths[current_mode]); - exit_qr(); - return true; - } - } - - return false; + svcCloseHandle(data->mutex); + data->finished = true; } -void take_picture(void) +bool start_capture_cam(qr_data *data) { - pp2d_begin_draw(GFX_TOP, GFX_LEFT); - free(camera_buf); + data->mutex = 0; + data->cancel = 0; + svcCreateEvent(&data->cancel, RESET_STICKY); + svcCreateMutex(&data->mutex, false); + if(threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, true) == NULL) + return false; + return true; +} - camera_buf = malloc(sizeof(u16) * 400 * 240 * 4); - if (camera_buf == NULL) return; +void update_qr(qr_data *data, EntryMode current_mode) +{ + hidScanInput(); + if (hidKeysDown() & KEY_R) { + exit_qr(data); + return; + } - CAMU_SetReceiving(&event, camera_buf, PORT_CAM1, 240 * 400 * 2, transfer_size); - svcWaitSynchronization(event, U64_MAX); - svcCloseHandle(event); + if (!data->capturing) { + if(start_capture_cam(data)) + data->capturing = true; + else { + exit_qr(data); + return; + } - u32 *rgba8_buf = malloc(240 * 400 * sizeof(u32)); - if (rgba8_buf == NULL) return; + } + + if (data->finished) { + exit_qr(data); + return; + } for (int i = 0; i < 240 * 400; i++) { - rgba8_buf[i] = RGB565_TO_ABGR8(camera_buf[i]); + data->texture_buffer[i] = RGB565_TO_ABGR8(data->camera_buffer[i]); } + draw_base_interface(); pp2d_free_texture(TEXTURE_QR); - pp2d_load_texture_memory(TEXTURE_QR, rgba8_buf, 400, 240); - free(rgba8_buf); + pp2d_load_texture_memory(TEXTURE_QR, data->texture_buffer, 400, 240); pp2d_draw_texture(TEXTURE_QR, 0, 0); pp2d_draw_rectangle(0, 216, 400, 24, RGBA8(55, 122, 168, 255)); pp2d_draw_text_center(GFX_TOP, 220, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE005 To Quit"); - pp2d_draw_rectangle(0, 0, 400, 24, RGBA8(55, 122, 168, 255)); - pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, RGBA8(255, 255, 255, 255), "Press \uE004 To Scan"); + pp2d_end_draw(); + + int w; + int h; + u8 *image = (u8*) quirc_begin(data->context, &w, &h); + svcWaitSynchronization(data->mutex, U64_MAX); + for (ssize_t x = 0; x < w; x++) { + for (ssize_t y = 0; y < h; y++) { + u16 px = data->camera_buffer[y * 400 + x]; + image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); + } + } + svcReleaseMutex(data->mutex); + quirc_end(data->context); + if(quirc_count(data->context) > 0) + { + struct quirc_code code; + struct quirc_data scan_data; + quirc_extract(data->context, 0, &code); + if (!quirc_decode(&code, &scan_data)) + { + exit_qr(data); + http_get((char*)scan_data.payload, main_paths[current_mode]); + } + } + +} + +void init_qr(EntryMode current_mode) +{ + qr_data *data = calloc(1, sizeof(qr_data)); + data->capturing = false; + data->finished = false; + data->context = quirc_new(); + quirc_resize(data->context, 400, 240); + + data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16)); + data->texture_buffer = calloc(1, 400 * 240 * sizeof(u32)); + + while (!data->finished) update_qr(data, current_mode); } /* diff --git a/source/draw.c b/source/draw.c index 02f2d3d..ef85393 100644 --- a/source/draw.c +++ b/source/draw.c @@ -61,7 +61,7 @@ void exit_screens(void) pp2d_exit(); } -static void draw_base_interface(void) +void draw_base_interface(void) { pp2d_begin_draw(GFX_TOP, GFX_LEFT); pp2d_draw_rectangle(0, 0, 400, 23, COLOR_ACCENT); diff --git a/source/main.c b/source/main.c index 455b161..861bc02 100644 --- a/source/main.c +++ b/source/main.c @@ -50,6 +50,7 @@ static Entry_List_s lists[MODE_AMOUNT] = {0}; int __stacksize__ = 64 * 1024; Result archive_result; +u32 old_time_limit; const char * main_paths[MODE_AMOUNT] = { "/Themes/", @@ -62,6 +63,8 @@ static void init_services(void) cfguInit(); ptmuInit(); acInit(); + APT_GetAppCpuTimeLimit(&old_time_limit); + APT_SetAppCpuTimeLimit(30); httpcInit(0); archive_result = open_archives(); if(envIsHomebrew()) @@ -77,6 +80,7 @@ static void exit_services(void) close_archives(); cfguExit(); ptmuExit(); + if (old_time_limit != UINT32_MAX) APT_SetAppCpuTimeLimit(old_time_limit); httpcExit(); acExit(); } @@ -340,22 +344,16 @@ int main(void) current_mode %= MODE_AMOUNT; continue; } - else if(!preview_mode && kDown & KEY_R) //toggle QR mode + else if(!qr_mode && !preview_mode && kDown & KEY_R) //toggle QR mode { - toggle_qr: + enable_qr: if(R_SUCCEEDED(camInit())) { camExit(); u32 out; ACU_GetWifiStatus(&out); if(out) - { - qr_mode = !qr_mode; - if(qr_mode) - init_qr(); - else - exit_qr(); - } + init_qr(current_mode); else { throw_error("Please connect to Wi-Fi before scanning QRs", ERROR_LEVEL_WARNING); @@ -377,24 +375,6 @@ int main(void) preview_mode = false; continue; } - else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode - { - CAMU_StopCapture(PORT_BOTH); - CAMU_Activate(SELECT_NONE); - qr_mode = !scan_qr(current_mode); - CAMU_Activate(SELECT_OUT1_OUT2); - CAMU_StartCapture(PORT_BOTH); - - if(!qr_mode) - load_lists(lists); - continue; - } - else if(qr_mode && kDown & KEY_B) - { - exit_qr(); - qr_mode = false; - continue; - } else if(preview_mode && kDown & (KEY_B | KEY_TOUCH)) { preview_mode = false; @@ -626,7 +606,7 @@ int main(void) } else if(BETWEEN(320-48, x, 320-24)) { - goto toggle_qr; + goto enable_qr; } else if(BETWEEN(320-72, x, 320-48)) { @@ -671,7 +651,6 @@ int main(void) } } } - exit_function(true); return 0; }