From 5b45014adf039ba645d004c52f679855af55714c Mon Sep 17 00:00:00 2001 From: eliboa Date: Fri, 11 Dec 2020 12:46:53 +0100 Subject: [PATCH] dev 2020 --- TegraRcmGUI.pro | 59 +- ariane/Versions.inc | 5 + ariane/ariane.files | 422 +- ariane/ariane.includes | 35 +- ariane/linker.ld | 154 - ariane/linker.specs | 7 - ariane/src/ariane.c | 909 ++ ariane/src/ariane.h | 83 + ariane/src/bdk/exception_handlers.S | 233 + ariane/src/bdk/fatfs_cfg.h | 24 + ariane/src/bdk/gfx/di.c | 446 + ariane/src/{hwinit => bdk/gfx}/di.h | 234 +- ariane/src/{hwinit => bdk/gfx}/di.inl | 342 +- ariane/src/bdk/gfx_utils.h | 24 + ariane/src/bdk/ianos/elfload/elf.h | 589 ++ ariane/src/bdk/ianos/elfload/elfarch.h | 49 + ariane/src/bdk/ianos/elfload/elfload.c | 324 + ariane/src/bdk/ianos/elfload/elfload.h | 127 + .../src/bdk/ianos/elfload/elfreloc_aarch64.c | 84 + ariane/src/bdk/ianos/elfload/elfreloc_arm.c | 66 + ariane/src/bdk/ianos/ianos.c | 121 + ariane/src/bdk/ianos/ianos.h | 34 + ariane/src/bdk/input/als.c | 117 + ariane/src/bdk/input/als.h | 65 + ariane/src/bdk/input/joycon.c | 872 ++ ariane/src/bdk/input/joycon.h | 98 + ariane/src/bdk/input/touch.c | 422 + ariane/src/bdk/input/touch.h | 157 + ariane/src/bdk/libs/compr/blz.c | 98 + ariane/src/bdk/libs/compr/blz.h | 36 + ariane/src/{lib => bdk/libs/compr}/lz.c | 0 ariane/src/{lib => bdk/libs/compr}/lz.h | 0 ariane/src/{lib => bdk/libs/fatfs}/diskio.h | 23 +- ariane/src/{lib => bdk/libs/fatfs}/ff.c | 699 +- ariane/src/{lib => bdk/libs/fatfs}/ff.h | 40 +- .../src/{lib => bdk/libs/fatfs}/ffunicode.c | 12 +- ariane/src/bdk/libs/lv_conf.h | 369 + .../src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md | 46 + ariane/src/bdk/libs/lvgl/docs/CONTRIBUTING.md | 103 + ariane/src/bdk/libs/lvgl/docs/astyle_c | 1 + ariane/src/bdk/libs/lvgl/docs/astyle_h | 1 + ariane/src/bdk/libs/lvgl/licence.txt | 8 + ariane/src/bdk/libs/lvgl/lv_core/lv_core.mk | 12 + ariane/src/bdk/libs/lvgl/lv_core/lv_group.c | 554 ++ ariane/src/bdk/libs/lvgl/lv_core/lv_group.h | 247 + ariane/src/bdk/libs/lvgl/lv_core/lv_indev.c | 971 ++ ariane/src/bdk/libs/lvgl/lv_core/lv_indev.h | 157 + ariane/src/bdk/libs/lvgl/lv_core/lv_lang.c | 117 + ariane/src/bdk/libs/lvgl/lv_core/lv_lang.h | 74 + ariane/src/bdk/libs/lvgl/lv_core/lv_obj.c | 1986 ++++ ariane/src/bdk/libs/lvgl/lv_core/lv_obj.h | 840 ++ ariane/src/bdk/libs/lvgl/lv_core/lv_refr.c | 614 ++ ariane/src/bdk/libs/lvgl/lv_core/lv_refr.h | 94 + ariane/src/bdk/libs/lvgl/lv_core/lv_style.c | 357 + ariane/src/bdk/libs/lvgl/lv_core/lv_style.h | 198 + ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.c | 207 + ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.h | 119 + ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.c | 163 + ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.h | 115 + ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.mk | 14 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c | 264 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h | 53 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_img.c | 759 ++ .../src/bdk/libs/lvgl/lv_draw/lv_draw_img.h | 167 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_label.c | 264 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_label.h | 53 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_line.c | 607 ++ .../src/bdk/libs/lvgl/lv_draw/lv_draw_line.h | 49 + .../bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c | 269 + .../bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h | 96 + .../src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c | 1435 +++ .../src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h | 48 + .../bdk/libs/lvgl/lv_draw/lv_draw_triangle.c | 168 + .../bdk/libs/lvgl/lv_draw/lv_draw_triangle.h | 51 + .../bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c | 691 ++ .../bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h | 89 + .../libs/lvgl/lv_fonts/hekate_symbol_120.c | 58 + .../bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c | 159 + .../bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c | 159 + .../src/bdk/libs/lvgl/lv_fonts/interui_20.c | 248 + .../src/bdk/libs/lvgl/lv_fonts/interui_30.c | 248 + .../bdk/libs/lvgl/lv_fonts/lv_font_builtin.c | 100 + .../bdk/libs/lvgl/lv_fonts/lv_font_builtin.h | 95 + ariane/src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk | 14 + .../src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c | 248 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.h | 40 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.mk | 8 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c | 242 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h | 173 + .../src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c | 135 + .../src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h | 166 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c | 100 + ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h | 65 + ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.c | 445 + ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.h | 176 + ariane/src/bdk/libs/lvgl/lv_misc/lv_area.c | 200 + ariane/src/bdk/libs/lvgl/lv_misc/lv_area.h | 168 + ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.c | 79 + ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.h | 80 + ariane/src/bdk/libs/lvgl/lv_misc/lv_color.c | 167 + ariane/src/bdk/libs/lvgl/lv_misc/lv_color.h | 455 + ariane/src/bdk/libs/lvgl/lv_misc/lv_font.c | 269 + ariane/src/bdk/libs/lvgl/lv_misc/lv_font.h | 191 + ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.c | 627 ++ ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.h | 276 + ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.c | 40 + ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.h | 75 + ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.c | 376 + ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.h | 145 + ariane/src/bdk/libs/lvgl/lv_misc/lv_log.c | 82 + ariane/src/bdk/libs/lvgl/lv_misc/lv_log.h | 86 + ariane/src/bdk/libs/lvgl/lv_misc/lv_math.c | 165 + ariane/src/bdk/libs/lvgl/lv_misc/lv_math.h | 73 + ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.c | 470 + ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.h | 127 + ariane/src/bdk/libs/lvgl/lv_misc/lv_misc.mk | 19 + .../src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h | 223 + ariane/src/bdk/libs/lvgl/lv_misc/lv_task.c | 332 + ariane/src/bdk/libs/lvgl/lv_misc/lv_task.h | 149 + ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.c | 36 + ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.h | 38 + ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.c | 793 ++ ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.h | 197 + ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.c | 516 + ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.h | 213 + ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.c | 310 + ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.h | 127 + ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.c | 429 + ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.h | 160 + ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.c | 763 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.h | 280 + ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.c | 881 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.h | 197 + .../src/bdk/libs/lvgl/lv_objx/lv_calendar.c | 1038 ++ .../src/bdk/libs/lvgl/lv_objx/lv_calendar.h | 246 + ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.c | 593 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.h | 229 + ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.c | 347 + ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.h | 174 + ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.c | 824 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.h | 262 + ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.c | 642 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.h | 163 + ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.c | 981 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.h | 286 + ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.c | 466 + ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.h | 222 + ariane/src/bdk/libs/lvgl/lv_objx/lv_img.c | 408 + ariane/src/bdk/libs/lvgl/lv_objx/lv_img.h | 195 + ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c | 391 + ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h | 249 + ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.c | 488 + ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.h | 216 + ariane/src/bdk/libs/lvgl/lv_objx/lv_label.c | 987 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_label.h | 295 + ariane/src/bdk/libs/lvgl/lv_objx/lv_led.c | 244 + ariane/src/bdk/libs/lvgl/lv_objx/lv_led.h | 116 + ariane/src/bdk/libs/lvgl/lv_objx/lv_line.c | 301 + ariane/src/bdk/libs/lvgl/lv_objx/lv_line.h | 158 + ariane/src/bdk/libs/lvgl/lv_objx/lv_list.c | 1052 +++ ariane/src/bdk/libs/lvgl/lv_objx/lv_list.h | 336 + ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.c | 382 + ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.h | 153 + ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.c | 532 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.h | 221 + ariane/src/bdk/libs/lvgl/lv_objx/lv_objx.mk | 36 + .../src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c | 231 + .../src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h | 111 + ariane/src/bdk/libs/lvgl/lv_objx/lv_page.c | 1205 +++ ariane/src/bdk/libs/lvgl/lv_objx/lv_page.h | 402 + ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.c | 411 + ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.h | 168 + ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.c | 582 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.h | 224 + ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.c | 520 + ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.h | 202 + ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.c | 471 + ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.h | 201 + ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.c | 445 + ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.h | 194 + ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.c | 1365 +++ ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.h | 390 + ariane/src/bdk/libs/lvgl/lv_objx/lv_table.c | 855 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_table.h | 261 + ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.c | 909 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.h | 252 + .../src/bdk/libs/lvgl/lv_objx/lv_tileview.c | 578 ++ .../src/bdk/libs/lvgl/lv_objx/lv_tileview.h | 163 + ariane/src/bdk/libs/lvgl/lv_objx/lv_win.c | 591 ++ ariane/src/bdk/libs/lvgl/lv_objx/lv_win.h | 298 + ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.c | 112 + ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.h | 343 + .../bdk/libs/lvgl/lv_themes/lv_theme_hekate.c | 909 ++ .../bdk/libs/lvgl/lv_themes/lv_theme_hekate.h | 71 + .../src/bdk/libs/lvgl/lv_themes/lv_themes.mk | 9 + ariane/src/bdk/libs/lvgl/lv_version.h | 66 + ariane/src/bdk/libs/lvgl/lvgl.h | 85 + ariane/src/bdk/libs/lvgl/lvgl.mk | 8 + ariane/src/bdk/mem/emc.h | 693 ++ ariane/src/bdk/mem/heap.c | 177 + ariane/src/bdk/mem/heap.h | 51 + ariane/src/bdk/mem/mc.c | 160 + ariane/src/bdk/mem/mc.h | 30 + ariane/src/bdk/mem/mc_t210.h | 516 + ariane/src/bdk/mem/minerva.c | 147 + ariane/src/bdk/mem/minerva.h | 65 + .../{minerva_tc/mtc => bdk/mem}/mtc_table.h | 8 +- ariane/src/bdk/mem/sdram.c | 805 ++ ariane/src/bdk/mem/sdram.h | 29 + ariane/src/bdk/mem/sdram_config.inl | 706 ++ ariane/src/bdk/mem/sdram_config_lz.inl | 124 + ariane/src/{hwinit => bdk/mem}/sdram_lp0.c | 17 +- ariane/src/bdk/mem/sdram_lp0_param_t210.h | 964 ++ ariane/src/bdk/mem/sdram_param_t210.h | 930 ++ ariane/src/bdk/mem/smmu.c | 171 + ariane/src/bdk/mem/smmu.h | 82 + ariane/src/bdk/memory_map.h | 101 + ariane/src/bdk/module.h | 41 + ariane/src/bdk/power/bq24193.c | 178 + ariane/src/bdk/power/bq24193.h | 121 + ariane/src/bdk/power/max17050.c | 279 + ariane/src/bdk/power/max17050.h | 135 + ariane/src/bdk/power/max77620.h | 340 + ariane/src/bdk/power/max7762x.c | 177 + ariane/src/{hwinit => bdk/power}/max7762x.h | 58 +- ariane/src/bdk/power/regulator_5v.c | 76 + ariane/src/bdk/power/regulator_5v.h | 34 + ariane/src/bdk/rtc/max77620-rtc.c | 147 + ariane/src/bdk/rtc/max77620-rtc.h | 77 + ariane/src/bdk/sec/se.c | 491 + ariane/src/bdk/sec/se.h | 37 + ariane/src/bdk/sec/se_t210.h | 391 + ariane/src/bdk/sec/tsec.c | 290 + ariane/src/{hwinit/util.h => bdk/sec/tsec.h} | 22 +- ariane/src/bdk/sec/tsec_t210.h | 50 + ariane/src/bdk/soc/bpmp.c | 308 + ariane/src/bdk/soc/bpmp.h | 68 + ariane/src/bdk/soc/ccplex.c | 140 + ariane/src/bdk/soc/ccplex.h | 24 + ariane/src/bdk/soc/clock.c | 716 ++ ariane/src/bdk/soc/clock.h | 224 + ariane/src/bdk/soc/fuse.c | 357 + ariane/src/bdk/soc/fuse.h | 87 + ariane/src/bdk/soc/gpio.c | 168 + ariane/src/{hwinit => bdk/soc}/gpio.h | 62 +- ariane/src/bdk/soc/hw_init.c | 365 + ariane/src/bdk/soc/hw_init.h | 26 + ariane/src/bdk/soc/i2c.c | 172 + ariane/src/bdk/soc/i2c.h | 48 + ariane/src/bdk/soc/irq.c | 263 + ariane/src/bdk/soc/irq.h | 222 + ariane/src/bdk/soc/kfuse.c | 51 + ariane/src/bdk/soc/kfuse.h | 42 + ariane/src/bdk/soc/pinmux.c | 32 + ariane/src/bdk/soc/pinmux.h | 109 + ariane/src/bdk/soc/pmc.h | 87 + ariane/src/bdk/soc/pmc_lp0_t210.h | 564 ++ ariane/src/bdk/soc/t210.h | 288 + ariane/src/bdk/soc/uart.c | 169 + ariane/src/{hwinit => bdk/soc}/uart.h | 42 +- ariane/src/bdk/storage/mbr_gpt.h | 84 + ariane/src/{hwinit => bdk/storage}/mmc.h | 46 +- ariane/src/bdk/storage/nx_sd.h | 58 + ariane/src/bdk/storage/ramdisk.c | 67 + ariane/src/bdk/storage/ramdisk.h | 30 + ariane/src/{hwinit => bdk/storage}/sd.h | 29 +- ariane/src/{hwinit => bdk/storage}/sdmmc.c | 538 +- ariane/src/{hwinit => bdk/storage}/sdmmc.h | 57 +- ariane/src/bdk/storage/sdmmc_driver.c | 1302 +++ ariane/src/bdk/storage/sdmmc_driver.h | 262 + ariane/src/bdk/storage/sdmmc_t210.h | 108 + ariane/src/bdk/thermal/fan.c | 106 + ariane/src/bdk/thermal/fan.h | 29 + ariane/src/bdk/thermal/tmp451.c | 65 + ariane/src/bdk/thermal/tmp451.h | 42 + ariane/src/bdk/usb/usb_descriptors.h | 752 ++ ariane/src/bdk/usb/usb_gadget_hid.c | 432 + ariane/src/bdk/usb/usb_gadget_ums.c | 1891 ++++ ariane/src/bdk/usb/usb_t210.h | 172 + ariane/src/bdk/usb/usbd.c | 1696 ++++ ariane/src/bdk/usb/usbd.h | 86 + ariane/src/bdk/utils/aarch64_util.h | 37 + ariane/src/bdk/utils/btn.c | 114 + ariane/src/bdk/utils/btn.h | 34 + ariane/src/bdk/utils/dirlist.c | 100 + ariane/src/bdk/utils/dirlist.h | 19 + ariane/src/bdk/utils/ini.c | 189 + ariane/src/bdk/utils/ini.h | 50 + ariane/src/bdk/utils/list.h | 97 + ariane/src/bdk/utils/sprintf.c | 149 + .../{hwinit/tsec.h => bdk/utils/sprintf.h} | 12 +- .../src/{minerva_tc/mtc => bdk/utils}/types.h | 63 +- ariane/src/bdk/utils/util.c | 167 + ariane/src/bdk/utils/util.h | 78 + ariane/src/cbmem.c | 390 - ariane/src/cbmem.h | 70 - ariane/src/display/cfb_console.c | 1637 ---- ariane/src/display/video_fb.h | 59 - ariane/src/display/video_font_large.h | 6181 ------------ ariane/src/display/video_font_small.h | 4630 --------- ariane/src/{lib => }/ffconf.h | 43 +- ariane/src/fuse.c | 236 - ariane/src/fuse.h | 197 - ariane/src/gfx/gfx.c | 539 ++ ariane/src/gfx/gfx.h | 72 + ariane/src/gfx/gfx_save.c | 538 ++ ariane/src/gfx/gfx_save.h | 84 + ariane/src/gfx/logos.h | 335 + ariane/src/hwinit/btn.c | 75 - ariane/src/hwinit/btn.h | 30 - ariane/src/hwinit/carveout.c | 381 - ariane/src/hwinit/carveout.h | 50 - ariane/src/hwinit/clock.c | 435 - ariane/src/hwinit/clock.h | 490 - ariane/src/hwinit/cluster.c | 143 - ariane/src/hwinit/cluster.h | 24 - ariane/src/hwinit/di.c | 209 - ariane/src/hwinit/emc.h | 471 - ariane/src/hwinit/flow.h | 98 - ariane/src/hwinit/fuse.c | 28 - ariane/src/hwinit/fuse.h | 44 - ariane/src/hwinit/gpio.c | 94 - ariane/src/hwinit/hwinit.c | 278 - ariane/src/hwinit/hwinit.h | 26 - ariane/src/hwinit/i2c.c | 132 - ariane/src/hwinit/i2c.h | 35 - ariane/src/hwinit/kfuse.c | 42 - ariane/src/hwinit/kfuse.h | 41 - ariane/src/hwinit/max77620.h | 328 - ariane/src/hwinit/max7762x.c | 166 - ariane/src/hwinit/mc.c | 149 - ariane/src/hwinit/mc.h | 12 - ariane/src/hwinit/mc_t210.h | 226 - ariane/src/hwinit/mtc.c | 236 - ariane/src/hwinit/mtc.h | 10 - ariane/src/hwinit/pinmux.c | 100 - ariane/src/hwinit/pinmux.h | 297 - ariane/src/hwinit/pmc.h | 719 -- ariane/src/hwinit/sdmmc_driver.c | 1111 --- ariane/src/hwinit/sdmmc_driver.h | 126 - ariane/src/hwinit/sdmmc_t210.h | 132 - ariane/src/hwinit/sdram.c | 1113 --- ariane/src/hwinit/sdram.h | 28 - ariane/src/hwinit/sdram_lz4.inl | 67 - ariane/src/hwinit/sdram_param_t210.h | 971 -- ariane/src/hwinit/t210.h | 118 - ariane/src/hwinit/timer.c | 49 - ariane/src/hwinit/timer.h | 36 - ariane/src/hwinit/tsec.c | 165 - ariane/src/hwinit/types.h | 54 - ariane/src/hwinit/uart.c | 94 - ariane/src/hwinit/util.c | 41 - ariane/src/lib/crc32.c | 28 - ariane/src/lib/crc32.h | 6 - ariane/src/lib/decomp.h | 35 - ariane/src/lib/diskio.c | 55 - ariane/src/lib/heap.c | 136 - ariane/src/lib/heap.h | 27 - ariane/src/lib/integer.h | 38 - ariane/src/lib/lz4.c.inc | 280 - ariane/src/lib/lz4_wrapper.c | 208 - ariane/src/lib/lzma.c | 59 - ariane/src/lib/lzmadecode.c | 431 - ariane/src/lib/lzmadecode.h | 65 - ariane/src/lib/printk.c | 62 - ariane/src/lib/printk.h | 12 - ariane/src/lib/vsprintf.c | 1676 ---- ariane/src/lib/vsprintf.h | 28 - ariane/src/libs/fatfs/diskio.c | 147 + ariane/src/libs/fatfs/ffconf.h | 296 + ariane/src/{lib => libs/fatfs}/ffsystem.c | 41 +- ariane/src/libs/hekate_config.c | 647 ++ ariane/src/libs/hekate_config.h | 56 + ariane/src/libs/hos/fss.c | 247 + ariane/src/libs/hos/fss.h | 34 + ariane/src/libs/hos/hos.c | 673 ++ ariane/src/libs/hos/hos.h | 105 + ariane/src/libs/hos/pkg1.c | 112 + ariane/src/libs/hos/pkg1.h | 52 + ariane/src/libs/hos/pkg2.c | 227 + ariane/src/libs/hos/pkg2.h | 99 + ariane/src/libs/hos/sept.c | 236 + ariane/src/libs/hos/sept.h | 25 + ariane/src/link.ld | 25 + ariane/src/logo.h | 824 ++ ariane/src/main.c | 910 +- ariane/src/minerva_tc/LICENSE | 339 - ariane/src/minerva_tc/README.md | 23 - ariane/src/minerva_tc/mtc/mtc.c | 4018 -------- ariane/src/minerva_tc/mtc/mtc.h | 141 - ariane/src/minerva_tc/mtc/mtc_mc_emc_regs.h | 626 -- ...x_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin | Bin 49280 -> 0 bytes ...x_abca2_2_0_10NoCfgVersion_V9.8.7_V1.6.bin | Bin 49280 -> 0 bytes ...x_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin | Bin 49280 -> 0 bytes ...x_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin | Bin 49280 -> 0 bytes ...x_abca2_1_0_10NoCfgVersion_V9.8.7_V1.6.bin | Bin 49280 -> 0 bytes ariane/src/panic_color.h | 23 - ariane/src/rcm_usb.c | 8 +- ariane/src/rcm_usb.h | 2 +- ariane/src/start.s | 125 +- ariane/src/storage.c | 20 - ariane/src/storage.h | 9 - ariane/src/storage/emummc.c | 315 + ariane/src/storage/emummc.h | 62 + ariane/src/storage/nx_emmc.c | 85 + ariane/src/storage/nx_emmc.h | 49 + ariane/src/storage/nx_emmc_bis.c | 232 + ariane/src/storage/nx_emmc_bis.h | 229 + ariane/src/storage/nx_sd.c | 237 + ariane/src/usb_command.h | 45 +- ariane/src/usb_output.h | 31 - ariane/src/utils.c | 48 - ariane/src/utils.h | 79 - kourou/.gitignore | 73 + kourou/kourou.cpp | 327 +- kourou/kourou.h | 46 +- kourou/kourou.pro | 37 + kourou/libs/rcm_device.cpp | 75 +- kourou/libs/rcm_device.h | 2 +- kourou/libs/tegrarcm/aes-cmac.cpp | 89 - kourou/libs/tegrarcm/aes-cmac.h | 42 - kourou/libs/tegrarcm/debug.c | 44 - kourou/libs/tegrarcm/debug.h | 55 - .../tegrarcm/miniloader/tegra20-miniloader.h | 8323 ----------------- kourou/libs/tegrarcm/nv3p.c | 830 -- kourou/libs/tegrarcm/nv3p.h | 196 - kourou/libs/tegrarcm/nv3p_status.h | 66 - kourou/libs/tegrarcm/rcm.c | 400 - kourou/libs/tegrarcm/rcm.h | 134 - kourou/libs/tegrarcm/rsa-pss.cpp | 163 - kourou/libs/tegrarcm/rsa-pss.h | 46 - kourou/libs/tegrarcm/usb.c | 353 - kourou/libs/tegrarcm/usb.h | 73 - kourou/main.cpp | 210 + kourou/usb_command.h | 60 +- languages/tegrarcmgui_fr.ts | 399 +- libs/libusbK/bin/lib/amd64/libusbK.lib | Bin 0 -> 23804 bytes libs/libusbK/bin/lib/static/amd64/libusbK.lib | Bin 0 -> 1427362 bytes libs/libusbK/bin/lib/static/ia64/libusbK.lib | Bin 0 -> 1437590 bytes libs/libusbK/bin/lib/static/x86/libusbK.lib | Bin 0 -> 1079964 bytes libs/libusbK/bin/lib/x86/libusbK.lib | Bin 0 -> 25672 bytes libs/libusbK/includes/libusbk.h | 4000 ++++++++ libs/libusbK/includes/lusbk_dynapi.c | 1915 ++++ libs/libusbK/includes/lusbk_shared.h | 309 + libs/libusbK/license/AUTHORS-libusb0.txt | 20 + libs/libusbK/license/AUTHORS-libusbK.txt | 40 + libs/libusbK/license/LICENSE-bsd.txt | 33 + libs/libusbK/license/LICENSE-gpl3.txt | 686 ++ libs/libusbK/license/LICENSE-lgpl3.txt | 165 + libs/zip_libs/include/JlCompress.h | 197 + libs/zip_libs/include/crc32.h | 441 + libs/zip_libs/include/crypt.h | 135 + libs/zip_libs/include/deflate.h | 349 + libs/zip_libs/include/gzguts.h | 218 + libs/zip_libs/include/inffast.h | 11 + libs/zip_libs/include/inffixed.h | 94 + libs/zip_libs/include/inflate.h | 125 + libs/zip_libs/include/inftrees.h | 62 + libs/zip_libs/include/ioapi.h | 207 + libs/zip_libs/include/quaadler32.h | 54 + libs/zip_libs/include/quachecksum32.h | 78 + libs/zip_libs/include/quacrc32.h | 50 + libs/zip_libs/include/quagzipfile.h | 108 + libs/zip_libs/include/quaziodevice.h | 102 + libs/zip_libs/include/quazip.h | 571 ++ libs/zip_libs/include/quazip_global.h | 59 + libs/zip_libs/include/quazipdir.h | 223 + libs/zip_libs/include/quazipfile.h | 456 + libs/zip_libs/include/quazipfileinfo.h | 178 + libs/zip_libs/include/quazipnewinfo.h | 207 + libs/zip_libs/include/trees.h | 128 + libs/zip_libs/include/unzip.h | 458 + libs/zip_libs/include/zconf.h | 534 ++ libs/zip_libs/include/zip.h | 390 + libs/zip_libs/include/zlib.h | 1912 ++++ libs/zip_libs/include/zutil.h | 271 + main.cpp | 5 +- packagemanager.cpp | 174 + packagemanager.h | 103 + packagemanager.ui | 54 + packages.cpp | 497 + packages.h | 143 + qerror.h | 84 + qhekate.cpp | 304 + qhekate.h | 98 + qhekate.ui | 148 + qkourou.cpp | 239 +- qkourou.h | 29 +- qobjects/custombutton.cpp | 85 + qobjects/custombutton.h | 46 + qobjects/hekate_ini.cpp | 292 + qobjects/hekate_ini.h | 87 + qpayload.cpp | 121 +- qpayload.h | 9 +- qpayload.ui | 78 +- qprogress_widget.cpp | 77 + qprogress_widget.h | 39 + qprogress_widget.ui | 85 + qresources.qrc | 7 + qsettings.cpp | 29 +- qsettings.h | 7 + qsettings.ui | 205 +- qtools.cpp | 8 +- qtools.ui | 90 +- qutils.cpp | 72 + qutils.h | 67 +- res/Badge_label.qss | 11 + res/Badge_value.qss | 11 + res/ProgressWidget.qss | 18 + res/QFrame_box01.qss | 12 +- res/QFrame_box02.qss | 4 +- res/QLabel_title01.qss | 2 +- res/QLabel_warning.qss | 2 +- res/QMainWindow.qss | 80 +- res/QPushButton.qss | 1 + res/QPushButton_light.qss | 20 + res/QTabWidget.qss | 4 +- res/QTableView.qss | 8 + res/QTableWidget.qss | 21 + res/loader_bg000000.gif | Bin 0 -> 1924 bytes res/loader_bg646464.gif | Bin 0 -> 1924 bytes res/loader_bgFFFFFF.gif | Bin 0 -> 1924 bytes res/logo-v-2.blz | Bin 0 -> 17420 bytes res/logo-v-2.bmp | Bin 0 -> 80696 bytes res/logo-v-2.rgb | Bin 0 -> 120960 bytes res/logo-v-3.blz | Bin 0 -> 9732 bytes res/logo-v-3.bmp | Bin 0 -> 46456 bytes res/logo-v-3.rgb | Bin 0 -> 68400 bytes res/logo-v.blz | Bin 0 -> 22004 bytes res/logo-v.bmp | Bin 0 -> 106296 bytes res/logo-v.rgb | Bin 0 -> 158400 bytes res/logo.blz | Bin 0 -> 5304 bytes res/logo.bmp | Bin 0 -> 21678 bytes res/logo.bmp.c | 233 + res/logo.bmp.lzma | Bin 0 -> 3076 bytes res/logo.bmp.lzma.bck | Bin 0 -> 2731 bytes res/logo2.bmp | Bin 0 -> 11112 bytes res/logov.blz | Bin 0 -> 5040 bytes res/logov.bmp | Bin 0 -> 21878 bytes res/logov.bmp.rawdata | Bin 0 -> 20800 bytes res/logov.rgb | 57 + res/logov2.bmp | Bin 0 -> 21878 bytes res/logov3.bmp | Bin 0 -> 21878 bytes res/packages.json | 38 + res/pix.bmp | Bin 0 -> 58 bytes res/pix.rgb | Bin 0 -> 3 bytes res/switch_logo_black.png | Bin 0 -> 14732 bytes tegrarcmgui.cpp | 281 +- tegrarcmgui.h | 23 +- tegrarcmgui.ui | 414 +- types.h | 2 + update_manager/github_api.cpp | 112 + update_manager/github_api.h | 34 + update_manager/um_dialog.cpp | 14 + update_manager/um_dialog.h | 22 + update_manager/um_dialog.ui | 21 + update_manager/update_manager.cpp | 6 + update_manager/update_manager.h | 17 + 558 files changed, 106210 insertions(+), 44815 deletions(-) create mode 100644 ariane/Versions.inc delete mode 100644 ariane/linker.ld delete mode 100644 ariane/linker.specs create mode 100644 ariane/src/ariane.c create mode 100644 ariane/src/ariane.h create mode 100644 ariane/src/bdk/exception_handlers.S create mode 100644 ariane/src/bdk/fatfs_cfg.h create mode 100644 ariane/src/bdk/gfx/di.c rename ariane/src/{hwinit => bdk/gfx}/di.h (54%) rename ariane/src/{hwinit => bdk/gfx}/di.inl (58%) create mode 100644 ariane/src/bdk/gfx_utils.h create mode 100644 ariane/src/bdk/ianos/elfload/elf.h create mode 100644 ariane/src/bdk/ianos/elfload/elfarch.h create mode 100644 ariane/src/bdk/ianos/elfload/elfload.c create mode 100644 ariane/src/bdk/ianos/elfload/elfload.h create mode 100644 ariane/src/bdk/ianos/elfload/elfreloc_aarch64.c create mode 100644 ariane/src/bdk/ianos/elfload/elfreloc_arm.c create mode 100644 ariane/src/bdk/ianos/ianos.c create mode 100644 ariane/src/bdk/ianos/ianos.h create mode 100644 ariane/src/bdk/input/als.c create mode 100644 ariane/src/bdk/input/als.h create mode 100644 ariane/src/bdk/input/joycon.c create mode 100644 ariane/src/bdk/input/joycon.h create mode 100644 ariane/src/bdk/input/touch.c create mode 100644 ariane/src/bdk/input/touch.h create mode 100644 ariane/src/bdk/libs/compr/blz.c create mode 100644 ariane/src/bdk/libs/compr/blz.h rename ariane/src/{lib => bdk/libs/compr}/lz.c (100%) rename ariane/src/{lib => bdk/libs/compr}/lz.h (100%) rename ariane/src/{lib => bdk/libs/fatfs}/diskio.h (79%) rename ariane/src/{lib => bdk/libs/fatfs}/ff.c (92%) rename ariane/src/{lib => bdk/libs/fatfs}/ff.h (92%) rename ariane/src/{lib => bdk/libs/fatfs}/ffunicode.c (99%) create mode 100644 ariane/src/bdk/libs/lv_conf.h create mode 100644 ariane/src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md create mode 100644 ariane/src/bdk/libs/lvgl/docs/CONTRIBUTING.md create mode 100644 ariane/src/bdk/libs/lvgl/docs/astyle_c create mode 100644 ariane/src/bdk/libs/lvgl/docs/astyle_h create mode 100644 ariane/src/bdk/libs/lvgl/licence.txt create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_core.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_group.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_group.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_indev.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_indev.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_lang.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_lang.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_obj.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_obj.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_refr.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_refr.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_style.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_style.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/interui_20.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/interui_30.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_area.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_area.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_color.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_color.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_font.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_font.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_log.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_log.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_math.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_math.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_misc.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_task.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_task.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_img.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_img.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_label.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_label.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_led.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_led.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_line.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_line.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_list.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_list.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_objx.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_page.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_page.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_table.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_table.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_win.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_objx/lv_win.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c create mode 100644 ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h create mode 100644 ariane/src/bdk/libs/lvgl/lv_themes/lv_themes.mk create mode 100644 ariane/src/bdk/libs/lvgl/lv_version.h create mode 100644 ariane/src/bdk/libs/lvgl/lvgl.h create mode 100644 ariane/src/bdk/libs/lvgl/lvgl.mk create mode 100644 ariane/src/bdk/mem/emc.h create mode 100644 ariane/src/bdk/mem/heap.c create mode 100644 ariane/src/bdk/mem/heap.h create mode 100644 ariane/src/bdk/mem/mc.c create mode 100644 ariane/src/bdk/mem/mc.h create mode 100644 ariane/src/bdk/mem/mc_t210.h create mode 100644 ariane/src/bdk/mem/minerva.c create mode 100644 ariane/src/bdk/mem/minerva.h rename ariane/src/{minerva_tc/mtc => bdk/mem}/mtc_table.h (99%) create mode 100644 ariane/src/bdk/mem/sdram.c create mode 100644 ariane/src/bdk/mem/sdram.h create mode 100644 ariane/src/bdk/mem/sdram_config.inl create mode 100644 ariane/src/bdk/mem/sdram_config_lz.inl rename ariane/src/{hwinit => bdk/mem}/sdram_lp0.c (99%) create mode 100644 ariane/src/bdk/mem/sdram_lp0_param_t210.h create mode 100644 ariane/src/bdk/mem/sdram_param_t210.h create mode 100644 ariane/src/bdk/mem/smmu.c create mode 100644 ariane/src/bdk/mem/smmu.h create mode 100644 ariane/src/bdk/memory_map.h create mode 100644 ariane/src/bdk/module.h create mode 100644 ariane/src/bdk/power/bq24193.c create mode 100644 ariane/src/bdk/power/bq24193.h create mode 100644 ariane/src/bdk/power/max17050.c create mode 100644 ariane/src/bdk/power/max17050.h create mode 100644 ariane/src/bdk/power/max77620.h create mode 100644 ariane/src/bdk/power/max7762x.c rename ariane/src/{hwinit => bdk/power}/max7762x.h (70%) create mode 100644 ariane/src/bdk/power/regulator_5v.c create mode 100644 ariane/src/bdk/power/regulator_5v.h create mode 100644 ariane/src/bdk/rtc/max77620-rtc.c create mode 100644 ariane/src/bdk/rtc/max77620-rtc.h create mode 100644 ariane/src/bdk/sec/se.c create mode 100644 ariane/src/bdk/sec/se.h create mode 100644 ariane/src/bdk/sec/se_t210.h create mode 100644 ariane/src/bdk/sec/tsec.c rename ariane/src/{hwinit/util.h => bdk/sec/tsec.h} (70%) create mode 100644 ariane/src/bdk/sec/tsec_t210.h create mode 100644 ariane/src/bdk/soc/bpmp.c create mode 100644 ariane/src/bdk/soc/bpmp.h create mode 100644 ariane/src/bdk/soc/ccplex.c create mode 100644 ariane/src/bdk/soc/ccplex.h create mode 100644 ariane/src/bdk/soc/clock.c create mode 100644 ariane/src/bdk/soc/clock.h create mode 100644 ariane/src/bdk/soc/fuse.c create mode 100644 ariane/src/bdk/soc/fuse.h create mode 100644 ariane/src/bdk/soc/gpio.c rename ariane/src/{hwinit => bdk/soc}/gpio.h (54%) create mode 100644 ariane/src/bdk/soc/hw_init.c create mode 100644 ariane/src/bdk/soc/hw_init.h create mode 100644 ariane/src/bdk/soc/i2c.c create mode 100644 ariane/src/bdk/soc/i2c.h create mode 100644 ariane/src/bdk/soc/irq.c create mode 100644 ariane/src/bdk/soc/irq.h create mode 100644 ariane/src/bdk/soc/kfuse.c create mode 100644 ariane/src/bdk/soc/kfuse.h create mode 100644 ariane/src/bdk/soc/pinmux.c create mode 100644 ariane/src/bdk/soc/pinmux.h create mode 100644 ariane/src/bdk/soc/pmc.h create mode 100644 ariane/src/bdk/soc/pmc_lp0_t210.h create mode 100644 ariane/src/bdk/soc/t210.h create mode 100644 ariane/src/bdk/soc/uart.c rename ariane/src/{hwinit => bdk/soc}/uart.h (60%) create mode 100644 ariane/src/bdk/storage/mbr_gpt.h rename ariane/src/{hwinit => bdk/storage}/mmc.h (95%) create mode 100644 ariane/src/bdk/storage/nx_sd.h create mode 100644 ariane/src/bdk/storage/ramdisk.c create mode 100644 ariane/src/bdk/storage/ramdisk.h rename ariane/src/{hwinit => bdk/storage}/sd.h (81%) rename ariane/src/{hwinit => bdk/storage}/sdmmc.c (72%) rename ariane/src/{hwinit => bdk/storage}/sdmmc.h (62%) create mode 100644 ariane/src/bdk/storage/sdmmc_driver.c create mode 100644 ariane/src/bdk/storage/sdmmc_driver.h create mode 100644 ariane/src/bdk/storage/sdmmc_t210.h create mode 100644 ariane/src/bdk/thermal/fan.c create mode 100644 ariane/src/bdk/thermal/fan.h create mode 100644 ariane/src/bdk/thermal/tmp451.c create mode 100644 ariane/src/bdk/thermal/tmp451.h create mode 100644 ariane/src/bdk/usb/usb_descriptors.h create mode 100644 ariane/src/bdk/usb/usb_gadget_hid.c create mode 100644 ariane/src/bdk/usb/usb_gadget_ums.c create mode 100644 ariane/src/bdk/usb/usb_t210.h create mode 100644 ariane/src/bdk/usb/usbd.c create mode 100644 ariane/src/bdk/usb/usbd.h create mode 100644 ariane/src/bdk/utils/aarch64_util.h create mode 100644 ariane/src/bdk/utils/btn.c create mode 100644 ariane/src/bdk/utils/btn.h create mode 100644 ariane/src/bdk/utils/dirlist.c create mode 100644 ariane/src/bdk/utils/dirlist.h create mode 100644 ariane/src/bdk/utils/ini.c create mode 100644 ariane/src/bdk/utils/ini.h create mode 100644 ariane/src/bdk/utils/list.h create mode 100644 ariane/src/bdk/utils/sprintf.c rename ariane/src/{hwinit/tsec.h => bdk/utils/sprintf.h} (79%) rename ariane/src/{minerva_tc/mtc => bdk/utils}/types.h (53%) create mode 100644 ariane/src/bdk/utils/util.c create mode 100644 ariane/src/bdk/utils/util.h delete mode 100644 ariane/src/cbmem.c delete mode 100644 ariane/src/cbmem.h delete mode 100644 ariane/src/display/cfb_console.c delete mode 100644 ariane/src/display/video_fb.h delete mode 100644 ariane/src/display/video_font_large.h delete mode 100644 ariane/src/display/video_font_small.h rename ariane/src/{lib => }/ffconf.h (93%) delete mode 100644 ariane/src/fuse.c delete mode 100644 ariane/src/fuse.h create mode 100644 ariane/src/gfx/gfx.c create mode 100644 ariane/src/gfx/gfx.h create mode 100644 ariane/src/gfx/gfx_save.c create mode 100644 ariane/src/gfx/gfx_save.h create mode 100644 ariane/src/gfx/logos.h delete mode 100644 ariane/src/hwinit/btn.c delete mode 100644 ariane/src/hwinit/btn.h delete mode 100644 ariane/src/hwinit/carveout.c delete mode 100644 ariane/src/hwinit/carveout.h delete mode 100644 ariane/src/hwinit/clock.c delete mode 100644 ariane/src/hwinit/clock.h delete mode 100644 ariane/src/hwinit/cluster.c delete mode 100644 ariane/src/hwinit/cluster.h delete mode 100644 ariane/src/hwinit/di.c delete mode 100644 ariane/src/hwinit/emc.h delete mode 100644 ariane/src/hwinit/flow.h delete mode 100644 ariane/src/hwinit/fuse.c delete mode 100644 ariane/src/hwinit/fuse.h delete mode 100644 ariane/src/hwinit/gpio.c delete mode 100644 ariane/src/hwinit/hwinit.c delete mode 100644 ariane/src/hwinit/hwinit.h delete mode 100644 ariane/src/hwinit/i2c.c delete mode 100644 ariane/src/hwinit/i2c.h delete mode 100644 ariane/src/hwinit/kfuse.c delete mode 100644 ariane/src/hwinit/kfuse.h delete mode 100644 ariane/src/hwinit/max77620.h delete mode 100644 ariane/src/hwinit/max7762x.c delete mode 100644 ariane/src/hwinit/mc.c delete mode 100644 ariane/src/hwinit/mc.h delete mode 100644 ariane/src/hwinit/mc_t210.h delete mode 100644 ariane/src/hwinit/mtc.c delete mode 100644 ariane/src/hwinit/mtc.h delete mode 100644 ariane/src/hwinit/pinmux.c delete mode 100644 ariane/src/hwinit/pinmux.h delete mode 100644 ariane/src/hwinit/pmc.h delete mode 100644 ariane/src/hwinit/sdmmc_driver.c delete mode 100644 ariane/src/hwinit/sdmmc_driver.h delete mode 100644 ariane/src/hwinit/sdmmc_t210.h delete mode 100644 ariane/src/hwinit/sdram.c delete mode 100644 ariane/src/hwinit/sdram.h delete mode 100644 ariane/src/hwinit/sdram_lz4.inl delete mode 100644 ariane/src/hwinit/sdram_param_t210.h delete mode 100644 ariane/src/hwinit/t210.h delete mode 100644 ariane/src/hwinit/timer.c delete mode 100644 ariane/src/hwinit/timer.h delete mode 100644 ariane/src/hwinit/tsec.c delete mode 100644 ariane/src/hwinit/types.h delete mode 100644 ariane/src/hwinit/uart.c delete mode 100644 ariane/src/hwinit/util.c delete mode 100644 ariane/src/lib/crc32.c delete mode 100644 ariane/src/lib/crc32.h delete mode 100644 ariane/src/lib/decomp.h delete mode 100644 ariane/src/lib/diskio.c delete mode 100644 ariane/src/lib/heap.c delete mode 100644 ariane/src/lib/heap.h delete mode 100644 ariane/src/lib/integer.h delete mode 100644 ariane/src/lib/lz4.c.inc delete mode 100644 ariane/src/lib/lz4_wrapper.c delete mode 100644 ariane/src/lib/lzma.c delete mode 100644 ariane/src/lib/lzmadecode.c delete mode 100644 ariane/src/lib/lzmadecode.h delete mode 100644 ariane/src/lib/printk.c delete mode 100644 ariane/src/lib/printk.h delete mode 100644 ariane/src/lib/vsprintf.c delete mode 100644 ariane/src/lib/vsprintf.h create mode 100644 ariane/src/libs/fatfs/diskio.c create mode 100644 ariane/src/libs/fatfs/ffconf.h rename ariane/src/{lib => libs/fatfs}/ffsystem.c (52%) create mode 100644 ariane/src/libs/hekate_config.c create mode 100644 ariane/src/libs/hekate_config.h create mode 100644 ariane/src/libs/hos/fss.c create mode 100644 ariane/src/libs/hos/fss.h create mode 100644 ariane/src/libs/hos/hos.c create mode 100644 ariane/src/libs/hos/hos.h create mode 100644 ariane/src/libs/hos/pkg1.c create mode 100644 ariane/src/libs/hos/pkg1.h create mode 100644 ariane/src/libs/hos/pkg2.c create mode 100644 ariane/src/libs/hos/pkg2.h create mode 100644 ariane/src/libs/hos/sept.c create mode 100644 ariane/src/libs/hos/sept.h create mode 100644 ariane/src/link.ld create mode 100644 ariane/src/logo.h delete mode 100644 ariane/src/minerva_tc/LICENSE delete mode 100644 ariane/src/minerva_tc/README.md delete mode 100644 ariane/src/minerva_tc/mtc/mtc.c delete mode 100644 ariane/src/minerva_tc/mtc/mtc.h delete mode 100644 ariane/src/minerva_tc/mtc/mtc_mc_emc_regs.h delete mode 100644 ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram0_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin delete mode 100644 ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram1_nx_abca2_2_0_10NoCfgVersion_V9.8.7_V1.6.bin delete mode 100644 ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram2_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin delete mode 100644 ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram3_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin delete mode 100644 ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram4_nx_abca2_1_0_10NoCfgVersion_V9.8.7_V1.6.bin delete mode 100644 ariane/src/panic_color.h delete mode 100644 ariane/src/storage.c delete mode 100644 ariane/src/storage.h create mode 100644 ariane/src/storage/emummc.c create mode 100644 ariane/src/storage/emummc.h create mode 100644 ariane/src/storage/nx_emmc.c create mode 100644 ariane/src/storage/nx_emmc.h create mode 100644 ariane/src/storage/nx_emmc_bis.c create mode 100644 ariane/src/storage/nx_emmc_bis.h create mode 100644 ariane/src/storage/nx_sd.c delete mode 100644 ariane/src/usb_output.h delete mode 100644 ariane/src/utils.c delete mode 100644 ariane/src/utils.h create mode 100644 kourou/.gitignore create mode 100644 kourou/kourou.pro delete mode 100644 kourou/libs/tegrarcm/aes-cmac.cpp delete mode 100644 kourou/libs/tegrarcm/aes-cmac.h delete mode 100644 kourou/libs/tegrarcm/debug.c delete mode 100644 kourou/libs/tegrarcm/debug.h delete mode 100644 kourou/libs/tegrarcm/miniloader/tegra20-miniloader.h delete mode 100644 kourou/libs/tegrarcm/nv3p.c delete mode 100644 kourou/libs/tegrarcm/nv3p.h delete mode 100644 kourou/libs/tegrarcm/nv3p_status.h delete mode 100644 kourou/libs/tegrarcm/rcm.c delete mode 100644 kourou/libs/tegrarcm/rcm.h delete mode 100644 kourou/libs/tegrarcm/rsa-pss.cpp delete mode 100644 kourou/libs/tegrarcm/rsa-pss.h delete mode 100644 kourou/libs/tegrarcm/usb.c delete mode 100644 kourou/libs/tegrarcm/usb.h create mode 100644 kourou/main.cpp create mode 100644 libs/libusbK/bin/lib/amd64/libusbK.lib create mode 100644 libs/libusbK/bin/lib/static/amd64/libusbK.lib create mode 100644 libs/libusbK/bin/lib/static/ia64/libusbK.lib create mode 100644 libs/libusbK/bin/lib/static/x86/libusbK.lib create mode 100644 libs/libusbK/bin/lib/x86/libusbK.lib create mode 100644 libs/libusbK/includes/libusbk.h create mode 100644 libs/libusbK/includes/lusbk_dynapi.c create mode 100644 libs/libusbK/includes/lusbk_shared.h create mode 100644 libs/libusbK/license/AUTHORS-libusb0.txt create mode 100644 libs/libusbK/license/AUTHORS-libusbK.txt create mode 100644 libs/libusbK/license/LICENSE-bsd.txt create mode 100644 libs/libusbK/license/LICENSE-gpl3.txt create mode 100644 libs/libusbK/license/LICENSE-lgpl3.txt create mode 100644 libs/zip_libs/include/JlCompress.h create mode 100644 libs/zip_libs/include/crc32.h create mode 100644 libs/zip_libs/include/crypt.h create mode 100644 libs/zip_libs/include/deflate.h create mode 100644 libs/zip_libs/include/gzguts.h create mode 100644 libs/zip_libs/include/inffast.h create mode 100644 libs/zip_libs/include/inffixed.h create mode 100644 libs/zip_libs/include/inflate.h create mode 100644 libs/zip_libs/include/inftrees.h create mode 100644 libs/zip_libs/include/ioapi.h create mode 100644 libs/zip_libs/include/quaadler32.h create mode 100644 libs/zip_libs/include/quachecksum32.h create mode 100644 libs/zip_libs/include/quacrc32.h create mode 100644 libs/zip_libs/include/quagzipfile.h create mode 100644 libs/zip_libs/include/quaziodevice.h create mode 100644 libs/zip_libs/include/quazip.h create mode 100644 libs/zip_libs/include/quazip_global.h create mode 100644 libs/zip_libs/include/quazipdir.h create mode 100644 libs/zip_libs/include/quazipfile.h create mode 100644 libs/zip_libs/include/quazipfileinfo.h create mode 100644 libs/zip_libs/include/quazipnewinfo.h create mode 100644 libs/zip_libs/include/trees.h create mode 100644 libs/zip_libs/include/unzip.h create mode 100644 libs/zip_libs/include/zconf.h create mode 100644 libs/zip_libs/include/zip.h create mode 100644 libs/zip_libs/include/zlib.h create mode 100644 libs/zip_libs/include/zutil.h create mode 100644 packagemanager.cpp create mode 100644 packagemanager.h create mode 100644 packagemanager.ui create mode 100644 packages.cpp create mode 100644 packages.h create mode 100644 qerror.h create mode 100644 qhekate.cpp create mode 100644 qhekate.h create mode 100644 qhekate.ui create mode 100644 qobjects/custombutton.cpp create mode 100644 qobjects/custombutton.h create mode 100644 qobjects/hekate_ini.cpp create mode 100644 qobjects/hekate_ini.h create mode 100644 qprogress_widget.cpp create mode 100644 qprogress_widget.h create mode 100644 qprogress_widget.ui create mode 100644 res/Badge_label.qss create mode 100644 res/Badge_value.qss create mode 100644 res/ProgressWidget.qss create mode 100644 res/QPushButton_light.qss create mode 100644 res/QTableWidget.qss create mode 100644 res/loader_bg000000.gif create mode 100644 res/loader_bg646464.gif create mode 100644 res/loader_bgFFFFFF.gif create mode 100644 res/logo-v-2.blz create mode 100644 res/logo-v-2.bmp create mode 100644 res/logo-v-2.rgb create mode 100644 res/logo-v-3.blz create mode 100644 res/logo-v-3.bmp create mode 100644 res/logo-v-3.rgb create mode 100644 res/logo-v.blz create mode 100644 res/logo-v.bmp create mode 100644 res/logo-v.rgb create mode 100644 res/logo.blz create mode 100644 res/logo.bmp create mode 100644 res/logo.bmp.c create mode 100644 res/logo.bmp.lzma create mode 100644 res/logo.bmp.lzma.bck create mode 100644 res/logo2.bmp create mode 100644 res/logov.blz create mode 100644 res/logov.bmp create mode 100644 res/logov.bmp.rawdata create mode 100644 res/logov.rgb create mode 100644 res/logov2.bmp create mode 100644 res/logov3.bmp create mode 100644 res/packages.json create mode 100644 res/pix.bmp create mode 100644 res/pix.rgb create mode 100644 res/switch_logo_black.png create mode 100644 update_manager/github_api.cpp create mode 100644 update_manager/github_api.h create mode 100644 update_manager/um_dialog.cpp create mode 100644 update_manager/um_dialog.h create mode 100644 update_manager/um_dialog.ui create mode 100644 update_manager/update_manager.cpp create mode 100644 update_manager/update_manager.h diff --git a/TegraRcmGUI.pro b/TegraRcmGUI.pro index 849d130..bd6241a 100644 --- a/TegraRcmGUI.pro +++ b/TegraRcmGUI.pro @@ -1,4 +1,4 @@ -QT += core gui +QT += core gui network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 @@ -17,12 +17,25 @@ DEFINES += QT_DEPRECATED_WARNINGS # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +# Default config is x64 +!contains(CONFIG, ARCH64):!contains(CONFIG, ARCH32) { CONFIG += ARCH64 } + +OUT_PWD = $$OUT_PWD +STATIC_BUILD = $$find(OUT_PWD, "Static") +!isEmpty(STATIC_BUILD) { DEFINES += QUAZIP_STATIC } + SOURCES += \ kourou/kourou.cpp \ kourou/libs/rcm_device.cpp \ main.cpp \ + packagemanager.cpp \ + packages.cpp \ + qhekate.cpp \ qkourou.cpp \ + qobjects/custombutton.cpp \ + qobjects/hekate_ini.cpp \ qpayload.cpp \ + qprogress_widget.cpp \ qsettings.cpp \ qtools.cpp \ qutils.cpp \ @@ -33,40 +46,58 @@ HEADERS += \ kourou/libs/libusbk_int.h \ kourou/libs/rcm_device.h \ kourou/usb_command.h \ + packagemanager.h \ + packages.h \ + qerror.h \ + qhekate.h \ qkourou.h \ + qobjects/custombutton.h \ + qobjects/hekate_ini.h \ qpayload.h \ + qprogress_widget.h \ qsettings.h \ qtools.h \ qutils.h \ rcm_device.h \ tegrarcmgui.h \ - types.h + types.h \ FORMS += \ + packagemanager.ui \ + qhekate.ui \ qpayload.ui \ + qprogress_widget.ui \ qsettings.ui \ qtools.ui \ - tegrarcmgui.ui + tegrarcmgui.ui \ TRANSLATIONS = languages/tegrarcmgui_fr.ts -ARCH = 32 -#ARCH = 64 +# libusbK (dll) +INCLUDEPATH += $$PWD/libs/libusbK/includes +CONFIG(ARCH64) { LIBS += -L$$PWD/libs/libusbK/bin/lib/amd64/ -llibusbK } +CONFIG(ARCH32) { LIBS += -L$$PWD/libs/libusbK/bin/lib/x86/ -llibusbK } -contains( ARCH, 64 ) { - LIBS += -L$$PWD/../../../../../../../libusbK-dev-kit/bin/lib/amd64/ -llibusbK +# quazip & zlib +CMAKE_CXXFLAGS += -std=gnu++14 +INCLUDEPATH += $$PWD/libs/zip_libs/include +CONFIG(ARCH64) { + !isEmpty(STATIC_BUILD) { + LIBS += -L$$PWD/libs/zip_libs/lib_x64_static/ -lquazip -lz + } else { + LIBS += -L$$PWD/libs/zip_libs/lib_x64/ -lquazip -lz + } } -contains( ARCH, 32 ) { - LIBS += -L$$PWD/../../../../../../../libusbK-dev-kit/bin/lib/x86/ -llibusbK +CONFIG(ARCH32) { + !isEmpty(STATIC_BUILD) { + LIBS += -L$$PWD/libs/zip_libs/lib_x86_static/ -lquazip -lz + } else { + LIBS += -L$$PWD/libs/zip_libs/lib_x86/ -lquazip -lz + } } -INCLUDEPATH += $$PWD/../../../../../../../libusbK-dev-kit/includes -DEPENDPATH += $$PWD/../../../../../../../libusbK-dev-kit/includes - - LIBS += -lsetupapi RESOURCES += \ qresources.qrc -DISTFILES += diff --git a/ariane/Versions.inc b/ariane/Versions.inc new file mode 100644 index 0000000..b53c8fe --- /dev/null +++ b/ariane/Versions.inc @@ -0,0 +1,5 @@ +# IPL Version. +BLVERSION_MAJOR := 0 +BLVERSION_MINOR := 1 +BLVERSION_HOTFX := 0 +BLVERSION_RSVD := 0 diff --git a/ariane/ariane.files b/ariane/ariane.files index be1b806..e237e7c 100644 --- a/ariane/ariane.files +++ b/ariane/ariane.files @@ -1,104 +1,326 @@ -src/cbmem.c -src/cbmem.h -src/display/cfb_console.c -src/display/video_fb.h -src/display/video_font_large.h -src/display/video_font_small.h -src/fuse.c -src/fuse.h -src/hwinit/btn.c -src/hwinit/btn.h -src/hwinit/carveout.c -src/hwinit/carveout.h -src/hwinit/clock.c -src/hwinit/clock.h -src/hwinit/cluster.c -src/hwinit/cluster.h -src/hwinit/di.c -src/hwinit/di.h -src/hwinit/di.inl -src/hwinit/emc.h -src/hwinit/flow.h -src/hwinit/fuse.c -src/hwinit/fuse.h -src/hwinit/gpio.c -src/hwinit/gpio.h -src/hwinit/hwinit.c -src/hwinit/hwinit.h -src/hwinit/i2c.c -src/hwinit/i2c.h -src/hwinit/kfuse.c -src/hwinit/kfuse.h -src/hwinit/max77620.h -src/hwinit/max7762x.c -src/hwinit/max7762x.h -src/hwinit/mc.c -src/hwinit/mc.h -src/hwinit/mc_t210.h -src/hwinit/mmc.h -src/hwinit/mtc.c -src/hwinit/mtc.h -src/hwinit/pinmux.c -src/hwinit/pinmux.h -src/hwinit/pmc.h -src/hwinit/sd.h -src/hwinit/sdmmc.c -src/hwinit/sdmmc.h -src/hwinit/sdmmc_driver.c -src/hwinit/sdmmc_driver.h -src/hwinit/sdmmc_t210.h -src/hwinit/sdram.c -src/hwinit/sdram.h -src/hwinit/sdram_lp0.c -src/hwinit/sdram_lz4.inl -src/hwinit/sdram_param_t210.h -src/hwinit/t210.h -src/hwinit/timer.c -src/hwinit/timer.h -src/hwinit/tsec.c -src/hwinit/tsec.h -src/hwinit/types.h -src/hwinit/uart.c -src/hwinit/uart.h -src/hwinit/util.c -src/hwinit/util.h -src/lib/crc32.c -src/lib/crc32.h -src/lib/decomp.h -src/lib/diskio.c -src/lib/diskio.h -src/lib/ff.c -src/lib/ff.h -src/lib/ffconf.h -src/lib/ffsystem.c -src/lib/ffunicode.c -src/lib/heap.c -src/lib/heap.h -src/lib/integer.h -src/lib/lz.c -src/lib/lz.h -src/lib/lz4.c.inc -src/lib/lz4_wrapper.c -src/lib/lzma.c -src/lib/lzmadecode.c -src/lib/lzmadecode.h -src/lib/printk.c -src/lib/printk.h -src/lib/vsprintf.c -src/lib/vsprintf.h +src/ariane.c +src/ariane.h +src/bdk/exception_handlers.S +src/bdk/fatfs_cfg.h +src/bdk/gfx/di.c +src/bdk/gfx/di.h +src/bdk/gfx/di.inl +src/bdk/gfx_utils.h +src/bdk/ianos/elfload/elf.h +src/bdk/ianos/elfload/elfarch.h +src/bdk/ianos/elfload/elfload.c +src/bdk/ianos/elfload/elfload.h +src/bdk/ianos/elfload/elfreloc_aarch64.c +src/bdk/ianos/elfload/elfreloc_arm.c +src/bdk/ianos/ianos.c +src/bdk/ianos/ianos.h +src/bdk/input/als.c +src/bdk/input/als.h +src/bdk/input/joycon.c +src/bdk/input/joycon.h +src/bdk/input/touch.c +src/bdk/input/touch.h +src/bdk/libs/compr/blz.c +src/bdk/libs/compr/blz.h +src/bdk/libs/compr/lz.c +src/bdk/libs/compr/lz.h +src/bdk/libs/fatfs/diskio.h +src/bdk/libs/fatfs/ff.c +src/bdk/libs/fatfs/ff.h +src/bdk/libs/fatfs/ffunicode.c +src/bdk/libs/lv_conf.h +src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md +src/bdk/libs/lvgl/docs/CONTRIBUTING.md +src/bdk/libs/lvgl/docs/astyle_c +src/bdk/libs/lvgl/docs/astyle_h +src/bdk/libs/lvgl/licence.txt +src/bdk/libs/lvgl/lv_core/lv_core.mk +src/bdk/libs/lvgl/lv_core/lv_group.c +src/bdk/libs/lvgl/lv_core/lv_group.h +src/bdk/libs/lvgl/lv_core/lv_indev.c +src/bdk/libs/lvgl/lv_core/lv_indev.h +src/bdk/libs/lvgl/lv_core/lv_lang.c +src/bdk/libs/lvgl/lv_core/lv_lang.h +src/bdk/libs/lvgl/lv_core/lv_obj.c +src/bdk/libs/lvgl/lv_core/lv_obj.h +src/bdk/libs/lvgl/lv_core/lv_refr.c +src/bdk/libs/lvgl/lv_core/lv_refr.h +src/bdk/libs/lvgl/lv_core/lv_style.c +src/bdk/libs/lvgl/lv_core/lv_style.h +src/bdk/libs/lvgl/lv_core/lv_vdb.c +src/bdk/libs/lvgl/lv_core/lv_vdb.h +src/bdk/libs/lvgl/lv_draw/lv_draw.c +src/bdk/libs/lvgl/lv_draw/lv_draw.h +src/bdk/libs/lvgl/lv_draw/lv_draw.mk +src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c +src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h +src/bdk/libs/lvgl/lv_draw/lv_draw_img.c +src/bdk/libs/lvgl/lv_draw/lv_draw_img.h +src/bdk/libs/lvgl/lv_draw/lv_draw_label.c +src/bdk/libs/lvgl/lv_draw/lv_draw_label.h +src/bdk/libs/lvgl/lv_draw/lv_draw_line.c +src/bdk/libs/lvgl/lv_draw/lv_draw_line.h +src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c +src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h +src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c +src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h +src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c +src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h +src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c +src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h +src/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c +src/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c +src/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c +src/bdk/libs/lvgl/lv_fonts/interui_20.c +src/bdk/libs/lvgl/lv_fonts/interui_30.c +src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c +src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h +src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk +src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c +src/bdk/libs/lvgl/lv_hal/lv_hal.h +src/bdk/libs/lvgl/lv_hal/lv_hal.mk +src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c +src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h +src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c +src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h +src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c +src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h +src/bdk/libs/lvgl/lv_misc/lv_anim.c +src/bdk/libs/lvgl/lv_misc/lv_anim.h +src/bdk/libs/lvgl/lv_misc/lv_area.c +src/bdk/libs/lvgl/lv_misc/lv_area.h +src/bdk/libs/lvgl/lv_misc/lv_circ.c +src/bdk/libs/lvgl/lv_misc/lv_circ.h +src/bdk/libs/lvgl/lv_misc/lv_color.c +src/bdk/libs/lvgl/lv_misc/lv_color.h +src/bdk/libs/lvgl/lv_misc/lv_font.c +src/bdk/libs/lvgl/lv_misc/lv_font.h +src/bdk/libs/lvgl/lv_misc/lv_fs.c +src/bdk/libs/lvgl/lv_misc/lv_fs.h +src/bdk/libs/lvgl/lv_misc/lv_gc.c +src/bdk/libs/lvgl/lv_misc/lv_gc.h +src/bdk/libs/lvgl/lv_misc/lv_ll.c +src/bdk/libs/lvgl/lv_misc/lv_ll.h +src/bdk/libs/lvgl/lv_misc/lv_log.c +src/bdk/libs/lvgl/lv_misc/lv_log.h +src/bdk/libs/lvgl/lv_misc/lv_math.c +src/bdk/libs/lvgl/lv_misc/lv_math.h +src/bdk/libs/lvgl/lv_misc/lv_mem.c +src/bdk/libs/lvgl/lv_misc/lv_mem.h +src/bdk/libs/lvgl/lv_misc/lv_misc.mk +src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h +src/bdk/libs/lvgl/lv_misc/lv_task.c +src/bdk/libs/lvgl/lv_misc/lv_task.h +src/bdk/libs/lvgl/lv_misc/lv_templ.c +src/bdk/libs/lvgl/lv_misc/lv_templ.h +src/bdk/libs/lvgl/lv_misc/lv_txt.c +src/bdk/libs/lvgl/lv_misc/lv_txt.h +src/bdk/libs/lvgl/lv_misc/lv_ufs.c +src/bdk/libs/lvgl/lv_misc/lv_ufs.h +src/bdk/libs/lvgl/lv_objx/lv_arc.c +src/bdk/libs/lvgl/lv_objx/lv_arc.h +src/bdk/libs/lvgl/lv_objx/lv_bar.c +src/bdk/libs/lvgl/lv_objx/lv_bar.h +src/bdk/libs/lvgl/lv_objx/lv_btn.c +src/bdk/libs/lvgl/lv_objx/lv_btn.h +src/bdk/libs/lvgl/lv_objx/lv_btnm.c +src/bdk/libs/lvgl/lv_objx/lv_btnm.h +src/bdk/libs/lvgl/lv_objx/lv_calendar.c +src/bdk/libs/lvgl/lv_objx/lv_calendar.h +src/bdk/libs/lvgl/lv_objx/lv_canvas.c +src/bdk/libs/lvgl/lv_objx/lv_canvas.h +src/bdk/libs/lvgl/lv_objx/lv_cb.c +src/bdk/libs/lvgl/lv_objx/lv_cb.h +src/bdk/libs/lvgl/lv_objx/lv_chart.c +src/bdk/libs/lvgl/lv_objx/lv_chart.h +src/bdk/libs/lvgl/lv_objx/lv_cont.c +src/bdk/libs/lvgl/lv_objx/lv_cont.h +src/bdk/libs/lvgl/lv_objx/lv_ddlist.c +src/bdk/libs/lvgl/lv_objx/lv_ddlist.h +src/bdk/libs/lvgl/lv_objx/lv_gauge.c +src/bdk/libs/lvgl/lv_objx/lv_gauge.h +src/bdk/libs/lvgl/lv_objx/lv_img.c +src/bdk/libs/lvgl/lv_objx/lv_img.h +src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c +src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h +src/bdk/libs/lvgl/lv_objx/lv_kb.c +src/bdk/libs/lvgl/lv_objx/lv_kb.h +src/bdk/libs/lvgl/lv_objx/lv_label.c +src/bdk/libs/lvgl/lv_objx/lv_label.h +src/bdk/libs/lvgl/lv_objx/lv_led.c +src/bdk/libs/lvgl/lv_objx/lv_led.h +src/bdk/libs/lvgl/lv_objx/lv_line.c +src/bdk/libs/lvgl/lv_objx/lv_line.h +src/bdk/libs/lvgl/lv_objx/lv_list.c +src/bdk/libs/lvgl/lv_objx/lv_list.h +src/bdk/libs/lvgl/lv_objx/lv_lmeter.c +src/bdk/libs/lvgl/lv_objx/lv_lmeter.h +src/bdk/libs/lvgl/lv_objx/lv_mbox.c +src/bdk/libs/lvgl/lv_objx/lv_mbox.h +src/bdk/libs/lvgl/lv_objx/lv_objx.mk +src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c +src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h +src/bdk/libs/lvgl/lv_objx/lv_page.c +src/bdk/libs/lvgl/lv_objx/lv_page.h +src/bdk/libs/lvgl/lv_objx/lv_preload.c +src/bdk/libs/lvgl/lv_objx/lv_preload.h +src/bdk/libs/lvgl/lv_objx/lv_roller.c +src/bdk/libs/lvgl/lv_objx/lv_roller.h +src/bdk/libs/lvgl/lv_objx/lv_slider.c +src/bdk/libs/lvgl/lv_objx/lv_slider.h +src/bdk/libs/lvgl/lv_objx/lv_spinbox.c +src/bdk/libs/lvgl/lv_objx/lv_spinbox.h +src/bdk/libs/lvgl/lv_objx/lv_sw.c +src/bdk/libs/lvgl/lv_objx/lv_sw.h +src/bdk/libs/lvgl/lv_objx/lv_ta.c +src/bdk/libs/lvgl/lv_objx/lv_ta.h +src/bdk/libs/lvgl/lv_objx/lv_table.c +src/bdk/libs/lvgl/lv_objx/lv_table.h +src/bdk/libs/lvgl/lv_objx/lv_tabview.c +src/bdk/libs/lvgl/lv_objx/lv_tabview.h +src/bdk/libs/lvgl/lv_objx/lv_tileview.c +src/bdk/libs/lvgl/lv_objx/lv_tileview.h +src/bdk/libs/lvgl/lv_objx/lv_win.c +src/bdk/libs/lvgl/lv_objx/lv_win.h +src/bdk/libs/lvgl/lv_themes/lv_theme.c +src/bdk/libs/lvgl/lv_themes/lv_theme.h +src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c +src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h +src/bdk/libs/lvgl/lv_themes/lv_themes.mk +src/bdk/libs/lvgl/lv_version.h +src/bdk/libs/lvgl/lvgl.h +src/bdk/libs/lvgl/lvgl.mk +src/bdk/mem/emc.h +src/bdk/mem/heap.c +src/bdk/mem/heap.h +src/bdk/mem/mc.c +src/bdk/mem/mc.h +src/bdk/mem/mc_t210.h +src/bdk/mem/minerva.c +src/bdk/mem/minerva.h +src/bdk/mem/mtc_table.h +src/bdk/mem/sdram.c +src/bdk/mem/sdram.h +src/bdk/mem/sdram_config.inl +src/bdk/mem/sdram_config_lz.inl +src/bdk/mem/sdram_lp0.c +src/bdk/mem/sdram_lp0_param_t210.h +src/bdk/mem/sdram_param_t210.h +src/bdk/mem/smmu.c +src/bdk/mem/smmu.h +src/bdk/memory_map.h +src/bdk/module.h +src/bdk/power/bq24193.c +src/bdk/power/bq24193.h +src/bdk/power/max17050.c +src/bdk/power/max17050.h +src/bdk/power/max77620.h +src/bdk/power/max7762x.c +src/bdk/power/max7762x.h +src/bdk/power/regulator_5v.c +src/bdk/power/regulator_5v.h +src/bdk/rtc/max77620-rtc.c +src/bdk/rtc/max77620-rtc.h +src/bdk/sec/se.c +src/bdk/sec/se.h +src/bdk/sec/se_t210.h +src/bdk/sec/tsec.c +src/bdk/sec/tsec.h +src/bdk/sec/tsec_t210.h +src/bdk/soc/bpmp.c +src/bdk/soc/bpmp.h +src/bdk/soc/ccplex.c +src/bdk/soc/ccplex.h +src/bdk/soc/clock.c +src/bdk/soc/clock.h +src/bdk/soc/fuse.c +src/bdk/soc/fuse.h +src/bdk/soc/gpio.c +src/bdk/soc/gpio.h +src/bdk/soc/hw_init.c +src/bdk/soc/hw_init.h +src/bdk/soc/i2c.c +src/bdk/soc/i2c.h +src/bdk/soc/irq.c +src/bdk/soc/irq.h +src/bdk/soc/kfuse.c +src/bdk/soc/kfuse.h +src/bdk/soc/pinmux.c +src/bdk/soc/pinmux.h +src/bdk/soc/pmc.h +src/bdk/soc/pmc_lp0_t210.h +src/bdk/soc/t210.h +src/bdk/soc/uart.c +src/bdk/soc/uart.h +src/bdk/storage/mbr_gpt.h +src/bdk/storage/mmc.h +src/bdk/storage/nx_sd.h +src/bdk/storage/ramdisk.c +src/bdk/storage/ramdisk.h +src/bdk/storage/sd.h +src/bdk/storage/sdmmc.c +src/bdk/storage/sdmmc.h +src/bdk/storage/sdmmc_driver.c +src/bdk/storage/sdmmc_driver.h +src/bdk/storage/sdmmc_t210.h +src/bdk/thermal/fan.c +src/bdk/thermal/fan.h +src/bdk/thermal/tmp451.c +src/bdk/thermal/tmp451.h +src/bdk/usb/usb_descriptors.h +src/bdk/usb/usb_gadget_hid.c +src/bdk/usb/usb_gadget_ums.c +src/bdk/usb/usb_t210.h +src/bdk/usb/usbd.c +src/bdk/usb/usbd.h +src/bdk/utils/aarch64_util.h +src/bdk/utils/btn.c +src/bdk/utils/btn.h +src/bdk/utils/dirlist.c +src/bdk/utils/dirlist.h +src/bdk/utils/ini.c +src/bdk/utils/ini.h +src/bdk/utils/list.h +src/bdk/utils/sprintf.c +src/bdk/utils/sprintf.h +src/bdk/utils/types.h +src/bdk/utils/util.c +src/bdk/utils/util.h +src/ffconf.h +src/gfx/gfx.c +src/gfx/gfx.h +src/gfx/logos-gui.h +src/libs/fatfs/diskio.c +src/libs/fatfs/ffconf.h +src/libs/fatfs/ffsystem.c +src/libs/hekate_config.c +src/libs/hekate_config.h +src/libs/hos/fss.c +src/libs/hos/fss.h +src/libs/hos/hos.c +src/libs/hos/hos.h +src/libs/hos/hos_config.c +src/libs/hos/hos_config.h +src/libs/hos/pkg1.c +src/libs/hos/pkg1.h +src/libs/hos/pkg2.c +src/libs/hos/pkg2.h +src/libs/hos/pkg2_ini_kippatch.h +src/libs/hos/secmon_exo.c +src/libs/hos/secmon_exo.h +src/libs/hos/sept.c +src/libs/hos/sept.h +src/link.ld +src/logo.h src/main.c -src/minerva_tc/mtc/mtc.c -src/minerva_tc/mtc/mtc.h -src/minerva_tc/mtc/mtc_mc_emc_regs.h -src/minerva_tc/mtc/mtc_table.h -src/minerva_tc/mtc/types.h -src/panic_color.h src/rcm_usb.c src/rcm_usb.h -src/start.s -src/storage.c -src/storage.h +src/start.S +src/storage/emummc.c +src/storage/emummc.h +src/storage/nx_emmc.c +src/storage/nx_emmc.h +src/storage/nx_emmc_bis.c +src/storage/nx_emmc_bis.h +src/storage/nx_sd.c src/usb_command.h -src/usb_output.h -src/utils.c -src/utils.h diff --git a/ariane/ariane.includes b/ariane/ariane.includes index 23f23d1..e7749ad 100644 --- a/ariane/ariane.includes +++ b/ariane/ariane.includes @@ -1,5 +1,32 @@ src -src/display -src/hwinit -src/lib -src/minerva_tc/mtc +src/bdk +src/bdk/gfx +src/bdk/ianos +src/bdk/ianos/elfload +src/bdk/input +src/bdk/libs +src/bdk/libs/compr +src/bdk/libs/fatfs +src/bdk/libs/lvgl +src/bdk/libs/lvgl/lv_core +src/bdk/libs/lvgl/lv_draw +src/bdk/libs/lvgl/lv_fonts +src/bdk/libs/lvgl/lv_hal +src/bdk/libs/lvgl/lv_misc +src/bdk/libs/lvgl/lv_objx +src/bdk/libs/lvgl/lv_themes +src/bdk/mem +src/bdk/power +src/bdk/rtc +src/bdk/sec +src/bdk/soc +src/bdk/storage +src/bdk/thermal +src/bdk/usb +src/bdk/utils +src/gfx +src/libs +src/libs/fatfs +src/libs/hos +src/storage +. diff --git a/ariane/linker.ld b/ariane/linker.ld deleted file mode 100644 index c91d5ff..0000000 --- a/ariane/linker.ld +++ /dev/null @@ -1,154 +0,0 @@ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(_start) - -/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */ - -SECTIONS -{ - PROVIDE(__start__ = 0x40008000); - . = __start__; - . = ALIGN(32); - .text : - { - . = ALIGN(32); - /* .init */ - KEEP( *(.text.start) ) - KEEP( *(.init) ) - . = ALIGN(4); - - /* .text */ - *(.text) - *(.text.*) - *(.glue_7) - *(.glue_7t) - *(.stub) - *(.gnu.warning) - *(.gnu.linkonce.t*) - . = ALIGN(4); - - /* .fini */ - KEEP( *(.fini) ) - . = ALIGN(4); - } - - .rodata : - { - *(.rodata) - *(.roda) - *(.rodata.*) - *all.rodata*(*) - *(.gnu.linkonce.r*) - SORT(CONSTRUCTORS) - . = ALIGN(4); - } - - .preinit_array ALIGN(4) : - { - PROVIDE (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE (__preinit_array_end = .); - } - - .init_array ALIGN(4) : - { - PROVIDE (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE (__init_array_end = .); - } - - .fini_array ALIGN(4) : - { - PROVIDE (__fini_array_start = .); - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE (__fini_array_end = .); - } - - .ctors ALIGN(4) : - { - KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - - .dtors ALIGN(4) : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } - __exidx_start = .; - ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } - __exidx_end = .; - - .data : - { - *(.data) - *(.data.*) - *(.gnu.linkonce.d*) - CONSTRUCTORS - . = ALIGN(4); - } - - __bss_start__ = ALIGN(32); - .bss : - { - *(.dynbss) - *(.bss) - *(.bss.*) - *(.gnu.linkonce.b*) - *(COMMON) - . = ALIGN(8); - } - __bss_end__ = .; - __end__ = ABSOLUTE(.) ; - - PROVIDE(__stack = 0x4003F000); - . = __stack; - - /* ================== - ==== Metadata ==== - ================== */ - - /* Discard sections that difficult post-processing */ - /DISCARD/ : { *(.group .comment .note) } - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } -} diff --git a/ariane/linker.specs b/ariane/linker.specs deleted file mode 100644 index 17b095a..0000000 --- a/ariane/linker.specs +++ /dev/null @@ -1,7 +0,0 @@ -%rename link old_link - -*link: -%(old_link) -T linker.ld --nmagic --gc-sections - -*startfile: -crti%O%s crtbegin%O%s diff --git a/ariane/src/ariane.c b/ariane/src/ariane.c new file mode 100644 index 0000000..df6081e --- /dev/null +++ b/ariane/src/ariane.c @@ -0,0 +1,909 @@ +/* + * Ariane, payload based USB backend + * + * Copyright (c) 2020 eliboa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "libs/hekate_config.h" +extern hekate_config h_cfg; +extern boot_cfg_t b_cfg; +extern emummc_cfg_t emu_cfg; + +#include "ariane.h" +#include "gfx/gfx.h" +#include "storage/nx_emmc.h" +#include "storage/nx_emmc_bis.h" +#include "libs/hos/hos.h" +#include "libs/hos/sept.h" +#include "libs/hos/pkg1.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "storage/emummc.h" + +bool keygen_done = false; +bool is_init = true; +extern bool usb_ready; +UC_DeviceInfo di; +u8* usb_write_buff = (u8*)USB_EP_BULK_IN_BUF_ADDR; +u8* usb_read_buff = (u8*)USB_EP_BULK_OUT_BUF_ADDR; + +const pkg1_id_t *sys_pkg1_id; +const pkg1_id_t *emu_pkg1_id; + +static DispatchEntry dispatchEntries[] = +{ + { GET_STATUS, &rcm_ready_notice }, + { GET_DEVICE_INFO, &get_deviceinfo_command }, + { SET_AUTORCM_ON, &set_autorcm_on_command }, + { SET_AUTORCM_OFF, &set_autorcm_off_command }, + { READ_SD_FILE, &sdmmc_readfile_command }, + { WRITE_SD_FILE, &sdmmc_writefile_command }, + { SIZE_SD_FILE, &sdmmc_filesize_command }, + { REBOOT_RCM, &rcm_reboot_command }, + { GET_KEYS, &get_keys_command }, + { ISDIR_SD, &sdmmc_isdir_command }, + { MKDIR_SD, &sdmmc_mkdir_command }, + { MKPATH_SD, &sdmmc_mkpath_command }, + { PUSH_PAYLOAD, &launch_payload_command } +}; + +// Title ID 0100000000000809 (SystemVersion) +// Title ID 010000000000081B (BootImagePackageExFat) +static SystemTitle systemTitles[] = +{ + { "10.1.1", "5077973537f6735b564dd7475b779f87.nca", 10, "3df13daa7f553c8fa85bbff79a189d6c.nca"}, /* CHINA */ + { "10.1.0", "fd1faed0ca750700d254c0915b93d506.nca", 10, "3df13daa7f553c8fa85bbff79a189d6c.nca"}, + { "10.0.4", "34728c771299443420820d8ae490ea41.nca", 10, "d5bc167565842ee61f9670d23759844d.nca"}, + { "10.0.3", "5b1df84f88c3334335bbb45d8522cbb4.nca", 10, "d5bc167565842ee61f9670d23759844d.nca"}, + { "10.0.2", "e951bc9dedcd54f65ffd83d4d050f9e0.nca", 10, "d5bc167565842ee61f9670d23759844d.nca"}, + { "10.0.1", "36ab1acf0c10a2beb9f7d472685f9a89.nca", 10, "d5bc167565842ee61f9670d23759844d.nca"}, + { "10.0.0", "5625cdc21d5f1ca52f6c36ba261505b9.nca", 10, "d5bc167565842ee61f9670d23759844d.nca"}, + { "9.2.0", "09ef4d92bb47b33861e695ba524a2c17.nca", 10, "2416b3794964b3482c7bc506d12c44df.nca"}, + { "9.1.0", "c5fbb49f2e3648c8cfca758020c53ecb.nca", 10, "c9bd4eda34c91a676de09951bb8179ae.nca"}, + { "9.0.1", "fd1ffb82dc1da76346343de22edbc97c.nca", 9 , "3b444768f8a36d0ddd85635199f9676f.nca"}, + { "9.0.0", "a6af05b33f8f903aab90c8b0fcbcc6a4.nca", 9 , "3b444768f8a36d0ddd85635199f9676f.nca"}, + { "8.1.1", "e9bb0602e939270a9348bddd9b78827b.nca", 8 , "96f4b8b729ade072cc661d9700955258.nca"}, /* 8.1.1-12 from chinese gamecard */ + { "8.1.1", "724d9b432929ea43e787ad81bf09ae65.nca", 8 , "96f4b8b729ade072cc661d9700955258.nca"}, /* 8.1.1-100 from Lite */ + { "8.1.0", "7eedb7006ad855ec567114be601b2a9d.nca", 8 , "96f4b8b729ade072cc661d9700955258.nca"}, + { "8.0.1", "6c5426d27c40288302ad616307867eba.nca", 7 , "b2708136b24bbe206e502578000b1998.nca"}, + { "8.0.0", "4fe7b4abcea4a0bcc50975c1a926efcb.nca", 7 , "b2708136b24bbe206e502578000b1998.nca"}, + { "7.0.1", "e6b22c40bb4fa66a151f1dc8db5a7b5c.nca", 7 , "02a2cbfd48b2f2f3a6cec378d20a5eff.nca"}, + { "7.0.0", "c613bd9660478de69bc8d0e2e7ea9949.nca", 7 , "58c731cdacb330868057e71327bd343e.nca"}, + { "6.2.0", "6dfaaf1a3cebda6307aa770d9303d9b6.nca", 6 , "97cb7dc89421decc0340aec7abf8e33b.nca"}, + { "6.1.0", "1d21680af5a034d626693674faf81b02.nca", 5 , "d5186022d6080577b13f7fd8bcba4dbb.nca"}, + { "6.0.1", "663e74e45ffc86fbbaeb98045feea315.nca", 5 , "d5186022d6080577b13f7fd8bcba4dbb.nca"}, + { "6.0.0", "258c1786b0f6844250f34d9c6f66095b.nca", 5 , "d5186022d6080577b13f7fd8bcba4dbb.nca"}, + { "6.0.0", "286e30bafd7e4197df6551ad802dd815.nca", 5 , "711b5fc83a1f07d443dfc36ba606033b.nca"}, + { "5.1.0", "fce3b0ea366f9c95fe6498b69274b0e7.nca", 4 , "c9e500edc7bb0fde52eab246028ef84c.nca"}, + { "5.0.2", "c5758b0cb8c6512e8967e38842d35016.nca", 4 , "432f5cc48e6c1b88de2bc882204f03a1.nca"}, + { "5.0.1", "7f5529b7a092b77bf093bdf2f9a3bf96.nca", 4 , "432f5cc48e6c1b88de2bc882204f03a1.nca"}, + { "5.0.0", "faa857ad6e82f472863e97f810de036a.nca", 4 , "432f5cc48e6c1b88de2bc882204f03a1.nca"}, + { "4.1.0", "77e1ae7661ad8a718b9b13b70304aeea.nca", 3 , "458a54253f9e49ddb044642286ca6485.nca"}, + { "4.0.1", "d0e5d20e3260f3083bcc067483b71274.nca", 3 , "090b012b110973fbdc56a102456dc9c6.nca"}, + { "4.0.0", "f99ac61b17fdd5ae8e4dda7c0b55132a.nca", 3 , "090b012b110973fbdc56a102456dc9c6.nca"}, + { "3.0.2", "704129fc89e1fcb85c37b3112e51b0fc.nca", 2 , "e7dd3c6cf68953e86cce54b69b333256.nca"}, + { "3.0.1", "9a78e13d48ca44b1987412352a1183a1.nca", 2 , "17f9864ce7fe3a35cbe3e3b9f6185ffb.nca"}, + { "3.0.0", "7bef244b45bf63efb4bf47a236975ec6.nca", 1 , "9e5c73ec938f3e1e904a4031aa4240ed.nca"}, + { "2.3.0", "d1c991c53a8a9038f8c3157a553d876d.nca", 0 , "4a94289d2400b301cbe393e64831f84c.nca"}, + { "2.2.0", "7f90353dff2d7ce69e19e07ebc0d5489.nca", 0 , "4a94289d2400b301cbe393e64831f84c.nca"}, + { "2.1.0", "e9b3e75fce00e52fe646156634d229b4.nca", 0 , "4a94289d2400b301cbe393e64831f84c.nca"}, + { "2.0.0", "7a1f79f8184d4b9bae1755090278f52c.nca", 0 , "f55a04978465ebf5666ca93e21b26dd2.nca"}, + { "1.0.0", "a1b287e07f8455e8192f13d0e45a2aaf.nca", 0 , "3b7cd379e18e2ee7e1c6d0449d540841.nca"} +}; + +bool command_dispatcher(UC_CommandType command) +{ + for (u32 i = 0; i < ARRAY_SIZE(dispatchEntries); i++) if (dispatchEntries[i].command == command) + { + dispatchEntries[i].f_ptr(); + return true; + } + return false; +} + +u32 cur_backlight; +u32 last_activity; +UC_CommandType usb_command_read() +{ + UC_CommandType command = NONE; + + if (!cur_backlight) + cur_backlight = h_cfg.backlight; + + memset(usb_read_buff, 0, USB_BUFFER_LENGTH); + unsigned int bytesTransferred = 0; + int ret = rcm_usb_device_read_ep1_out_sync(usb_read_buff, USB_BUFFER_LENGTH, &bytesTransferred); + if (ret || !(bytesTransferred > 2)) + { + if (ret == 28) // Reconnection + reboot_to_rcm(); + + goto end; + } + UC_Header* uc = (UC_Header*)usb_read_buff; + if (uc->signature == COMMAND || uc->signature == EXEC_COMMAND) + { + command = uc->command; + if (command != GET_DEVICE_INFO && command != GET_STATUS) + { + h_cfg.backlight = 100; + last_activity = get_tmr_s(); + } + } + +end: + // Lower backlight brightness when inactive + if (command == NONE && cur_backlight == 100 && last_activity + 40 < get_tmr_s()) + h_cfg.backlight = 15; + + // Switch brightness + if (cur_backlight != h_cfg.backlight) + { + display_backlight_brightness(h_cfg.backlight, h_cfg.backlight == 15 ? 1000 : 0); + cur_backlight = h_cfg.backlight; + } + return command; +} + +void reboot_to_rcm() +{ + sd_end(); + + memset(&b_cfg, 0, sizeof(b_cfg)); + memset(&h_cfg, 0, sizeof(h_cfg)); + reconfig_hw_workaround(false, 0); + + // Reboot to RCM + PMC(0x50) = (1 << 1); + PMC(0x0) |= (1 << 4); + + while (true) + bpmp_halt(); +} + +void send_response(const void* in_buffer, u32 size) +{ + u32 new_size = size + sizeof(u16), bytes = 0; + if (new_size > RESPONSE_MAX_SIZE) + return; + + u16 signature = RESPONSE; + memcpy(&usb_write_buff[0], (u8*)&signature, sizeof(u16)); + memcpy(&usb_write_buff[sizeof(u16)], in_buffer, size); + rcm_usb_device_write_ep1_in_sync(&usb_write_buff[0], new_size, &bytes); +} + +bool recv_bin_packet(u32 *bytesReceived) +{ + memset(&usb_read_buff[0], 0, sizeof(UC_BlockHeader)); + *bytesReceived = 0; + u32 bytesTransferred = 0; + if(rcm_usb_device_read_ep1_out_sync(usb_read_buff, USB_BUFFER_LENGTH, &bytesTransferred) || !bytesTransferred) + return false; + + UC_BlockHeader *bh = (UC_BlockHeader*)&usb_read_buff[0]; + if (bh->signature != BIN_PACKET) + return false; + + // Send bloc size in response + send_response((const void*)&bh->block_size, sizeof(bh->block_size)); + *bytesReceived = bh->block_size; + return true; +} + +void hos_set_keys(bool allow_sept_reboot) +{ + // Read package1. + u8 *pkg1 = (u8 *)malloc(0x40000); + sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); + sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0); + sdmmc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + char *build_date = malloc(32); + sys_pkg1_id = pkg1_identify(pkg1, build_date); + if (!sys_pkg1_id) + { + gfx_printf("Failed to identify pkg1\n"); + goto out; + } + + tsec_ctxt_t tsec_ctxt; + tsec_ctxt.fw = (u8 *)pkg1 + sys_pkg1_id->tsec_off; + tsec_ctxt.pkg1 = pkg1; + tsec_ctxt.pkg11_off = sys_pkg1_id->pkg11_off; + tsec_ctxt.secmon_base = sys_pkg1_id->secmon_base; + + hos_eks_get(); // Get keys + if (sys_pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + { + u32 key_idx = 0; + if (sys_pkg1_id->kb >= KB_FIRMWARE_VERSION_810) + key_idx = 1; + + if (h_cfg.eks && h_cfg.eks->enabled[key_idx] >= sys_pkg1_id->kb) + h_cfg.sept_run = true; + else + { + if (!allow_sept_reboot || b_cfg.extra_cfg & EXTRA_CFG_NYX_BIS) + { + gfx_printf("Need to launch Sept first (kb = %d)\n", sys_pkg1_id->kb); + goto out; + } + else + { + b_cfg.extra_cfg = EXTRA_CFG_NYX_BIS; + sdmmc_storage_end(&emmc_storage); + sdram_lp0_save_params(sdram_get_params_patched()); + if (!reboot_to_sept((u8 *)tsec_ctxt.fw, sys_pkg1_id->kb)) + { + gfx_printf("Failed to run sept\n"); + goto out; + } + } + } + } + + // Read the correct keyblob. + u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); + sdmmc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + sys_pkg1_id->kb, 1, keyblob); + + // Derive & save hos keys + if (hos_bis_keygen(keyblob, sys_pkg1_id->kb, &tsec_ctxt) == 1) + { + hos_eks_bis_save(); + keygen_done = true; + gfx_printf("hos_eks_bis_save()\n"); + + for (u32 i = 0; i < 0x10; i++) + { + gfx_printf("%02x", h_cfg.eks->bis_keys[3].crypt[i]); + } + gfx_printf("\n"); + + } + else gfx_printf("Failed to generate keys\n"); + + free(keyblob); +out: + sdmmc_storage_end(&emmc_storage); + free(pkg1); +} + +void set_fs_info() +{ + if (!sdmounted()) + { + di.sdmmc_initialized = false; + return; + } + + di.sdmmc_initialized = true; + di.mmc_fs_type = sd_fs.fs_type; + di.mmc_fs_cl_size = sd_fs.csize; + di.mmc_fs_last_cl = sd_fs.n_fatent - 2; + + if (sd_fs.fs_type == FS_EXFAT) + f_getfree("", &di.mmc_fs_free_cl, NULL); // This operation can be slow for FAT32 + + di.cfw_sxos = (f_stat("boot.dat", NULL) == FR_OK); + di.cbl_hekate = (f_stat("bootloader/hekate_ipl.ini", NULL) == FR_OK); + + + FIL fp; + if (f_open(&fp, "bootloader/sys/nyx.bin", FA_READ) == FR_OK) + { + di.cbl_nyx = true; + u32 bytesTransferred = 0; + u8 buff[0x200]; + memset(di.nyx_version, 0, 3); + if (f_read(&fp, &buff, 0x200, &bytesTransferred) == FR_OK && bytesTransferred == 0x200 && !memcmp(&buff[0x99], "CTC", 3)) + memcpy(di.nyx_version, &buff[0x9C], 3); + f_close(&fp); + } + + if (f_open(&fp, "atmosphere/fusee-secondary.bin", FA_READ) == FR_OK) + { + di.cfw_ams = true; + u32 bytesTransferred = 0; + char buff[0x200]; + memset(di.ams_version, 0, 3); + if (f_read(&fp, &buff, 0x200, &bytesTransferred) == FR_OK) { + for (int i=0; i <= 0x200-4; i += 4) if (!memcmp(&buff[i], "FSS0", 4)) { + memcpy(&di.ams_version[2], &buff[i+0x19], 1); + memcpy(&di.ams_version[1], &buff[i+0x1A], 1); + memcpy(&di.ams_version[0], &buff[i+0x1B], 1); + break; + } + } + f_close(&fp); + } + + // Get emunand config + emummc_load_cfg(); + if (emu_cfg.enabled) + { + di.emunand_enabled = true; + di.emunand_type = FILEBASED; + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/raw_based"); + if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + if (!f_read(&fp, &emu_cfg.sector, 4, NULL)) + if (emu_cfg.sector) + di.emunand_type = RAWBASED; + } + } +} + +void get_fw_version(const char *path, const pkg1_id_t *pkg1_id, char *fw_version, bool *exfat) +{ + /* + char *filelist = NULL; + // Check NCAs to get sys firmware version + for (u32 i=0; i < ARRAY_SIZE(systemTitles); i++) if (systemTitles[i].kb == pkg1_id->kb) + { + + gfx_printf("Testing %s\n", systemTitles[i].nca_filename); + minerva_periodic_training(); + filelist = dirlist(path, systemTitles[i].nca_filename, true, true); + if (filelist && !strcmp(&filelist[0], systemTitles[i].nca_filename)) + { + strcpy(fw_version, systemTitles[i].fw_version); + + filelist = dirlist(path, systemTitles[i].nca_filename_exfat, true, true); + if (!strcmp(&filelist[0], systemTitles[i].nca_filename_exfat)) + *exfat = true; + + gfx_printf("FOUND FW %s %s\n", fw_version, *exfat ? "exFAT" : ""); + break; + } + } + + if (filelist) + free(filelist); + */ + + DIR dir; + FILINFO fno; + bool entry_found = false; + u32 title_entry = 0; + if(f_opendir(&dir, path)) + return; + + // Look for title ID 0100000000000809 (SystemVersion) + gfx_printf("Look for title ID 0100000000000809\n"); + for (;;) + { + int res = f_readdir(&dir, &fno); + if (res || !fno.fname[0] || entry_found) + break; + + if (fno.fname[0] == '.') + continue; + + for (u32 i=0; i < ARRAY_SIZE(systemTitles); i++) if (systemTitles[i].kb == pkg1_id->kb) + { + if (!strcmp(fno.fname, systemTitles[i].nca_filename)) + { + strcpy(fw_version, systemTitles[i].fw_version); + entry_found = true; + title_entry = i; + break; + } + } + } + + f_closedir(&dir); + + if (!entry_found) + return; + + // Look for title ID 010000000000081B (BootImagePackageExFat) + gfx_printf("Look for title ID 010000000000081B\n"); + f_opendir(&dir, path); + for (;;) + { + int res = f_readdir(&dir, &fno); + if (res || !fno.fname[0]) + break; + + if (fno.fname[0] == '.') + continue; + + if (!strcmp(fno.fname, systemTitles[title_entry].nca_filename_exfat)) + { + *exfat = true; + break; + } + } + + f_closedir(&dir); +} + +void set_deviceinfo() +{ + /* + * ToDo: + * - emunand type detection + * - get Nintendo device ID + */ + + u32 start_tmr = get_tmr_ms(); + memset(&di, 0, sizeof(UC_DeviceInfo)); + di.signature = DEVINFO; + + // AutoRCM + get_autorcm_state(&di.autoRCM); + + // Burnt fuses + di.burnt_fuses = 0; + for (u32 i = 0; i < 32; i++) if ((fuse_read_odm(7) >> i) & 1) + di.burnt_fuses++; + + // Battery + int value = 0; + i2c_recv_buf_small((u8 *)&value, 2, I2C_1, 0x36, 0x06); + di.battery_capacity = value >> 8; + + // Set sdmmc FS info + set_fs_info(); + + if (!sd_mount()) + goto out; + + // Generate keys + hos_set_keys(FORBID_SEPT_REBOOT); + + if (!keygen_done || !sys_pkg1_id) + { + gfx_printf("KEYGEN NOT DONE\n"); + return; + } + // Get sys fw version & exFat driver + sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); + sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP); + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &emmc_storage); + emmc_part_t *system = nx_emmc_part_find(&gpt, "SYSTEM"); + if (!system) + { + gfx_printf("SYSTEM not found ! \n"); + goto out; + } + + h_cfg.emummc_force_disable = true; + nx_emmc_bis_init(system); + if(f_mount(&emmc_fs, "bis:", 1)) + { + gfx_printf("Failed to mount SYSTEM\n"); + goto out; + } + + get_fw_version("bis:/Contents/registered", sys_pkg1_id, &di.fw_version[0], &di.exFat_driver); + + gfx_printf("di.fw_version = %s %s\n", di.fw_version, di.exFat_driver ? " exFat" : ""); + + // Unmount cur bis storage + system = NULL; + f_mount(NULL, "bis:", 1); + + // Retrieve device id from CAL0 + emmc_part_t *cal0 = nx_emmc_part_find(&gpt, "PRODINFO"); + if (cal0) + { + nx_emmc_bis_init(cal0); + u8 buffer[0x200]; + if (nx_emmc_bis_read(2, 1, &buffer) == SUCCESS) + { + memcpy(&di.deviceId, &buffer[0x144], 20); + gfx_printf("NX ID = %s\n", di.deviceId); + } + } + + sdmmc_storage_end(&emmc_storage); + + if (!emu_cfg.enabled || di.emunand_type == FILEBASED) // Don't look up for emu fw if filebased emunand (too slow) + goto out; + + gfx_printf("Read emunand\n"); + + // Read emu pkg1 + sdmmc_storage_end(&emmc_storage); + u8 *pkg1 = (u8 *)malloc(0x40000); + h_cfg.emummc_force_disable = false; + emummc_storage_init_mmc(&emmc_storage, &emmc_sdmmc); + emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0); + emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + //gfx_printf("emu pkg1 read\n"); + char *build_date = malloc(32); + emu_pkg1_id = pkg1_identify(pkg1, build_date); + free(pkg1); + if (!emu_pkg1_id) + { + gfx_printf("Failed to read/id emu pkg1\n"); + goto out; + } + gfx_printf("emu pkg1 identify %d\n", emu_pkg1_id->kb); + + // Mount emu bis storage + emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP); + LIST_INIT(gpt_emu); + nx_emmc_gpt_parse(&gpt_emu, &emmc_storage); + system = nx_emmc_part_find(&gpt_emu, "SYSTEM"); + if (!system) + { + gfx_printf("EMU SYSTEM not found ! \n"); + nx_emmc_gpt_free(&gpt_emu); + goto out_emu; + } + + nx_emmc_bis_init(system); + if(f_mount(&emmc_fs, "bis:", 1)) + { + gfx_printf("EMU Failed to mount SYSTEM"); + goto out_emu; + } + + get_fw_version("bis:/Contents/registered", emu_pkg1_id, &di.emu_fw_version[0], &di.emu_exFat_driver); + gfx_printf("di.emu_fw_version = %s %s\n", di.emu_fw_version, di.emu_exFat_driver ? " exFat" : ""); + + f_mount(NULL, "bis:", 1); + +out_emu : + nx_emmc_gpt_free(&gpt_emu); + +out : + nx_emmc_gpt_free(&gpt); + sdmmc_storage_end(&emmc_storage); +} + +bool get_autorcm_state(bool *state) +{ + sdmmc_storage_t storage; + sdmmc_t sdmmc; + + if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + { + gfx_printf("Failed to mount EMMC BOOT0\n"); + return false; + } + + bool bct_state[4]; + bool autoRcmOn[4] = {false, false, false, false}; + for (int i = 0; i < 4; i++) + { + u8 buff[0x200]; + memset(buff, 0, 0x200); + if (!sdmmc_storage_read(&storage, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) + { + sdmmc_storage_end(&storage); + return false; + } + + if (buff[0x10] == 0xF7) bct_state[i] = true; + else bct_state[i] = false; + } + + *state = !memcmp(autoRcmOn, bct_state, 4) ? true : false; + sdmmc_storage_end(&storage); + return true; +} + +bool set_autorcm_state(bool autoRCM) +{ + sdmmc_storage_t storage; + sdmmc_t sdmmc; + + if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + { + gfx_printf("Failed to mount EMMC BOOT0\n"); + return false; + } + for (int i = 0; i < 4; i++) + { + u8 buff[0x200]; + memset(buff, 0, 0x200); + if (!sdmmc_storage_read(&storage, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) + { + sdmmc_storage_end(&storage); + return false; + } + if (!autoRCM) + buff[0x10] = 0xF7; + else + { + u8 randomXor = 0; + do randomXor = (unsigned)get_tmr_ms() & 0xFF; + while (!randomXor); + buff[0x10] ^= randomXor; + } + if (!sdmmc_storage_write(&storage, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) + { + sdmmc_storage_end(&storage); + return false; + } + } + sdmmc_storage_end(&storage); + return true; +} + +void get_deviceinfo_command() +{ + if (!is_init) + { + // Update battery charge + int value = 0; + i2c_recv_buf_small((u8 *)&value, 2, I2C_1, 0x36, 0x06); + di.battery_capacity = value >> 8; + + // Update FS info + set_fs_info(); + } + + //gfx_printf("Received get_deviceinfo_command %s\n", di.fw_version); + + u32 bytes = 0; + rcm_usb_device_write_ep1_in_sync((u8*)&di, sizeof(UC_DeviceInfo), &bytes); + + is_init = false; +} + +void sdmmc_filesize_command() +{ + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + u32 res = 0; + FIL fp; + + if (f_open(&fp, uc->path, FA_READ) == FR_OK) + res = f_size(&fp); + + send_response((const void*)&res, sizeof(u32)); // Notify caller +} + +void sdmmc_isdir_command() +{ + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + DIR dir; + + FRESULT res = f_opendir(&dir, uc->path); + if (res == FR_OK) + f_closedir(&dir); + + send_response((const void*)&res, sizeof(u32)); // Notify caller +} + +void sdmmc_mkdir_command() +{ + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + DIR dir; + + FRESULT res = f_opendir(&dir, uc->path); + if (res != FR_OK) + res = f_mkdir(uc->path); + else f_closedir(&dir); + + send_response((const void*)&res, sizeof(u32)); // Notify caller +} + +void sdmmc_mkpath_command() +{ + + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + DIR dir; + + FRESULT res = f_opendir(&dir, uc->path); + if (res != FR_OK) + { + char *cdir = malloc(ARRAY_SIZE(uc->path)); + memcpy(cdir, uc->path, ARRAY_SIZE(uc->path)); + char *cur_path = malloc(ARRAY_SIZE(uc->path)); + char *dir; + int pos = 0; + + while ((dir = strtok(cdir, "/")) != NULL) + { + free(cdir); + cdir = NULL; + memcpy(&cur_path[pos], &dir[0], strlen(dir)+1); + pos += strlen(dir)+1; + DIR s_dir; + res = f_opendir(&s_dir, cur_path); + if (res == FR_OK) { + f_closedir(&s_dir); + } else { + res = f_mkdir(cur_path); + if (res != FR_OK) + break; + } + cur_path[pos-1] = '/'; + } + free(cur_path); + } + else f_closedir(&dir); + send_response((const void*)&res, sizeof(u32)); // Notify caller +} + +void sdmmc_readfile_command() +{ + u32 start_tmr = get_tmr_ms(); + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + FIL fp; + + if (f_open(&fp, uc->path, FA_READ) != FR_OK) + goto out; + + u32 size = f_size(&fp); + u32 bytesRemaining = size; + + send_response((const void*)&size, sizeof(u32)); // Notify caller + while (bytesRemaining > 0) + { + minerva_periodic_training(); + + u32 buf_size = bytesRemaining > USB_BUFFER_LENGTH - 32 ? USB_BUFFER_LENGTH - 32 : bytesRemaining; + u32 bytesTransferred = 0; + memset(&usb_read_buff[0], 0, USB_BUFFER_LENGTH); + + UC_BlockHeader *bh = (UC_BlockHeader*)&usb_write_buff[0]; + bh->signature = BIN_PACKET; + bh->block_size = buf_size; + + if (f_read(&fp, &usb_write_buff[32], buf_size, &bytesTransferred) != FR_OK) + goto out; + + if (bytesTransferred != buf_size) + goto out; + + bytesTransferred = 0; + if (rcm_usb_device_write_ep1_in_sync(&usb_write_buff[0], USB_BUFFER_LENGTH, &bytesTransferred) && !bytesTransferred) + goto out; + + // Read confirm + memset(&usb_read_buff[0], 0, sizeof(u16) + sizeof(bool)); + bytesTransferred = 0; + if(rcm_usb_device_read_ep1_out_sync(usb_read_buff, sizeof(u16) + sizeof(bool), &bytesTransferred) && !bytesTransferred) + goto out; + + u16 *signature = (u16*)usb_read_buff; + bool *res = (bool*)&usb_read_buff[sizeof(u16)]; + if (*signature != RESPONSE || *res != true) + goto out; + + bytesRemaining -= buf_size; + } + +out: + //gfx_printf("readfile_command ends in %dms\n", get_tmr_ms() - start_tmr); + f_close(&fp); +} + +void sdmmc_writefile_command() +{ + UC_SDIO* uc = (UC_SDIO*)usb_read_buff; + FIL fp; + + if (f_open (&fp, uc->path, uc->create_always ? FA_WRITE | FA_CREATE_ALWAYS : FA_WRITE | FA_CREATE_NEW) != FR_OK) + goto out; + + u32 fileSize = uc->file_size; + u32 bytesRemaining = fileSize; + + while (bytesRemaining > 0) + { + minerva_periodic_training(); + u32 bytesTransferred = 0; + if (!recv_bin_packet(&bytesTransferred)) + break; + + u32 bytesWrite = 0; + if (f_write(&fp, &usb_read_buff[32], bytesTransferred, &bytesWrite) != FR_OK || bytesWrite <= 0) + break; + + bytesRemaining -= bytesWrite; + } + +out: + f_close(&fp); +} + +void rcm_reboot_command() +{ + bool confirm = true; + send_response((const void*)&confirm, sizeof(bool)); // Notify caller + + reboot_to_rcm(); +} + +void set_autorcm_on_command() +{ + bool res = set_autorcm_state(true); + send_response((const void*)&res, sizeof(bool)); // Notify caller +} + +void set_autorcm_off_command() +{ + bool res = set_autorcm_state(true); + send_response((const void*)&res, sizeof(bool)); // Notify caller +} + +void get_keys_command() +{ + hos_set_keys(ALLOW_SEPT_REBOOT); +} + +extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); + +void launch_payload_command() +{ + UC_EXEC* uc = (UC_EXEC*)usb_read_buff; + u32 bytesCount = 0; + + if (uc->command != PUSH_PAYLOAD) + goto out; + + void *buf = (void *)RCM_PAYLOAD_ADDR; + u32 size = uc->bin_size; + + bool confirm = true; + send_response((const void*)&confirm, sizeof(bool)); // Notify caller + + while (bytesCount < size) + { + minerva_periodic_training(); + u32 bytesTransferred = 0; + if (!recv_bin_packet(&bytesTransferred)) + break; + + memcpy(buf + bytesCount, &usb_read_buff[32], bytesTransferred); + bytesCount += bytesTransferred; + } + + if (bytesCount != size) + goto out; + + sd_end(); + + memset(&b_cfg, 0, sizeof(b_cfg)); + memset(&h_cfg, 0, sizeof(h_cfg)); + + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + reconfig_hw_workaround(false, 0); + + sdmmc_storage_init_wait_sd(); + + void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; + (*ext_payload_ptr)(); + +out: + gfx_printf("launch_payload_command failed (%db)\n", bytesCount); + return; +} diff --git a/ariane/src/ariane.h b/ariane/src/ariane.h new file mode 100644 index 0000000..8df480e --- /dev/null +++ b/ariane/src/ariane.h @@ -0,0 +1,83 @@ +/* + * Ariane, payload based USB backend + * + * Copyright (c) 2020 eliboa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ARIANE_H_ +#define _ARIANE_H_ + +#include +#include "rcm_usb.h" +#include "usb_command.h" + +#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000 +#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000 + +#define ALLOW_SEPT_REBOOT 1 +#define FORBID_SEPT_REBOOT 0 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +// This is a safe and unused DRAM region for our payloads. +#define RELOC_META_OFF 0x7C +#define PATCHED_RELOC_SZ 0x94 +#define PATCHED_RELOC_STACK 0x40007000 +#define PATCHED_RELOC_ENTRY 0x40010000 +#define EXT_PAYLOAD_ADDR 0xC0000000 +#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +#define COREBOOT_END_ADDR 0xD0000000 +#define CBFS_DRAM_EN_ADDR 0x4003e000 +#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" +#endif + +typedef struct _DispatchEntry { + UC_CommandType command; + void (*f_ptr)(); +} DispatchEntry; + +typedef struct _SystemTitle { + const char fw_version[10]; + const char nca_filename[40]; + u32 kb; + const char nca_filename_exfat[40]; +} SystemTitle; + +bool command_dispatcher(UC_CommandType command); +void send_response(const void* in_buffer, u32 size); +bool recv_bin_packet(u32 *bytesReceived); +void hos_set_keys(bool allow_sept_reboot); +bool get_autorcm_state(bool *state); +bool set_autorcm_state(bool autoRCM); +void set_deviceinfo(); +void reboot_to_rcm(); + +// Command functions +UC_CommandType usb_command_read(); +void get_deviceinfo_command(); +void sdmmc_filesize_command(); +void sdmmc_isdir_command(); +void sdmmc_mkdir_command(); +void sdmmc_mkpath_command(); +void sdmmc_readfile_command(); +void sdmmc_writefile_command(); +void rcm_reboot_command(); +void set_autorcm_on_command(); +void set_autorcm_off_command(); +void get_keys_command(); +void launch_payload_command(); + +#endif diff --git a/ariane/src/bdk/exception_handlers.S b/ariane/src/bdk/exception_handlers.S new file mode 100644 index 0000000..97d1ec6 --- /dev/null +++ b/ariane/src/bdk/exception_handlers.S @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * Armv7tdmi Status register. + * + * bit0: Mode 0. + * bit1: Mode 1. + * bit2: Mode 2. + * bit3: Mode 3. + * bit4: Mode 4. + * bit5: Thumb state. + * bit6: FIQ disable. + * bit7: IRQ disable. + * bit8-27: Reserved. + * bit28: Overflow condition. + * bit29: Carry/Borrow/Extend condition. + * bit30: Zero condition. + * bit31: Negative/Less than condition. + * + * M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers + * 10000 | USER | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR + * 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq + * 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq + * 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc + * 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt + * 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und + * 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR + */ + +#define EXCP_EN_ADDR 0x4003FFFC +#define EXCP_TYPE_ADDR 0x4003FFF8 +#define EXCP_LR_ADDR 0x4003FFF4 + +#define EXCP_VEC_BASE 0x6000F000 +#define EVP_COP_RESET_VECTOR 0x200 +#define EVP_COP_UNDEF_VECTOR 0x204 +#define EVP_COP_SWI_VECTOR 0x208 +#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C +#define EVP_COP_DATA_ABORT_VECTOR 0x210 +#define EVP_COP_RSVD_VECTOR 0x214 +#define EVP_COP_IRQ_VECTOR 0x218 +#define EVP_COP_FIQ_VECTOR 0x21C + +#define MODE_USR 0x10 +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UDF 0x1B +#define MODE_SYS 0x1F +#define MODE_MASK 0x1F + +#define FIQ 0x40 +#define IRQ 0x80 + +.section .text._irq_setup +.arm + +.extern ipl_main +.type ipl_main, %function + +.extern svc_handler +.type svc_handler, %function + +.extern irq_handler +.type irq_handler, %function + +.extern fiq_setup +.type fiq_setup, %function + +.extern fiq_handler +.type fiq_handler, %function + +.globl _irq_setup +.type _irq_setup, %function +_irq_setup: + MRS R0, CPSR + BIC R0, R0, #MODE_MASK /* Clear mode bits */ + ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */ + MSR CPSR, R0 + + /* Setup IRQ stack pointer */ + MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */ + LDR SP, =0x40040000 + + /* Setup SYS stack pointer */ + MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */ + LDR SP, =0x4003FF00 /* Will be changed later to DRAM */ + + MOV LR, PC + BL setup_vectors + /*BL fiq_setup*/ + + /* Enable interrupts */ + BL irq_enable_cpu_irq_exceptions + + B ipl_main + B . + +_reset: + LDR R0, =EXCP_EN_ADDR + LDR R1, =0x30505645 /* EVP0 */ + STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */ + LDR R0, =EXCP_LR_ADDR + MOV R1, LR + STR R1, [R0] /* Save LR in EXCP_LR_ADDR */ + LDR R0, =__bss_start + EOR R1, R1, R1 + LDR R2, =__bss_end + SUB R2, R2, R0 + BL memset + B _irq_setup + +_reset_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x545352 /* RST */ + STR R1, [R0] /* RST in EXCP_TYPE_ADDR */ + B _reset + +_undefined_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x464455 /* UDF */ + STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */ + B _reset + +_prefetch_abort_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x54424150 /* PABT */ + STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */ + B _reset + +_data_abort_handler: + LDR R0, =EXCP_TYPE_ADDR + LDR R1, =0x54424144 /* DABT */ + STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */ + B _reset + +.globl irq_enable_cpu_irq_exceptions +.type irq_enable_cpu_irq_exceptions, %function +irq_enable_cpu_irq_exceptions: + MRS R12, CPSR + BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */ + MSR CPSR, R12 + BX LR + +.globl irq_disable_cpu_irq_exceptions +.type irq_disable_cpu_irq_exceptions, %function +irq_disable_cpu_irq_exceptions: + MRS R12, CPSR + ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */ + MSR CPSR, R12 + BX LR + +_irq_handler: + MOV R13, R0 /* Save R0 in R13_IRQ */ + SUB R0, LR, #4 /* Put return address in R0_SYS */ + MOV LR, R1 /* Save R1 in R14_IRQ (LR) */ + MRS R1, SPSR /* Put the SPSR in R1_SYS */ + + MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */ + STMFD SP!, {R0, R1} /* SPSR and PC */ + STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */ + MOV R0, SP /* Make SP_SYS visible to IRQ mode */ + SUB SP, SP, #8 /* Make room for stacking R0 and R1 */ + + MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */ + STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */ + + MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */ + LDR R12, =irq_handler + MOV LR, PC /* Copy the return address to link register */ + BX R12 /* Call the C IRQ handler (ARM/THUMB) */ + + MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */ + MOV R0, SP /* Make SP_SYS visible to IRQ mode */ + ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */ + + MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */ + MOV SP, R0 /* Copy SP_SYS to SP_IRQ */ + LDR R0, [SP, #28] /* Load the saved SPSR from the stack */ + MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */ + + LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */ + NOP /* Cant access barked registers immediately */ + LDR LR, [SP, #24] /* Load return address from the SYS stack */ + MOVS PC, LR /* Return restoring CPSR from SPSR */ + +_fiq_handler: + BL fiq_handler + +setup_vectors: + /* Setup vectors */ + LDR R0, =EXCP_VEC_BASE + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_RESET_VECTOR] + + LDR R1, =_undefined_handler + STR R1, [R0, #EVP_COP_UNDEF_VECTOR] + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_SWI_VECTOR] + + LDR R1, =_prefetch_abort_handler + STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR] + + LDR R1, =_data_abort_handler + STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR] + + LDR R1, =_reset_handler + STR R1, [R0, #EVP_COP_RSVD_VECTOR] + + LDR R1, =_irq_handler + STR R1, [R0, #EVP_COP_IRQ_VECTOR] + + LDR R1, =_fiq_handler + STR R1, [R0, #EVP_COP_FIQ_VECTOR] + + BX LR diff --git a/ariane/src/bdk/fatfs_cfg.h b/ariane/src/bdk/fatfs_cfg.h new file mode 100644 index 0000000..a12585f --- /dev/null +++ b/ariane/src/bdk/fatfs_cfg.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FATFS_CFG_H_ +#define _FATFS_CFG_H_ + +#ifdef FFCFG_INC +#include FFCFG_INC +#endif + +#endif diff --git a/ariane/src/bdk/gfx/di.c b/ariane/src/bdk/gfx/di.c new file mode 100644 index 0000000..1549e7b --- /dev/null +++ b/ariane/src/bdk/gfx/di.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "di.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "di.inl" + +extern volatile nyx_storage_t *nyx_str; + +static u32 _display_id = 0; + +void display_end(); + +static void _display_dsi_wait(u32 timeout, u32 off, u32 mask) +{ + u32 end = get_tmr_us() + timeout; + while (get_tmr_us() < end && DSI(off) & mask) + ; + usleep(5); +} + +static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait) +{ + DSI(_DSIREG(DSI_WR_DATA)) = (param << 8) | cmd; + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + + if (wait) + usleep(wait); +} + +void display_init() +{ + // Check if display is already initialized. + if (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) & 0x18000000) + display_end(); + + // Power on. + max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); + + // Enable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. + + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). + + // Disable deep power down. + PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; + PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; + + // Config LCD and Backlight pins. + PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; // PULL_DOWN | 1 + PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; // PULL_DOWN + PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; // PULL_DOWN + + // Set Backlight +-5V pins mode and direction + gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); + + // Enable Backlight power. + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. + usleep(10000); + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. + usleep(10000); + + // Configure Backlight pins (PWM, EN, RST). + gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. + + // Power up supply regulator for display interface. + MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0; + + // Set DISP1 clock source and parent clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT. + u32 plld_div = (3 << 20) | (20 << 11) | 1; // DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 96 MHz. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; // PLLD_SETUP. + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2D0AAA; // PLLD_ENABLE_CLK. + + // Setup display communication interfaces. + exec_cfg((u32 *)DISPLAY_A_BASE, _display_dc_setup_win_config, 94); + exec_cfg((u32 *)DSI_BASE, _display_dsi_init_config, 61); + usleep(10000); + + // Enable Backlight Reset. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); + usleep(60000); + + // Setups DSI packet configuration and request display id. + DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; + _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 3, 0); + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + _display_dsi_send_cmd(MIPI_DSI_DCS_READ, MIPI_DCS_GET_DISPLAY_ID, 0); + _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); + + DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; + _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); + + usleep(5000); + + // MIPI_DCS_GET_DISPLAY_ID reply is a long read, size 3 u32. + for (u32 i = 0; i < 3; i++) + _display_id = DSI(_DSIREG(DSI_RD_DATA)); // Skip ack and msg type info and get the payload (display id). + + // Save raw Display ID to Nyx storage. + nyx_str->info.disp_id = _display_id; + + // Decode Display ID. + _display_id = ((_display_id >> 8) & 0xFF00) | (_display_id & 0xFF); + + if ((_display_id & 0xFF) == PANEL_JDI_XXX062M) + _display_id = PANEL_JDI_XXX062M; + + // Initialize display panel. + switch (_display_id) + { + case PANEL_JDI_XXX062M: + exec_cfg((u32 *)DSI_BASE, _display_init_config_jdi, 43); + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + break; + case PANEL_INL_P062CCA_AZ1: + case PANEL_AUO_A062TAN01: + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + DSI(_DSIREG(DSI_WR_DATA)) = 0x739; // MIPI_DSI_DCS_LONG_WRITE: 7 bytes. + if (_display_id == PANEL_INL_P062CCA_AZ1) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + DSI(_DSIREG(DSI_WR_DATA)) = 0x143209; // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + case PANEL_INL_P062CCA_AZ2: + case PANEL_AUO_A062TAN02: + default: // Allow spare part displays to work. + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000); + break; + } + + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); + + // Configure PLLD for DISP1. + plld_div = (1 << 20) | (24 << 11) | 1; // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 768 MHz, PLLD_OUT0 (DSI): 460.8 MHz. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = 0x20; + CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = 0x2DFC00; // Use new PLLD_SDM_DIN. + + // Finalize DSI configuration. + exec_cfg((u32 *)DSI_BASE, _display_dsi_packet_config, 21); + DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; // PCD1 | div3. + exec_cfg((u32 *)DSI_BASE, _display_dsi_mode_config, 10); + usleep(10000); + + // Calibrate display communication pads. + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_pad_cal_config, 6); + exec_cfg((u32 *)DSI_BASE, _display_dsi_pad_cal_config, 4); + exec_cfg((u32 *)MIPI_CAL_BASE, _display_mipi_apply_dsi_cal_config, 16); + usleep(10000); + + // Enable video display controller. + exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_enable_config, 113); +} + +void display_backlight_pwm_init() +{ + clock_enable_pwm(); + + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. + + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. +} + +void display_backlight(bool enable) +{ + gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO. +} + +void display_backlight_brightness(u32 brightness, u32 step_delay) +{ + u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF; + if (brightness == old_value) + return; + + if (brightness > 255) + brightness = 255; + + if (old_value < brightness) + { + for (u32 i = old_value; i < brightness + 1; i++) + { + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. + usleep(step_delay); + } + } + else + { + for (u32 i = old_value; i > brightness; i--) + { + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. + usleep(step_delay); + } + } + if (!brightness) + PWM(PWM_CONTROLLER_PWM_CSR_0) = 0; +} + +void display_end() +{ + display_backlight_brightness(0, 1000); + + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE; + DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF + + DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. + + // De-initialize video controller. + exec_cfg((u32 *)DISPLAY_A_BASE, _display_video_disp_controller_disable_config, 17); + exec_cfg((u32 *)DSI_BASE, _display_dsi_timing_deinit_config, 16); + usleep(10000); + + // De-initialize display panel. + switch (_display_id) + { + case PANEL_JDI_XXX062M: + exec_cfg((u32 *)DSI_BASE, _display_deinit_config_jdi, 22); + break; + case PANEL_AUO_A062TAN01: + exec_cfg((u32 *)DSI_BASE, _display_deinit_config_auo, 37); + break; + case PANEL_INL_P062CCA_AZ2: + case PANEL_AUO_A062TAN02: + DSI(_DSIREG(DSI_WR_DATA)) = 0x439; // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + DSI(_DSIREG(DSI_WR_DATA)) = 0x9483FFB9; // Enable extension cmd. (Pass: FF 83 94). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + // Set Power. + DSI(_DSIREG(DSI_WR_DATA)) = 0xB39; // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + if (_display_id == PANEL_INL_P062CCA_AZ2) + DSI(_DSIREG(DSI_WR_DATA)) = 0x751548B1; // Set Power control. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40). + else + DSI(_DSIREG(DSI_WR_DATA)) = 0x711148B1; // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + DSI(_DSIREG(DSI_WR_DATA)) = 0x71143209; + DSI(_DSIREG(DSI_WR_DATA)) = 0x114D31; // Set Power control. (Unknown). + DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; + usleep(5000); + break; + case PANEL_INL_P062CCA_AZ1: + default: + break; + } + + _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE, 50000); + + // Disable display and backlight pins. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. + usleep(10000); + + gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. + usleep(10000); + + gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. + usleep(10000); + + // Disable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. + + // Power down pads. + DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); + DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; + + // Switch to automatic function mode. + gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. + + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; +} + +void display_color_screen(u32 color) +{ + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8); + + // Configure display to show single color. + DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0; + DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0; + DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; + DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; + usleep(35000); + + display_backlight(true); +} + +u32 *display_init_framebuffer_pitch() +{ + // Sanitize framebuffer area. + memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000); + + // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch, 32); + usleep(35000); + + return (u32 *)IPL_FB_ADDRESS; +} + +u32 *display_init_framebuffer_pitch_inv() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_pitch_inv, 34); + + usleep(35000); + + return (u32 *)NYX_FB_ADDRESS; +} + +u32 *display_init_framebuffer_block() +{ + // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_block, 34); + + usleep(35000); + + return (u32 *)NYX_FB_ADDRESS; +} + +u32 *display_init_framebuffer_log() +{ + // This configures the framebuffer @ LOG_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer_log, 20); + + return (u32 *)LOG_FB_ADDRESS; +} + +void display_activate_console() +{ + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = WIN_ENABLE; // Enable window DD. + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0xFF80; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + + for (u32 i = 0xFF80; i < 0x10000; i++) + { + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(1000); + } + + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_deactivate_console() +{ + DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; // Select window C. + + for (u32 i = 0xFFFF; i > 0xFF7F; i--) + { + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = i & 0xFFFF; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; + usleep(500); + } + + DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0; + DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0; // Disable window DD. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ; +} + +void display_init_cursor(void *crs_fb, u32 size) +{ + // Setup cursor. + DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10); + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = + CURSOR_BLEND_R8G8B8A8 | CURSOR_BLEND_DST_FACTOR(CURSOR_BLEND_K1) | CURSOR_BLEND_SRC_FACTOR(CURSOR_BLEND_K1) | 0xFF; + + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) |= CURSOR_ENABLE; + + // Arm and activate changes. + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_set_pos_cursor(u32 x, u32 y) +{ + DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16); + + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} + +void display_deinit_cursor() +{ + DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = 0; + DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | CURSOR_UPDATE; + DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; +} diff --git a/ariane/src/hwinit/di.h b/ariane/src/bdk/gfx/di.h similarity index 54% rename from ariane/src/hwinit/di.h rename to ariane/src/bdk/gfx/di.h index 88dc9b7..2723de0 100644 --- a/ariane/src/hwinit/di.h +++ b/ariane/src/bdk/gfx/di.h @@ -1,27 +1,44 @@ /* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef _DI_H_ #define _DI_H_ -#include "types.h" +#include +#include /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) +// Display controller scratch registers. +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_0 0xED +#define DC_D_WINBUF_DD_SCRATCH_REGISTER_1 0xEE +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_0 0x16D +#define DC_T_WINBUF_TD_SCRATCH_REGISTER_1 0x16E +#define DC_COM_SCRATCH_REGISTER_A 0x325 +#define DC_COM_SCRATCH_REGISTER_B 0x326 +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_0 0xBED +#define DC_A_WINBUF_AD_SCRATCH_REGISTER_1 0xBEE +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_0 0xDED +#define DC_B_WINBUF_BD_SCRATCH_REGISTER_1 0xDEE +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_0 0xFED +#define DC_C_WINBUF_CD_SCRATCH_REGISTER_1 0xFEE + +// DC_CMD non-shadowed command/sync registers. #define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 @@ -48,6 +65,7 @@ #define PM0_ENABLE (1 << 16) #define PM1_ENABLE (1 << 18) +#define DC_CMD_INT_STATUS 0x37 #define DC_CMD_INT_MASK 0x38 #define DC_CMD_INT_ENABLE 0x39 @@ -60,11 +78,13 @@ #define WIN_A_ACT_REQ (1 << 1) #define WIN_B_ACT_REQ (1 << 2) #define WIN_C_ACT_REQ (1 << 3) +#define WIN_D_ACT_REQ (1 << 4) #define CURSOR_ACT_REQ (1 << 7) #define GENERAL_UPDATE (1 << 8) #define WIN_A_UPDATE (1 << 9) #define WIN_B_UPDATE (1 << 10) #define WIN_C_UPDATE (1 << 11) +#define WIN_D_UPDATE (1 << 12) #define CURSOR_UPDATE (1 << 15) #define NC_HOST_TRIG (1 << 24) @@ -72,15 +92,38 @@ #define WINDOW_A_SELECT (1 << 4) #define WINDOW_B_SELECT (1 << 5) #define WINDOW_C_SELECT (1 << 6) +#define WINDOW_D_SELECT (1 << 7) #define DC_CMD_REG_ACT_CONTROL 0x043 +// DC_D_WIN_DD window D instance of DC_WIN +#define DC_D_WIN_DD_WIN_OPTIONS 0x80 +#define DC_D_WIN_DD_COLOR_DEPTH 0x83 +#define DC_D_WIN_DD_POSITION 0x84 +#define DC_D_WIN_DD_SIZE 0x85 +#define DC_D_WIN_DD_LINE_STRIDE 0x8A +#define DC_D_WIN_DD_BLEND_LAYER_CONTROL 0x96 +#define DC_D_WIN_DD_BLEND_MATCH_SELECT 0x97 +#define DC_D_WIN_DD_BLEND_ALPHA_1BIT 0x99 + +// DC_D_WINBUF_DD window D instance of DC_WINBUF +#define DC_D_WINBUF_DD_START_ADDR 0xC0 +#define DC_D_WINBUF_DD_ADDR_H_OFFSET 0xC6 +#define DC_D_WINBUF_DD_ADDR_V_OFFSET 0xC8 +#define DC_D_WINBUF_DD_START_ADDR_HI 0xCD +#define DC_D_WINBUF_DD_MEMFETCH_CONTROL 0xEB + +// DC_T_WIN_TD macro for using DD defines. +#define _DC_T(reg) ((reg) + 0x80) + +// DC_COM non-shadowed registers. #define DC_COM_CRC_CONTROL 0x300 #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) #define DC_COM_DSC_TOP_CTL 0x33E +// DC_DISP shadowed registers. #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) #define DSI_ENABLE (1 << 29) @@ -159,7 +202,35 @@ #define DE_CONTROL_EARLY (3 << 2) #define DE_CONTROL_ACTIVE_BLANK (4 << 2) +// Cursor configuration registers. +#define DC_DISP_CURSOR_FOREGROUND 0x43C +#define DC_DISP_CURSOR_BACKGROUND 0x43D +#define CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16)) + +#define DC_DISP_CURSOR_START_ADDR 0x43E +#define CURSOR_CLIPPING(w) ((w) << 28) +#define CURSOR_CLIP_WIN_A 1 +#define CURSOR_CLIP_WIN_B 2 +#define CURSOR_CLIP_WIN_C 3 +#define CURSOR_SIZE_32 (0 << 24) +#define CURSOR_SIZE_64 (1 << 24) +#define CURSOR_SIZE_128 (2 << 24) +#define CURSOR_SIZE_256 (3 << 24) +#define DC_DISP_CURSOR_POSITION 0x440 +#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC +#define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1 +#define CURSOR_BLEND_2BIT (0 << 24) +#define CURSOR_BLEND_R8G8B8A8 (1 << 24) +#define CURSOR_BLEND_SRC_FACTOR(n) ((n) << 8) +#define CURSOR_BLEND_DST_FACTOR(n) ((n) << 16) +#define CURSOR_BLEND_ZRO 0 +#define CURSOR_BLEND_K1 1 +#define CURSOR_BLEND_NK1 2 +// End of cursor cfg regs. + #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 +#define DC_DISP_SD_BL_PARAMETERS 0x4D7 +#define DC_DISP_SD_BL_CONTROL 0x4DC #define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_WIN_CSC_YOF 0x611 @@ -174,14 +245,22 @@ #define DC_WIN_BD_WIN_OPTIONS 0xD80 #define DC_WIN_CD_WIN_OPTIONS 0xF80 -//The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). +// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). #define DC_WIN_WIN_OPTIONS 0x700 #define H_DIRECTION (1 << 0) #define V_DIRECTION (1 << 2) +#define SCAN_COLUMN (1 << 4) #define COLOR_EXPAND (1 << 6) #define CSC_ENABLE (1 << 18) #define WIN_ENABLE (1 << 30) +#define DC_WIN_BUFFER_CONTROL 0x702 +#define BUFFER_CONTROL_HOST 0 +#define BUFFER_CONTROL_VI 1 +#define BUFFER_CONTROL_EPP 2 +#define BUFFER_CONTROL_MPEGE 3 +#define BUFFER_CONTROL_SB2D 4 + #define DC_WIN_COLOR_DEPTH 0x703 #define WIN_COLOR_DEPTH_P1 0x0 #define WIN_COLOR_DEPTH_P2 0x1 @@ -206,8 +285,9 @@ #define WIN_COLOR_DEPTH_YCbCr422RA 0x18 #define WIN_COLOR_DEPTH_YUV422RA 0x19 -#define DC_WIN_BUFFER_CONTROL 0x702 #define DC_WIN_POSITION 0x704 +#define H_POSITION(x) (((x) & 0xFfff) << 0) +#define V_POSITION(x) (((x) & 0x1fff) << 16) #define DC_WIN_SIZE 0x705 #define H_SIZE(x) (((x) & 0x1fff) << 0) @@ -225,13 +305,55 @@ #define V_DDA_INC(x) (((x) & 0xffff) << 16) #define DC_WIN_LINE_STRIDE 0x70A +#define LINE_STRIDE(x) (x) +#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E -//The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). +#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716 +#define WIN_K1(x) (((x) & 0xff) << 8) +#define WIN_K2(x) (((x) & 0xff) << 16) +#define WIN_BLEND_ENABLE (0 << 24) +#define WIN_BLEND_BYPASS (1 << 24) + +#define DC_WINBUF_BLEND_MATCH_SELECT 0x717 +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ZERO (0 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ONE (1 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 (2 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_DST (3 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (4 << 0) +#define WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC (5 << 0) + +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ZERO (0 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ONE (1 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1 (2 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K2 (3 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1_TIMES_DST (4 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (5 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC (6 << 4) +#define WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 (7 << 4) + +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_ZERO (0 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K1 (1 << 8) +#define WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 (2 << 8) + +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO (0 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ONE (1 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_NEG_K1_TIMES_SRC (2 << 12) +#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12) + +#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719 +#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xff) << 0) +#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xff) << 8) + +/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 #define DC_WINBUF_ADDR_V_OFFSET 0x808 #define DC_WINBUF_SURFACE_KIND 0x80B +#define PITCH (0 << 0) +#define TILED (1 << 0) +#define BLOCK (2 << 0) +#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) /*! Display serial interface registers. */ #define _DSIREG(reg) ((reg) * 4) @@ -323,8 +445,9 @@ #define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) -#define DSI_PAD_CONTROL_CD 0x4c +#define DSI_PAD_CONTROL_CD 0x4C #define DSI_VIDEO_MODE_CONTROL 0x4E +#define DSI_CMD_PKT_VID_ENABLE 1 #define DSI_PAD_CONTROL_1 0x4F #define DSI_PAD_CONTROL_2 0x50 @@ -336,17 +459,82 @@ #define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) #define DSI_PAD_CONTROL_4 0x52 +#define DSI_INIT_SEQ_DATA_15 0x5F + +/*! MIPI registers. */ +#define MIPI_CAL_MIPI_CAL_CTRL (0x00 / 0x4) +#define MIPI_CAL_CIL_MIPI_CAL_STATUS (0x08 / 0x4) +#define MIPI_CAL_CILA_MIPI_CAL_CONFIG (0x14 / 0x4) +#define MIPI_CAL_CILB_MIPI_CAL_CONFIG (0x18 / 0x4) +#define MIPI_CAL_CILC_MIPI_CAL_CONFIG (0x1C / 0x4) +#define MIPI_CAL_CILD_MIPI_CAL_CONFIG (0x20 / 0x4) +#define MIPI_CAL_CILE_MIPI_CAL_CONFIG (0x24 / 0x4) +#define MIPI_CAL_CILF_MIPI_CAL_CONFIG (0x28 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG (0x38 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG (0x3C / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG (0x40 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG (0x44 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG0 (0x58 / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG1 (0x5C / 0x4) +#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 (0x60 / 0x4) +#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 (0x64 / 0x4) +#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 (0x68 / 0x4) +#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 (0x70 / 0x4) +#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4) + +/*! MIPI CMDs. */ +#define MIPI_DSI_DCS_SHORT_WRITE 0x05 +#define MIPI_DSI_DCS_READ 0x06 +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 +#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37 +#define MIPI_DSI_DCS_LONG_WRITE 0x39 + +/*! MIPI DCS CMDs. */ +#define MIPI_DCS_GET_DISPLAY_ID 0x04 +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10 +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11 +#define MIPI_DCS_SET_DISPLAY_ON 0x29 + +/* Switch Panels: + * [10] 81 [26]: JDI LPM062M326A + * [10] 96 [09]: JDI LAM062M109A + * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) + * [20] XX [10]: InnoLux P062CCA-AZ2 [UNCONFIRMED ID] + * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) + * [30] XX [10]: AUO A062TAN02 (59.06A33.002) [UNCONFIRMED ID] + */ + +enum +{ + PANEL_JDI_XXX062M = 0x10, + PANEL_JDI_LAM062M109A = 0x0910, + PANEL_JDI_LPM062M326A = 0x2610, + PANEL_INL_P062CCA_AZ1 = 0x0F20, + PANEL_AUO_A062TAN01 = 0x0F30, + PANEL_INL_P062CCA_AZ2 = 0x1020, + PANEL_AUO_A062TAN02 = 0x1030 +}; void display_init(); +void display_backlight_pwm_init(); void display_end(); /*! Show one single color on the display. */ void display_color_screen(u32 color); -/*! Init display in full 1280x720 resolution (32bpp, line stride 768, framebuffer size = 1280*768*4 bytes). */ -u32 *display_init_framebuffer(); +/*! Switches screen backlight ON/OFF. */ +void display_backlight(bool enable); +void display_backlight_brightness(u32 brightness, u32 step_delay); -/*! Enable or disable the backlight. Should only be called when the screen is completely set up, to avoid flickering. */ -void display_enable_backlight(u32 on); +/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */ +u32 *display_init_framebuffer_pitch(); +u32 *display_init_framebuffer_pitch_inv(); +u32 *display_init_framebuffer_block(); +u32 *display_init_framebuffer_log(); +void display_activate_console(); +void display_deactivate_console(); +void display_init_cursor(void *crs_fb, u32 size); +void display_set_pos_cursor(u32 x, u32 y); +void display_deinit_cursor(); #endif diff --git a/ariane/src/hwinit/di.inl b/ariane/src/bdk/gfx/di.inl similarity index 58% rename from ariane/src/hwinit/di.inl rename to ariane/src/bdk/gfx/di.inl index dc795fe..ef3b1b0 100644 --- a/ariane/src/hwinit/di.inl +++ b/ariane/src/bdk/gfx/di.inl @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert +* Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,16 +15,8 @@ * along with this program. If not, see . */ -//Clock config. -static const cfg_op_t _display_config_1[4] = { - {0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 - {0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC -}; - //Display A config. -static const cfg_op_t _display_config_2[94] = { +static const cfg_op_t _display_dc_setup_win_config[94] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, @@ -121,13 +114,13 @@ static const cfg_op_t _display_config_2[94] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} }; //DSI Init config. -static const cfg_op_t _display_config_3[60] = { +static const cfg_op_t _display_dsi_init_config[61] = { {DSI_WR_DATA, 0}, {DSI_INT_ENABLE, 0}, {DSI_INT_STATUS, 0}, @@ -136,6 +129,7 @@ static const cfg_op_t _display_config_3[60] = { {DSI_INIT_SEQ_DATA_1, 0}, {DSI_INIT_SEQ_DATA_2, 0}, {DSI_INIT_SEQ_DATA_3, 0}, + {DSI_INIT_SEQ_DATA_15, 0}, {DSI_DCS_CMDS, 0}, {DSI_PKT_SEQ_0_LO, 0}, {DSI_PKT_SEQ_1_LO, 0}, @@ -190,14 +184,14 @@ static const cfg_op_t _display_config_3[60] = { {DSI_INIT_SEQ_CONTROL, 0} }; -//DSI config (if ver == 0x10). -static const cfg_op_t _display_config_4[43] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, +//DSI panel config. +static const cfg_op_t _display_init_config_jdi[43] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1939}, + {DSI_WR_DATA, 0x1939}, // MIPI_DSI_DCS_LONG_WRITE: 25 bytes. {DSI_WR_DATA, 0xAAAAAAD8}, {DSI_WR_DATA, 0xAAAAAAEB}, {DSI_WR_DATA, 0xAAEBAAAA}, @@ -206,9 +200,9 @@ static const cfg_op_t _display_config_4[43] = { {DSI_WR_DATA, 0xAAEBAAAA}, {DSI_WR_DATA, 0xAA}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x1BD15}, + {DSI_WR_DATA, 0x01BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x1BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2739}, + {DSI_WR_DATA, 0x2739}, // MIPI_DSI_DCS_LONG_WRITE: 39 bytes. {DSI_WR_DATA, 0xFFFFFFD8}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, @@ -220,25 +214,25 @@ static const cfg_op_t _display_config_4[43] = { {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2BD15}, + {DSI_WR_DATA, 0x02BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x2BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xF39}, + {DSI_WR_DATA, 0xF39}, // MIPI_DSI_DCS_LONG_WRITE: 15 bytes. {DSI_WR_DATA, 0xFFFFFFD8}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFFFF}, {DSI_WR_DATA, 0xFFFFFF}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xBD15}, + {DSI_WR_DATA, 0x00BD15}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x0BD. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x6D915}, + {DSI_WR_DATA, 0x06D915}, // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0x6D9. {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; -//DSI config. -static const cfg_op_t _display_config_5[21] = { +//DSI packet config. +static const cfg_op_t _display_dsi_packet_config[21] = { {DSI_PAD_CONTROL_1, 0}, {DSI_PHY_TIMING_0, 0x6070601}, {DSI_PHY_TIMING_1, 0x40A0E05}, @@ -262,15 +256,8 @@ static const cfg_op_t _display_config_5[21] = { {DSI_HOST_CONTROL, 0}, }; -//Clock config. -static const cfg_op_t _display_config_6[3] = { - {0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE - {0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1 - {0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC -}; - -//DSI config. -static const cfg_op_t _display_config_7[10] = { +//DSI mode config. +static const cfg_op_t _display_dsi_mode_config[10] = { {DSI_TRIGGER, 0}, {DSI_CONTROL, 0}, {DSI_SOL_DELAY, 6}, @@ -284,17 +271,17 @@ static const cfg_op_t _display_config_7[10] = { }; //MIPI CAL config. -static const cfg_op_t _display_config_8[6] = { - {0x18, 0}, - {2, 0xF3F10000}, - {0x16, 1}, - {0x18, 0}, - {0x18, 0x10010}, - {0x17, 0x300} +static const cfg_op_t _display_mipi_pad_cal_config[6] = { + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, + {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, + {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300} }; //DSI config. -static const cfg_op_t _display_config_9[4] = { +static const cfg_op_t _display_dsi_pad_cal_config[4] = { {DSI_PAD_CONTROL_1, 0}, {DSI_PAD_CONTROL_2, 0}, {DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, @@ -302,27 +289,27 @@ static const cfg_op_t _display_config_9[4] = { }; //MIPI CAL config. -static const cfg_op_t _display_config_10[16] = { - {0xE, 0x200200}, - {0xF, 0x200200}, - {0x19, 0x200002}, - {0x1A, 0x200002}, - {5, 0}, - {6, 0}, - {7, 0}, - {8, 0}, - {9, 0}, - {0xA, 0}, - {0x10, 0}, - {0x11, 0}, - {0x1A, 0}, - {0x1C, 0}, - {0x1D, 0}, - {0, 0x2A000001} +static const cfg_op_t _display_mipi_apply_dsi_cal_config[16] = { + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, + {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}, + {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, + {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}, + {MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001} }; //Display A config. -static const cfg_op_t _display_config_11[113] = { +static const cfg_op_t _display_video_disp_controller_enable_config[113] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, @@ -403,7 +390,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_STATE_ACCESS, 0}, @@ -413,7 +400,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_DISP_SYNC_WIDTH, 0x10048}, {DC_DISP_BACK_PORCH, 0x90048}, {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. + {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. /* End of Display timings */ {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, @@ -447,13 +434,13 @@ static const cfg_op_t _display_config_11[113] = { }; ////Display A config. -static const cfg_op_t _display_config_12[17] = { +static const cfg_op_t _display_video_disp_controller_disable_config[17] = { {DC_DISP_FRONT_PORCH, 0xA0088}, {DC_CMD_INT_MASK, 0}, {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_INT_ENABLE, 0}, {DC_CMD_CONT_SYNCPT_VSYNC, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, @@ -468,15 +455,15 @@ static const cfg_op_t _display_config_12[17] = { }; //DSI config. -static const cfg_op_t _display_config_13[16] = { +static const cfg_op_t _display_dsi_timing_deinit_config[16] = { {DSI_POWER_CONTROL, 0}, {DSI_PAD_CONTROL_1, 0}, {DSI_PHY_TIMING_0, 0x6070601}, {DSI_PHY_TIMING_1, 0x40A0E05}, - {DSI_PHY_TIMING_2, 0x30109}, + {DSI_PHY_TIMING_2, 0x30118}, {DSI_BTA_TIMING, 0x190A14}, {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) }, - {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, + {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {DSI_TO_TALLY, 0}, {DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, @@ -488,11 +475,11 @@ static const cfg_op_t _display_config_13[16] = { }; //DSI config (if ver == 0x10). -static const cfg_op_t _display_config_14[22] = { - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0x9483FFB9}, +static const cfg_op_t _display_deinit_config_jdi[22] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x2139}, + {DSI_WR_DATA, 0x2139}, // MIPI_DSI_DCS_LONG_WRITE: 33 bytes. {DSI_WR_DATA, 0x191919D5}, {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19191919}, @@ -503,60 +490,207 @@ static const cfg_op_t _display_config_14[22] = { {DSI_WR_DATA, 0x19191919}, {DSI_WR_DATA, 0x19}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0xB39}, - {DSI_WR_DATA, 0x4F0F41B1}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x4F0F41B1}, // Set Power control. {DSI_WR_DATA, 0xF179A433}, - {DSI_WR_DATA, 0x2D81}, + {DSI_WR_DATA, 0x002D81}, {DSI_TRIGGER, DSI_TRIGGER_HOST}, - {DSI_WR_DATA, 0x439}, - {DSI_WR_DATA, 0xB9}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. {DSI_TRIGGER, DSI_TRIGGER_HOST} }; +static const cfg_op_t _display_deinit_config_auo[37] = { + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x9483FFB9}, // Enable extension cmd. (Pass: FF 83 94). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D5}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x2C39}, // MIPI_DSI_DCS_LONG_WRITE: 44 bytes. + {DSI_WR_DATA, 0x191919D6}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_WR_DATA, 0x19191919}, + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0xB39}, // MIPI_DSI_DCS_LONG_WRITE: 11 bytes. + {DSI_WR_DATA, 0x711148B1}, // Set Power control. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40). + // Set Power control. (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG). + {DSI_WR_DATA, 0x71143209}, + {DSI_WR_DATA, 0x114D31}, // Set Power control. (Unknown). + {DSI_TRIGGER, DSI_TRIGGER_HOST}, + {DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes. + {DSI_WR_DATA, 0x000000B9}, // Disable extension cmd. + {DSI_TRIGGER, DSI_TRIGGER_HOST} +}; + +static const cfg_op_t _display_init_config_invert[3] = { + {DSI_WR_DATA, 0x239}, + {DSI_WR_DATA, 0x02C1}, // INV_EN. + {DSI_TRIGGER, DSI_TRIGGER_HOST}, +}; + //Display A config. static const cfg_op_t cfg_display_one_color[8] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display. + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display. }; -//Display A config. -static const cfg_op_t cfg_display_framebuffer[32] = { - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. +//Display A config linear pitch. +static const cfg_op_t cfg_display_framebuffer_pitch[32] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_R8G8B8A8}, //T_A8B8G8R8 + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_POSITION, 0}, //(0,0) {DC_WIN_H_INITIAL_DDA, 0}, {DC_WIN_V_INITIAL_DDA, 0}, - {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. - {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, - {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. - {DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. - {DC_WIN_BUFFER_CONTROL, 0}, - {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address. + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. {DC_WINBUF_ADDR_H_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_WIN_WIN_OPTIONS, 0}, - {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE - {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD. - {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. - {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. - {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +//Display A config linear pitch inverse + Win D support. +static const cfg_op_t cfg_display_framebuffer_pitch_inv[34] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, // Linear: 0x383FFC, Block: 0x3813FC. + {DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +//Display A config block linear. +static const cfg_op_t cfg_display_framebuffer_block[34] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(720 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, + {DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, // Linear: 0x383FFC, Block: 0x3813FC. + {DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0. + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, + {DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, // Enable window AD. | SCAN_COLUMN | H_DIRECTION. + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} +}; + +//Display D config. +static const cfg_op_t cfg_display_framebuffer_log[20] = { + {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT}, + {DC_WIN_WIN_OPTIONS, 0}, + {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, + {DC_WIN_POSITION, 0}, //(0,0) + {DC_WIN_H_INITIAL_DDA, 0}, + {DC_WIN_V_INITIAL_DDA, 0}, + {DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(656 * 4)}, + {DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, // 1.0x. + {DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(656)}, + {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(656 * 2) | LINE_STRIDE(656 * 4)}, //656*2x656*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. + {DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST}, + {DC_WINBUF_SURFACE_KIND, PITCH}, + {DC_WINBUF_START_ADDR, LOG_FB_ADDRESS}, // Framebuffer address. + {DC_WINBUF_ADDR_H_OFFSET, 0}, + {DC_WINBUF_ADDR_V_OFFSET, 0}, + {DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200)}, + {DC_WINBUF_BLEND_MATCH_SELECT, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1}, + {DC_WIN_WIN_OPTIONS, 0}, // Enable window DD. + {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_D_UPDATE}, + {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ} }; diff --git a/ariane/src/bdk/gfx_utils.h b/ariane/src/bdk/gfx_utils.h new file mode 100644 index 0000000..ca81a7f --- /dev/null +++ b/ariane/src/bdk/gfx_utils.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GFX_UTILS_H_ +#define _GFX_UTILS_H_ + +#ifdef GFX_INC +#include GFX_INC +#endif + +#endif diff --git a/ariane/src/bdk/ianos/elfload/elf.h b/ariane/src/bdk/ianos/elfload/elf.h new file mode 100644 index 0000000..196cf87 --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elf.h @@ -0,0 +1,589 @@ +/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */ +/* + * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* imported sys/exec_elf.h from OpenBSD */ + +#ifndef ELF_H +#define ELF_H +#include + +typedef uint8_t Elf_Byte; + +typedef uint32_t Elf32_Addr; /* Unsigned program address */ +typedef uint32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef uint32_t Elf32_Word; /* Unsigned large integer */ +typedef uint16_t Elf32_Half; /* Unsigned medium integer */ + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Shalf; + +#ifdef __alpha__ +typedef int64_t Elf64_Sword; +typedef uint64_t Elf64_Word; +#else +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +#endif + +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Xword; + +typedef uint32_t Elf64_Half; +typedef uint16_t Elf64_Quarter; + +/* + * e_ident[] identification indexes + * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html + */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI ID */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] Operating System/ABI */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Id bytes */ + Elf64_Quarter e_type; /* file type */ + Elf64_Quarter e_machine; /* machine type */ + Elf64_Half e_version; /* version number */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* Program hdr offset */ + Elf64_Off e_shoff; /* Section hdr offset */ + Elf64_Half e_flags; /* Processor flags */ + Elf64_Quarter e_ehsize; /* sizeof ehdr */ + Elf64_Quarter e_phentsize; /* Program header entry size */ + Elf64_Quarter e_phnum; /* Number of program headers */ + Elf64_Quarter e_shentsize; /* Section header entry size */ + Elf64_Quarter e_shnum; /* Number of section headers */ + Elf64_Quarter e_shstrndx; /* String table index */ +} Elf64_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +/* + * Don't know if EM_MIPS_RS4_BE, + * EM_SPARC64, EM_PARISC, + * or EM_PPC are ABI compliant + */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_PPC 20 /* PowerPC */ +#define EM_ARM 40 /* ARM AArch32 */ +#define EM_ALPHA 41 /* DEC ALPHA */ +#define EM_SH 42 /* Hitachi/Renesas Super-H */ +#define EM_SPARCV9 43 /* SPARC version 9 */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_AMD64 62 /* AMD64 architecture */ +#define EM_VAX 75 /* DEC VAX */ +#define EM_AARCH64 183 /* ARM AArch64 */ + +/* Non-standard */ +#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct +{ + Elf32_Word sh_name; /* name - index into section header + * string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Half sh_name; /* section name */ + Elf64_Half sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* virtual address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Half sh_link; /* link to another */ + Elf64_Half sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory alignment */ + Elf64_Xword sh_entsize; /* table entry size */ +} Elf64_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_TLS 0x400 /* thread local storage */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \ + * specific section attributes */ + +/* Symbol Table Entry */ +typedef struct elf32_sym +{ + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Half st_name; /* Symbol name index in str table */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Xword st_value; /* value of symbol */ + Elf64_Xword st_size; /* size of symbol */ +} Elf64_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +#define ELF64_ST_BIND(x) ((x) >> 4) +#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_TLS 6 /* thread local storage */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ +} Elf64_Rel; + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ + Elf64_Sxword r_addend; /* adjustment value */ +} Elf64_Rela; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t)) + +#if defined(__mips64__) && defined(__MIPSEL__) +/* + * The 64-bit MIPS ELF ABI uses a slightly different relocation format + * than the regular ELF ABI: the r_info field is split into several + * pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details). + */ +#undef ELF64_R_SYM +#undef ELF64_R_TYPE +#undef ELF64_R_INFO +#define ELF64_R_TYPE(info) (swap32((info) >> 32)) +#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s)) +#endif /* __mips64__ && __MIPSEL__ */ + +/* Program Header */ +typedef struct +{ + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Half p_type; /* entry type */ + Elf64_Half p_flags; /* flags */ + Elf64_Off p_offset; /* offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* file size */ + Elf64_Xword p_memsz; /* memory size */ + Elf64_Xword p_align; /* memory & file alignment */ +} Elf64_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* thread local storage */ +#define PT_LOOS 0x60000000 /* reserved range for OS */ +#define PT_HIOS 0x6fffffff /* specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ +#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ + +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Xword d_tag; /* controls meaning of d_val */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library \ + * search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ +#define DT_LOOS 0x6000000d /* reserved range for OS */ +#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* some other useful tags */ +#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ +#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ +#define DT_FLAGS_1 0x6ffffffb + +/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONLFAT 0x00002000 + +/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ +#define DT_NUM (DT_JMPREL + 1) + +/* + * Note Definitions + */ +typedef struct +{ + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; +} Elf32_Note; + +typedef struct +{ + Elf64_Half namesz; + Elf64_Half descsz; + Elf64_Half type; +} Elf64_Note; + +#if defined(ELFSIZE) && (ELFSIZE == 32) +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_RelA Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Half Elf32_Half +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_Nhdr Elf32_Nhdr +#define Elf_Note Elf32_Note + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELFCLASS ELFCLASS32 + +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#elif defined(ELFSIZE) && (ELFSIZE == 64) + +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_RelA Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Half Elf64_Half +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_Nhdr Elf64_Nhdr +#define Elf_Note Elf64_Note + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELFCLASS ELFCLASS64 + +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#endif + +#endif diff --git a/ariane/src/bdk/ianos/elfload/elfarch.h b/ariane/src/bdk/ianos/elfload/elfarch.h new file mode 100644 index 0000000..f1cc388 --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elfarch.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ELFARCH_H +#define ELFARCH_H + +#if defined(__i386__) +#define EM_THIS EM_386 +#define EL_ARCH_USES_REL +#elif defined(__amd64__) +#define EM_THIS EM_AMD64 +#define EL_ARCH_USES_RELA +#elif defined(__arm__) +#define EM_THIS EM_ARM +#define EL_ARCH_USES_REL +#elif defined(__aarch64__) +#define EM_THIS EM_AARCH64 +#define EL_ARCH_USES_RELA +#define EL_ARCH_USES_REL +#else +#error specify your ELF architecture +#endif + +#if defined(__LP64__) || defined(__LLP64__) +#define ELFSIZE 64 +#else +#define ELFSIZE 32 +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define ELFDATATHIS ELFDATA2LSB +#else +#define ELFDATATHIS ELFDATA2MSB +#endif + +#endif diff --git a/ariane/src/bdk/ianos/elfload/elfload.c b/ariane/src/bdk/ianos/elfload/elfload.c new file mode 100644 index 0000000..16f8200 --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elfload.c @@ -0,0 +1,324 @@ +/* + * Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "elfload.h" + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset) +{ + return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO; +} + +#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize)) +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + for (; *i < ctx->ehdr.e_phnum; (*i)++) + { + if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i)))) + return rv; + + if (phdr->p_type == type) + { + return rv; + } + } + + *i = -1; + return rv; +} + +#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize)) +el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + + for (; *i < ctx->ehdr.e_shnum; (*i)++) + { + if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i)))) + + return rv; + + if (shdr->sh_type == type) + { + return rv; + } + } + + *i = -1; + + return rv; +} + +el_status el_init(el_ctx *ctx) +{ + el_status rv = EL_OK; + if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0))) + return rv; + + /* validate header */ + + if (!IS_ELF(ctx->ehdr)) + return EL_NOTELF; + + if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS) + return EL_WRONGBITS; + + if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS) + return EL_WRONGENDIAN; + + if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT) + return EL_NOTELF; + + if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN) + return EL_NOTEXEC; + + if (ctx->ehdr.e_machine != EM_THIS) + return EL_WRONGARCH; + + if (ctx->ehdr.e_version != EV_CURRENT) + return EL_NOTELF; + + /* load phdrs */ + Elf_Phdr ph; + + /* iterate through, calculate extents */ + ctx->base_load_paddr = ctx->base_load_vaddr = 0; + ctx->align = 1; + ctx->memsz = 0; + + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr phend = ph.p_vaddr + ph.p_memsz; + if (phend > ctx->memsz) + ctx->memsz = phend; + + if (ph.p_align > ctx->align) + ctx->align = ph.p_align; + + i++; + } + + // Program Header + if (ctx->ehdr.e_type == ET_DYN) + { + i = 0; + + if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + + ctx->dynoff = ph.p_offset; + ctx->dynsize = ph.p_filesz; + } + else + { + ctx->dynoff = 0; + ctx->dynsize = 0; + } + + // Section String Table + if (ctx->ehdr.e_type == ET_DYN) + { + i = ctx->ehdr.e_shstrndx - 1; + + if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i))) + return rv; + + // Reset + i = 0; + + if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + } + + return rv; +} + +/* +typedef void* (*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); +*/ + +el_status el_load(el_ctx *ctx, el_alloc_cb alloc) +{ + el_status rv = EL_OK; + + /* address deltas */ + Elf_Addr pdelta = ctx->base_load_paddr; + Elf_Addr vdelta = ctx->base_load_vaddr; + + /* iterate paddrs */ + Elf_Phdr ph; + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr pload = ph.p_paddr + pdelta; + Elf_Addr vload = ph.p_vaddr + vdelta; + + /* allocate mem */ + char *dest = alloc(ctx, pload, vload, ph.p_memsz); + if (!dest) + return EL_ENOMEM; + + EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n", + ph.p_offset, ph.p_vaddr, dest); + + /* read loaded portion */ + if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset))) + return rv; + + /* zero mem-only portion */ + memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz); + + i++; + } + + return rv; +} + +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) +{ + el_status rv = EL_OK; + size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn); + + for (unsigned i = 0; i < ndyn; i++) + { + if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn))) + return rv; + + if (dyn->d_tag == tag) + return EL_OK; + } + + dyn->d_tag = DT_NULL; + return EL_OK; +} + +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type) +{ + el_status rv = EL_OK; + + Elf_Dyn rel, relsz, relent; + + if ((rv = el_finddyn(ctx, &rel, type))) + return rv; + + if ((rv = el_finddyn(ctx, &relsz, type + 1))) + return rv; + + if ((rv = el_finddyn(ctx, &relent, type + 2))) + return rv; + + if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL) + { + ri->entrysize = 0; + ri->tablesize = 0; + ri->tableoff = 0; + } + else + { + ri->tableoff = rel.d_un.d_ptr; + ri->tablesize = relsz.d_un.d_val; + ri->entrysize = relent.d_un.d_val; + } + + return rv; +} + +extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel); +extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela); + +el_status el_relocate(el_ctx *ctx) +{ + el_status rv = EL_OK; + + // not dynamic + if (ctx->ehdr.e_type != ET_DYN) + return EL_OK; + + char *base = (char *)ctx->base_load_paddr; + + el_relocinfo ri; +#ifdef EL_ARCH_USES_REL + if ((rv = el_findrelocs(ctx, &ri, DT_REL))) + return rv; + + if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_Rel)); + return EL_BADREL; + } + + size_t relcnt = ri.tablesize / sizeof(Elf_Rel); + Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff); + for (size_t i = 0; i < relcnt; i++) + { + if ((rv = el_applyrel(ctx, &reltab[i]))) + return rv; + } +#endif + +#ifdef EL_ARCH_USES_RELA + if ((rv = el_findrelocs(ctx, &ri, DT_RELA))) + return rv; + + if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_RelA)); + return EL_BADREL; + } + + size_t relacnt = ri.tablesize / sizeof(Elf_RelA); + Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff); + for (size_t i = 0; i < relacnt; i++) + { + if ((rv = el_applyrela(ctx, &relatab[i]))) + return rv; + } +#endif + +#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA) +#error No relocation type defined! +#endif + + return rv; +} diff --git a/ariane/src/bdk/ianos/elfload/elfload.h b/ariane/src/bdk/ianos/elfload/elfload.h new file mode 100644 index 0000000..2b9bb67 --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elfload.h @@ -0,0 +1,127 @@ +/* + * Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ELFLOAD_H +#define ELFLOAD_H +#include + +#include "elfarch.h" +#include "elf.h" + +#include + +#ifdef DEBUG +#include +#define EL_DEBUG(format, ...) \ + gfx_printf(format __VA_OPT__(, ) __VA_ARGS__) +#else +#define EL_DEBUG(...) \ + do \ + { \ + } while (0) +#endif + +typedef enum +{ + EL_OK = 0, + + EL_EIO, + EL_ENOMEM, + + EL_NOTELF, + EL_WRONGBITS, + EL_WRONGENDIAN, + EL_WRONGARCH, + EL_WRONGOS, + EL_NOTEXEC, + EL_NODYN, + EL_BADREL, + +} el_status; + +typedef struct el_ctx +{ + bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset); + + /* base_load_* -> address we are actually going to load at + */ + Elf_Addr + base_load_paddr, + base_load_vaddr; + + /* size in memory of binary */ + Elf_Addr memsz; + + /* required alignment */ + Elf_Addr align; + + /* ELF header */ + Elf_Ehdr ehdr; + + // Section Header Str Table + Elf_Shdr shstr; + Elf_Shdr symtab; + + /* Offset of dynamic table (0 if not ET_DYN) */ + Elf_Off dynoff; + /* Size of dynamic table (0 if not ET_DYN) */ + Elf_Addr dynsize; +} el_ctx; + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset); + +el_status el_init(el_ctx *ctx); +typedef void *(*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); + +el_status el_load(el_ctx *ctx, el_alloc_cb alloccb); + +/* find the next phdr of type \p type, starting at \p *i. + * On success, returns EL_OK with *i set to the phdr number, and the phdr loaded + * in *phdr. + * + * If the end of the phdrs table was reached, *i is set to -1 and the contents + * of *phdr are undefined + */ +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i); + +/* Relocate the loaded executable */ +el_status el_relocate(el_ctx *ctx); + +/* find a dynamic table entry + * returns the entry on success, dyn->d_tag = DT_NULL on failure + */ +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type); + +typedef struct +{ + Elf_Off tableoff; + Elf_Addr tablesize; + Elf_Addr entrysize; +} el_relocinfo; + +/* find all information regarding relocations of a specific type. + * + * pass DT_REL or DT_RELA for type + * sets ri->entrysize = 0 if not found + */ +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type); + +#endif diff --git a/ariane/src/bdk/ianos/elfload/elfreloc_aarch64.c b/ariane/src/bdk/ianos/elfload/elfreloc_aarch64.c new file mode 100644 index 0000000..bbb0ce4 --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elfreloc_aarch64.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "elfload.h" + +#if defined(__aarch64__) + +#define R_AARCH64_NONE 0 +#define R_AARCH64_RELATIVE 1027 + +el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p = rel->r_addend + ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p += ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/ariane/src/bdk/ianos/elfload/elfreloc_arm.c b/ariane/src/bdk/ianos/elfload/elfreloc_arm.c new file mode 100644 index 0000000..8b905cb --- /dev/null +++ b/ariane/src/bdk/ianos/elfload/elfreloc_arm.c @@ -0,0 +1,66 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you can do + * whatever you want with this stuff. If we meet some day, and you think this + * stuff is worth it, you can buy me a beer in return. M4xw + * ---------------------------------------------------------------------------- + */ + +#include "elfload.h" + +#if defined(__arm__) + +// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf +#define R_ARM_NONE 0 +#define R_ARM_ABS32 2 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_RELATIVE 23 + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset + uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr + +#if 0 // For later symbol usage + Elf32_Sym *elfSym; + const char *symbolName; + + // We resolve relocs from the originating elf-image + elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym; + int strtab_offset = ctx->shstr.sh_offset; + char *strtab = (char *)buffteg + strtab_offset; + symbolName = strtab + elfSym->st_name; + //EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value); +#endif + + switch (type) + { + case R_ARM_NONE: + EL_DEBUG("R_ARM_NONE\n"); + break; + case R_ARM_JUMP_SLOT: + case R_ARM_ABS32: + case R_ARM_GLOB_DAT: + // Stubbed for later purpose + //*p += elfSym->st_value; // + vaddr from sec + //*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now + break; + case R_ARM_RELATIVE: // Needed for PIE + if (sym) + { + return EL_BADREL; + } + *p += ctx->base_load_vaddr; + break; + + default: + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/ariane/src/bdk/ianos/ianos.c b/ariane/src/bdk/ianos/ianos.c new file mode 100644 index 0000000..5eca1b6 --- /dev/null +++ b/ariane/src/bdk/ianos/ianos.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018 M4xw + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ianos.h" +#include "elfload/elfload.h" +#include +#include +#include +#include + +#include + +#define IRAM_LIB_ADDR 0x4002B000 +#define DRAM_LIB_ADDR 0xE0000000 + +extern heap_t _heap; + +void *elfBuf = NULL; +void *fileBuf = NULL; + +static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig) +{ + bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t)); + bdkParameters->gfxCon = (void *)&gfx_con; + bdkParameters->gfxCtx = (void *)&gfx_ctxt; + bdkParameters->memcpy = (memcpy_t)&memcpy; + bdkParameters->memset = (memset_t)&memset; + bdkParameters->sharedHeap = &_heap; + + entrypoint(moduleConfig, bdkParameters); +} + +static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size) +{ + (void)ctx; + (void)phys; + (void)size; + return (void *)virt; +} + +static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset) +{ + (void)ctx; + + memcpy(dest, fileBuf + offset, numberBytes); + + return true; +} + +//TODO: Support shared libraries. +uintptr_t ianos_loader(char *path, elfType_t type, void *moduleConfig) +{ + el_ctx ctx; + uintptr_t epaddr = 0; + + if (!sd_mount()) + goto elfLoadFinalOut; + + // Read library. + fileBuf = sd_file_read(path, NULL); + + if (!fileBuf) + goto elfLoadFinalOut; + + ctx.pread = _ianos_read_cb; + + if (el_init(&ctx)) + goto elfLoadFinalOut; + + // Set our relocated library's buffer. + switch (type & 0xFFFF) + { + case EXEC_ELF: + case AR64_ELF: + elfBuf = (void *)DRAM_LIB_ADDR; + break; + default: + elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default. + } + + if (!elfBuf) + goto elfLoadFinalOut; + + // Load and relocate library. + ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf; + if (el_load(&ctx, _ianos_alloc_cb)) + goto elfFreeOut; + + if (el_relocate(&ctx)) + goto elfFreeOut; + + // Launch. + epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf; + moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr; + + _ianos_call_ep(ep, moduleConfig); + +elfFreeOut: + free(fileBuf); + elfBuf = NULL; + fileBuf = NULL; + +elfLoadFinalOut: + return epaddr; +} \ No newline at end of file diff --git a/ariane/src/bdk/ianos/ianos.h b/ariane/src/bdk/ianos/ianos.h new file mode 100644 index 0000000..5ebec64 --- /dev/null +++ b/ariane/src/bdk/ianos/ianos.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 M4xw + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef IANOS_H +#define IANOS_H + +#include + +typedef enum +{ + DRAM_LIB = 0, // DRAM library. + EXEC_ELF = 1, // Executable elf that does not return. + DR64_LIB = 2, // AARCH64 DRAM library. + AR64_ELF = 3, // Executable elf that does not return. + KEEP_IN_RAM = (1 << 31) // Shared library mask. +} elfType_t; + +uintptr_t ianos_loader(char *path, elfType_t type, void* config); + +#endif \ No newline at end of file diff --git a/ariane/src/bdk/input/als.c b/ariane/src/bdk/input/als.c new file mode 100644 index 0000000..3f59657 --- /dev/null +++ b/ariane/src/bdk/input/als.c @@ -0,0 +1,117 @@ +/* + * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "als.h" +#include +#include +#include +#include +#include + +#define HOS_GAIN BH1730_GAIN_64X +#define HOS_ITIME 38 + +void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime) +{ + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime)); + + als_val->gain = gain; + als_val->itime = itime; +} + +void get_als_lux(als_table_t *als_val) +{ + u32 data[2]; + float pre_gain_lux; + float visible_light; + float ir_light; + float light_ratio; + + u8 adc_ready = 0; + u8 retries = 100; + + const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 }; + const float als_norm_res = 100.0; + const float als_multiplier = 3.6; + const float als_tint = 2.7; + + // Wait for ADC to prepare new data. + while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries) + { + retries--; + adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG)); + } + + // Get visible and ir light raw data. + data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); + data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + + (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); + + als_val->over_limit = data[0] > 65534 || data[1] > 65534; + als_val->vi_light = data[0]; + als_val->ir_light = data[1]; + + if (!data[0] || !retries) + { + als_val->lux = 0.0; + + return; + } + + visible_light = (float)data[0]; + ir_light = (float)data[1]; + light_ratio = (float)data[1] / (float)data[0]; + + // The following are specific to the light filter Switch uses. + if (light_ratio < 0.5) + pre_gain_lux = visible_light * 5.002 - ir_light * 7.502; + else if (light_ratio < 0.754) + pre_gain_lux = visible_light * 2.250 - ir_light * 2.000; + else if (light_ratio < 1.029) + pre_gain_lux = visible_light * 1.999 - ir_light * 1.667; + else if (light_ratio < 1.373) + pre_gain_lux = visible_light * 0.884 - ir_light * 0.583; + else if (light_ratio < 1.879) + pre_gain_lux = visible_light * 0.309 - ir_light * 0.165; + else pre_gain_lux = 0.0; + + als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier; +} + +u8 als_init(als_table_t *als_val) +{ + pinmux_config_i2c(I2C_2); + clock_enable_i2c(I2C_2); + i2c_init(I2C_2); + + max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD8 | MAX77620_LDO_CFG2_ADE_MASK); + + u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME)); + i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN); + + als_val->gain = HOS_GAIN; + als_val->itime = HOS_ITIME; + + return id; +} diff --git a/ariane/src/bdk/input/als.h b/ariane/src/bdk/input/als.h new file mode 100644 index 0000000..ad31e42 --- /dev/null +++ b/ariane/src/bdk/input/als.h @@ -0,0 +1,65 @@ +/* + * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ALS_H_ +#define __ALS_H_ + +#include + +#define BH1730_I2C_ADDR 0x29 + +#define BH1730_CMD_MAGIC 0x80 +#define BH1730_CMD_SETADDR 0x00 +#define BH1730_CMD_SPECCMD 0x60 +#define BH1730_SPECCMD_RESET 0x4 + +#define BH1730_CONTROL_REG 0x00 +#define BH1730_CTL_ADC_VALID 0x10 +#define BH1730_CTL_ONE_TIME 0x08 +#define BH1730_CTL_DAT0_ONLY 0x04 +#define BH1730_CTL_ADC_EN 0x02 +#define BH1730_CTL_POWER_ON 0x01 +#define BH1730_TIMING_REG 0x01 +#define BH1730_GAIN_REG 0x07 +#define BH1730_GAIN_1X 0x00 +#define BH1730_GAIN_2X 0x01 +#define BH1730_GAIN_64X 0x02 +#define BH1730_GAIN_128X 0x03 +#define BH1730_DATA0LOW_REG 0x14 +#define BH1730_DATA0HIGH_REG 0x15 +#define BH1730_DATA1LOW_REG 0x16 +#define BH1730_DATA1HIGH_REG 0x17 + +#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | reg) +#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | cmd) + +typedef struct _als_table_t +{ + float lux; + bool over_limit; + u32 vi_light; + u32 ir_light; + u8 gain; + u8 itime; +} als_table_t; + +void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime); +void get_als_lux(als_table_t *als_val); +u8 als_init(als_table_t *als_val); + +#endif /* __ALS_H_ */ diff --git a/ariane/src/bdk/input/joycon.c b/ariane/src/bdk/input/joycon.c new file mode 100644 index 0000000..2db1aa6 --- /dev/null +++ b/ariane/src/bdk/input/joycon.c @@ -0,0 +1,872 @@ +/* + * Joy-Con UART driver for Nintendo Switch + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "joycon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// For disabling driver when logging is enabled. +#include + +#define JC_WIRED_CMD 0x91 +#define JC_WIRED_HID 0x92 +#define JC_WIRED_INIT_REPLY 0x94 +#define JC_INIT_HANDSHAKE 0xA5 + +#define JC_WIRED_CMD_MAC 0x01 +#define JC_WIRED_CMD_10 0x10 + +#define JC_HID_OUTPUT_RPT 0x01 +#define JC_HID_RUMBLE_RPT 0x10 + +#define JC_HID_INPUT_RPT 0x30 +#define JC_HID_SUBMCD_RPT 0x21 + +#define JC_HID_SUBCMD_HCI_STATE 0x06 +#define HCI_STATE_SLEEP 0x00 +#define HCI_STATE_RECONNECT 0x01 +#define HCI_STATE_PAIR 0x02 +#define HCI_STATE_HOME 0x04 +#define JC_HID_SUBCMD_SPI_READ 0x10 +#define SPI_READ_OFFSET 0x20 +#define JC_HID_SUBCMD_RUMBLE_CTL 0x48 +#define JC_HID_SUBCMD_SND_RUMBLE 0xFF + +#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status. +#define JC_BTN_MASK_R 0x76FF + +#define JC_ID_L 1 +#define JC_ID_R 2 + +enum +{ + JC_BATT_EMTPY = 0, + JC_BATT_CRIT = 2, + JC_BATT_LOW = 4, + JC_BATT_MID = 6, + JC_BATT_FULL = 8 +}; + +static const u8 init_jc[] = { + 0xA1, 0xA2, 0xA3, 0xA4 +}; + +static const u8 init_handshake[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd. + 0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data. +}; + +static const u8 init_get_info[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_MAC, // Wired cmd and subcmd. + 0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data. +}; + +static const u8 init_finilize[] = { + 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. + JC_WIRED_CMD, JC_WIRED_CMD_10, // Wired cmd and subcmd. + 0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data. +}; + +static const u8 nx_pad_status[] = { + 0x19, 0x01, 0x03, 0x08, 0x00, // Uart header. + JC_WIRED_HID, 0x00, // Wired cmd and hid cmd. + 0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data. +}; + +typedef struct _jc_uart_hdr_t +{ + u8 magic[3]; + u8 total_size_lsb; + u8 total_size_msb; +} jc_uart_hdr_t; + +typedef struct _jc_wired_hdr_t +{ + jc_uart_hdr_t uart_hdr; + u8 cmd; + u8 data[5]; + u8 crc; + u8 payload[]; +} jc_wired_hdr_t; + +typedef struct _jc_hid_out_rpt_t +{ + u8 cmd; + u8 pkt_id; + u8 rumble[8]; + u8 subcmd; + u8 subcmd_data[]; +} jc_hid_out_rpt_t; + +typedef struct _jc_hid_out_spi_read_t +{ + u32 addr; + u8 size; +} jc_hid_out_spi_read_t; + +typedef struct _jc_hid_in_rpt_t +{ + u8 cmd; + u8 pkt_id; + u8 conn_info:4; + u8 batt_info:4; + u8 btn_right; + u8 btn_shared; + u8 btn_left; + u8 stick_h_left; + u8 stick_m_left; + u8 stick_v_left; + u8 stick_h_right; + u8 stick_m_right; + u8 stick_v_right; + u8 vib_decider; + u8 submcd_ack; + u8 subcmd; + u8 subcmd_data[]; +} jc_hid_in_rpt_t; + +typedef struct _jc_hid_in_spi_read_t +{ + u32 addr; + u8 size; + u8 data[]; +} jc_hid_in_spi_read_t; + +typedef struct _jc_hid_in_pair_data_t +{ + u8 magic; + u8 size; + u16 checksum; + u8 mac[6]; + u8 ltk[16]; + u8 pad0[10]; + u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported + u8 pad1; +} jc_hid_in_pair_data_t; + +typedef struct _joycon_ctxt_t +{ + u8 buf[0x100]; //FIXME: If heap is used, dumping breaks. + u8 uart; + u8 type; + u8 mac[6]; + u32 hw_init_done; + u32 last_received_time; + u32 last_status_req_time; + u8 rumble_sent; + u8 connected; +} joycon_ctxt_t; + +static joycon_ctxt_t jc_l; +static joycon_ctxt_t jc_r; + +static bool jc_init_done = false; +static u32 hid_pkt_inc = 0; + +static jc_gamepad_rpt_t jc_gamepad; + +void jc_power_supply(u8 uart, bool enable); + +void joycon_send_raw(u8 uart_port, const u8 *buf, u16 size) +{ + uart_send(uart_port, buf, size); + uart_wait_idle(uart_port, UART_TX_IDLE); +} + +static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size) +{ + out->uart_hdr.magic[0] = 0x19; + out->uart_hdr.magic[1] = 0x01; + out->uart_hdr.magic[2] = 0x3; + + out->uart_hdr.total_size_lsb = 7; + out->uart_hdr.total_size_msb = 0; + out->cmd = wired_cmd; + + if (data) + memcpy(out->data, data, size); + + out->crc = 0; // wired crc8ccit can be skipped. + + return sizeof(jc_wired_hdr_t); +} + +static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size) +{ + u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0); + pkt_size += size; + + rpt->uart_hdr.total_size_lsb += size; + rpt->data[0] = size >> 8; + rpt->data[1] = size & 0xFF; + + if (payload) + memcpy(rpt->payload, payload, size); + + return pkt_size; +} + +void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size) +{ + u8 rpt[0x50]; + memset(rpt, 0, sizeof(rpt)); + + u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size); + + joycon_send_raw(uart, rpt, rpt_size); +} + +static u8 jc_hid_pkt_id_incr() +{ + u8 curr_id = hid_pkt_inc; + hid_pkt_inc++; + + return (curr_id & 0xF); +} + +void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size) +{ + u8 temp[0x30]; + u8 rumble_neutral[8] = {0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40}; + u8 rumble_init[8] = {0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72}; + + memset(temp, 0, sizeof(temp)); + + jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp; + + memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral)); + + if (subcmd == JC_HID_SUBCMD_SND_RUMBLE) + { + bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent; + bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent; + + // Enable rumble. + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->pkt_id = jc_hid_pkt_id_incr(); + hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL; + hid_pkt->subcmd_data[0] = 1; + if (send_r_rumble) + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10); + if (send_l_rumble) + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10); + + // Send rumble. + hid_pkt->cmd = JC_HID_RUMBLE_RPT; + hid_pkt->pkt_id = jc_hid_pkt_id_incr(); + memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init)); + if (send_r_rumble) + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10); + if (send_l_rumble) + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10); + + msleep(15); + + // Disable rumble. + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->pkt_id = jc_hid_pkt_id_incr(); + hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL; + hid_pkt->subcmd_data[0] = 0; + memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral)); + if (send_r_rumble) + jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10); + if (send_l_rumble) + jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10); + } + else + { + hid_pkt->cmd = JC_HID_OUTPUT_RPT; + hid_pkt->pkt_id = jc_hid_pkt_id_incr(); + hid_pkt->subcmd = subcmd; + if (data) + memcpy(hid_pkt->subcmd_data, data, size); + + u8 pkt_size = sizeof(jc_hid_out_rpt_t) + size; + + jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size); + } +} + +static void jc_charging_decider(u8 batt, u8 uart) +{ + u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000; + + // Power supply control based on battery levels and charging. + if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging. + jc_power_supply(uart, true); + else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit. + jc_power_supply(uart, false); +} + +static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size) +{ + u32 btn_tmp; + jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet; + + switch (hid_pkt->cmd) + { + case JC_HID_INPUT_RPT: + btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16; + + if (jc->type & JC_ID_L) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L); + + jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8); + jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4); + + jc_gamepad.batt_info_l = hid_pkt->batt_info; + } + else if (jc->type & JC_ID_R) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R); + + jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8); + jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4); + + jc_gamepad.batt_info_r = hid_pkt->batt_info; + } + + jc_gamepad.conn_l = jc_l.connected; + jc_gamepad.conn_r = jc_r.connected; + + jc_charging_decider(hid_pkt->batt_info, jc->uart); + break; + case JC_HID_SUBMCD_RPT: + if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ) + { + jc_bt_conn_t *bt_conn; + + if (jc->type & JC_ID_L) + bt_conn = &jc_gamepad.bt_conn_l; + else + bt_conn = &jc_gamepad.bt_conn_r; + + jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data; + jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data; + + // Check if we reply is pairing info. + if (spi_info->size == 0x1A && pair_data->magic == 0x95 && pair_data->size == 0x22) + { + bt_conn->type = jc->type; + + memcpy(bt_conn->mac, jc->mac, 6); + memcpy(bt_conn->host_mac, pair_data->mac, 6); + for (u32 i = 16; i > 0; i--) + bt_conn->ltk[16 - i] = pair_data->ltk[i - 1]; + } + } + break; + default: + break; + } + jc->last_received_time = get_tmr_ms(); +} + +static void jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size) +{ + switch (data[0]) + { + case JC_WIRED_CMD_MAC: + for (int i = 12; i > 6; i--) + jc->mac[12 - i] = data[i]; + jc->type = data[6]; + jc->connected = true; + default: + break; + } +} + +static void jc_uart_pkt_parse(joycon_ctxt_t *jc, const u8* packet, size_t size) +{ + jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)packet; + switch (pkt->cmd) + { + case JC_WIRED_HID: + jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]); + break; + case JC_WIRED_INIT_REPLY: + jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1); + break; + default: + break; + } +} + +static void jc_rcv_pkt(joycon_ctxt_t *jc) +{ + if (gpio_read(GPIO_PORT_E, GPIO_PIN_6) && jc->uart == UART_C) + return; + else if (gpio_read(GPIO_PORT_H, GPIO_PIN_6) && jc->uart == UART_B) + return; + + // Check if device stopped sending data. + u32 uart_irq = uart_get_IIR(jc->uart); + if ((uart_irq & 0x8) != 0x8) + return; + + u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0x100); + + // Check valid size and uart reply magic. + if (len > 7 && !memcmp(jc->buf, "\x19\x81\x03", 3)) + { + jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)(jc->buf); + + jc_uart_pkt_parse(jc, jc->buf, pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t)); + } +} + +static bool jc_send_init_rumble(joycon_ctxt_t *jc) +{ + // Send init rumble or request nx pad status report. + if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent)) + { + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0); + + if (jc_l.connected) + jc_l.rumble_sent = true; + if (jc_r.connected) + jc_r.rumble_sent = true; + + if (jc->uart != UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + else + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + + return 1; + } + + return 0; +} + +static void jc_req_nx_pad_status(joycon_ctxt_t *jc) +{ + bool sent_rumble = jc_send_init_rumble(jc); + + if (sent_rumble) + return; + + if (jc->last_status_req_time > get_tmr_ms() || !jc->connected) + return; + + // Turn off Joy-Con detect. + if (jc->uart == UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + else + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status)); + + // Turn Joy-Con detect on. + if (jc->uart == UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + else + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + + jc->last_status_req_time = get_tmr_ms() + 15; +} + +static bool _jc_validate_pairing_info(u8 *buf, bool *is_hos) +{ + u8 crc = 0; + for (u32 i = 0; i < 0x22; i++) + crc += buf[4 + i]; + + crc += 0x68; // Host is Switch. + + if ((crc ^ 0x55) == buf[2]) + *is_hos = true; + + crc -= 0x68; + crc += 0x08; // Host is PC. + + if (*is_hos || (crc ^ 0x55) == buf[2]) + return true; + + return false; +} + +jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos) +{ + u8 retries; + jc_bt_conn_t *bt_conn; + + bt_conn = &jc_gamepad.bt_conn_l; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + + bt_conn = &jc_gamepad.bt_conn_r; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + + while (jc_l.last_status_req_time > get_tmr_ms()) + { + jc_rcv_pkt(&jc_r); + jc_rcv_pkt(&jc_l); + } + + jc_hid_in_spi_read_t subcmd_data_l; + subcmd_data_l.addr = 0x2000; + subcmd_data_l.size = 0x1A; + + jc_hid_in_spi_read_t subcmd_data_r; + subcmd_data_r.addr = 0x2000; + subcmd_data_r.size = 0x1A; + + // Turn off Joy-Con detect. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + bool jc_r_found = jc_r.connected ? false : true; + bool jc_l_found = jc_l.connected ? false : true; + + u32 total_retries = 10; +retry: + retries = 10; + while (retries) + { + u32 time_now = get_tmr_ms(); + if ((!jc_l_found && jc_l.last_status_req_time < time_now) || (!jc_r_found && jc_r.last_status_req_time < time_now)) + { + if (!jc_l_found) + { + jc_send_hid_cmd(jc_l.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5); + jc_l.last_status_req_time = get_tmr_ms() + 15; + } + + if (!jc_r_found) + { + jc_send_hid_cmd(jc_r.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5); + jc_r.last_status_req_time = get_tmr_ms() + 15; + } + + retries--; + } + + if (!jc_l_found) + { + memset(jc_l.buf, 0, 0x100); + jc_rcv_pkt(&jc_l); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_l.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_l.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_l.addr += 0x26; // Get next slot. + else + jc_l_found = true; // Entry is active. + + if (jc_l_found && is_hos) + *is_l_hos = true; + } + } + + if (!jc_r_found) + { + memset(jc_r.buf, 0, 0x100); + jc_rcv_pkt(&jc_r); + + bool is_hos = false; + if (_jc_validate_pairing_info(&jc_r.buf[SPI_READ_OFFSET], &is_hos)) + { + bool is_active = jc_r.buf[SPI_READ_OFFSET] == 0x95; + + if (!is_active) + subcmd_data_r.addr += 0x26; // Get next slot. + else + jc_r_found = true; // Entry is active. + + if (jc_r_found && is_hos) + *is_r_hos = true; + } + } + + if (jc_l_found && jc_r_found) + break; + } + + if (!jc_l_found || !jc_r_found) + { + if (total_retries) + { + total_retries--; + goto retry; + } + + if (!jc_l_found) + { + bt_conn = &jc_gamepad.bt_conn_l; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + + if (!jc_r_found) + { + bt_conn = &jc_gamepad.bt_conn_r; + memset(bt_conn->host_mac, 0, 6); + memset(bt_conn->ltk, 0, 16); + } + } + + // Turn Joy-Con detect on. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + + return &jc_gamepad; +} + +void jc_deinit() +{ + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + u8 data = HCI_STATE_SLEEP; + + if (jc_r.connected) + { + jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1); + jc_rcv_pkt(&jc_r); + } + if (jc_l.connected) + { + jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1); + jc_rcv_pkt(&jc_l); + } + + jc_power_supply(UART_B, false); + jc_power_supply(UART_C, false); +} + +static void jc_init_conn(joycon_ctxt_t *jc) +{ + if (((u32)get_tmr_ms() - jc->last_received_time) > 1000) + { + jc_power_supply(jc->uart, true); + + // Turn off Joy-Con detect. + if (jc->uart == UART_B) + { + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + jc_gamepad.conn_r = false; + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + } + else + { + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + jc_gamepad.conn_l = false; + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + } + + uart_init(jc->uart, 1000000); + uart_invert(jc->uart, true, UART_INVERT_TXD); + uart_set_IIR(jc->uart); + + joycon_send_raw(jc->uart, init_jc, 4); + joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake)); + + msleep(5); + jc_rcv_pkt(jc); + + joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info)); + msleep(5); + jc_rcv_pkt(jc); + + joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize)); + msleep(5); + jc_rcv_pkt(jc); + + // Turn Joy-Con detect on. + if (jc->uart == UART_B) + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + else + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + + jc->last_received_time = get_tmr_ms(); + + if (jc->connected) + jc_power_supply(jc->uart, false); + } +} + +static void jc_conn_check() +{ + // Check if a Joy-Con was disconnected. + if (gpio_read(GPIO_PORT_E, GPIO_PIN_6)) + { + jc_power_supply(UART_C, false); + + hid_pkt_inc = 0; + + jc_l.connected = false; + jc_l.rumble_sent = false; + + jc_gamepad.buttons &= ~JC_BTN_MASK_L; + jc_gamepad.conn_l = false; + + jc_gamepad.batt_info_l = 0; + jc_gamepad.bt_conn_l.type = 0; + } + + if (gpio_read(GPIO_PORT_H, GPIO_PIN_6)) + { + jc_power_supply(UART_B, false); + + hid_pkt_inc = 0; + + jc_r.connected = false; + jc_r.rumble_sent = false; + + jc_gamepad.buttons &= ~JC_BTN_MASK_R; + jc_gamepad.conn_r = false; + + jc_gamepad.batt_info_r = 0; + jc_gamepad.bt_conn_r.type = 0; + } +} + +void jc_power_supply(u8 uart, bool enable) +{ + if (enable) + { + if (regulator_get_5v_dev_enabled(1 << uart)) + return; + + regulator_enable_5v(1 << uart); + + if (jc_init_done) + { + if (uart == UART_C) + gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH); + else + gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH); + return; + } + + if (uart == UART_C) + { + // Joy-Con(L) Charge Detect. + PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1; + gpio_config(GPIO_PORT_CC, GPIO_PIN_3, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_3, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH); + } + else + { + // Joy-Con(R) Charge Detect. + PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2; + gpio_config(GPIO_PORT_K, GPIO_PIN_3, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_K, GPIO_PIN_3, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH); + } + } + else + { + if (!regulator_get_5v_dev_enabled(1 << uart)) + return; + + regulator_disable_5v(1 << uart); + + if (uart == UART_C) + gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW); + else + gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW); + } +} + +void jc_init_hw() +{ + jc_l.uart = UART_C; + jc_r.uart = UART_B; + +#if (LV_LOG_PRINTF != 1) + jc_power_supply(UART_C, true); + jc_power_supply(UART_B, true); + + // Joy-Con (R) IsAttached. + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); + + // Joy-Con (L) IsAttached. + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); + + // Configure pinmuxing for UART B and C. + pinmux_config_uart(UART_B); + pinmux_config_uart(UART_C); + + // Ease the stress to APB. + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + + // Enable UART B and C clocks. + clock_enable_uart(UART_B); + clock_enable_uart(UART_C); + + // Restore OC. + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + + // Turn Joy-Con detect on. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); + + jc_init_done = true; +#endif +} + +jc_gamepad_rpt_t *joycon_poll() +{ + if (!jc_init_done) + return NULL; + + if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6)) + jc_init_conn(&jc_r); + if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6)) + jc_init_conn(&jc_l); + + if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6)) + jc_req_nx_pad_status(&jc_r); + if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6)) + jc_req_nx_pad_status(&jc_l); + + if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6)) + jc_rcv_pkt(&jc_r); + if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6)) + jc_rcv_pkt(&jc_l); + + jc_conn_check(); + + return &jc_gamepad; +} diff --git a/ariane/src/bdk/input/joycon.h b/ariane/src/bdk/input/joycon.h new file mode 100644 index 0000000..932c836 --- /dev/null +++ b/ariane/src/bdk/input/joycon.h @@ -0,0 +1,98 @@ +/* + * Ambient light sensor driver for Nintendo Switch's Rohm BH1730 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __JOYCON_H_ +#define __JOYCON_H_ + +#include + +#define JC_BTNS_DIRECTION_PAD 0xF0000 +#define JC_BTNS_PREV_NEXT 0x800080 +#define JC_BTNS_ENTER 0x400008 +#define JC_BTNS_ESC 0x4 + +#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC) + +typedef struct _jc_bt_conn_t +{ + u8 type; + u8 mac[6]; + u8 host_mac[6]; + u8 ltk[16]; +} jc_bt_conn_t; + +typedef struct _jc_gamepad_rpt_t +{ + union + { + struct + { + // Joy-Con (R). + u32 y:1; + u32 x:1; + u32 b:1; + u32 a:1; + u32 sr_r:1; + u32 sl_r:1; + u32 r:1; + u32 zr:1; + + // Shared + u32 minus:1; + u32 plus:1; + u32 r3:1; + u32 l3:1; + u32 home:1; + u32 cap:1; + u32 pad:1; + u32 wired:1; + + // Joy-Con (L). + u32 down:1; + u32 up:1; + u32 right:1; + u32 left:1; + u32 sr_l:1; + u32 sl_l:1; + u32 l:1; + u32 zl:1; + }; + u32 buttons; + }; + + u16 lstick_x; + u16 lstick_y; + u16 rstick_x; + u16 rstick_y; + bool center_stick_l; + bool center_stick_r; + bool conn_l; + bool conn_r; + u8 batt_info_l; + u8 batt_info_r; + jc_bt_conn_t bt_conn_l; + jc_bt_conn_t bt_conn_r; +} jc_gamepad_rpt_t; + +void jc_power_supply(u8 uart, bool enable); +void jc_init_hw(); +void jc_deinit(); +jc_gamepad_rpt_t *joycon_poll(); +jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos); + +#endif \ No newline at end of file diff --git a/ariane/src/bdk/input/touch.c b/ariane/src/bdk/input/touch.c new file mode 100644 index 0000000..eef61ec --- /dev/null +++ b/ariane/src/bdk/input/touch.c @@ -0,0 +1,422 @@ +/* + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller + * + * Copyright (c) 2018 langerhans + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "touch.h" + + +#include +#define DPRINTF(...) gfx_printf(__VA_ARGS__) + +static int touch_command(u8 cmd, u8 *buf, u8 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd, buf, size); + if (!res) + return 1; + return 0; +} + +static int touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size) +{ + int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd[0], &cmd[1], csize - 1); + if (res) + res = i2c_recv_buf(buf, size, I2C_3, STMFTS_I2C_ADDR); + if (!res) + return 1; + + return 0; +} + +static int touch_wait_event(u8 event, u8 status, u32 timeout) +{ + u32 timer = get_tmr_ms() + timeout; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == event && tmp[2] == status) + return 0; + + if (get_tmr_ms() > timer) + return 1; + } +} + +#define X_REAL_MAX 1264 +#define Y_REAL_MAX 704 +#define EDGE_OFFSET 15 + +static void _touch_compensate_limits(touch_event *event, bool touching) +{ + event->x = MAX(event->x, EDGE_OFFSET); + event->x = MIN(event->x, X_REAL_MAX); + event->x -= EDGE_OFFSET; + u32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET); + event->x = ((u32)event->x * x_adj) / 1000; + + if (touching) + { + event->y = MAX(event->y, EDGE_OFFSET); + event->y = MIN(event->y, Y_REAL_MAX); + event->y -= EDGE_OFFSET; + u32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET); + event->y = ((u32)event->y * y_adj) / 1000; + } +} + +static void _touch_process_contact_event(touch_event *event, bool touching) +{ + event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4); + + // Normally, GUI elements have bigger horizontal estate. + // Avoid parsing y axis when finger is removed to minimize touch noise. + if (touching) + { + event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB); + + event->z = event->raw[5] | (event->raw[6] << 8); + event->z = event->z << 6; + u16 tmp = 0x40; + if ((event->raw[7] & 0x3F) != 1 && (event->raw[7] & 0x3F) != 0x3F) + tmp = event->raw[7] & 0x3F; + event->z /= tmp + 0x40; + + event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1; + } + else + event->fingers = 0; + + _touch_compensate_limits(event, touching); +} + +static void _touch_parse_event(touch_event *event) +{ + event->type = event->raw[1] & STMFTS_MASK_EVENT_ID; + + switch (event->type) + { + case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + _touch_process_contact_event(event, true); + if (event->z < 255) // Reject palm rest. + event->touch = true; + else + { + event->touch = false; + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + event->touch = false; + _touch_process_contact_event(event, false); + break; + case STMFTS_EV_NO_EVENT: + if (event->touch) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + break; + default: + if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION) + event->type = STMFTS_EV_MULTI_TOUCH_MOTION; + else + event->type = STMFTS_EV_MULTI_TOUCH_LEAVE; + } + + // gfx_con_setpos(&gfx_con, 0, 300); + // DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z); + // DPRINTF("0 = %02X\n1 = %02x\n2 = %02x\n3 = %02x\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]); + // DPRINTF("4 = %02X\n5 = %02x\n6 = %02x\n7 = %02x\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]); +} + +void touch_poll(touch_event *event) +{ + i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT); + + _touch_parse_event(event); +} + +touch_event touch_poll_wait() +{ + touch_event event; + do + { + touch_poll(&event); + } while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE); + + return event; +} + +touch_info touch_get_info() +{ + touch_info info; + u8 buf[8]; + memset(&buf, 0, 8); + i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO); + + info.chip_id = buf[0] << 8 | buf[1]; + info.fw_ver = buf[2] << 8 | buf[3]; + info.config_id = buf[4]; + info.config_ver = buf[5]; + + //DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02x, Cfg Ver: %d\n", + // info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver); + + return info; +} + +int touch_get_fw_info(touch_fw_info_t *fw) +{ + u8 buf[8] = {0}; + + // Get fw address info. + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0x60 }; + int res = touch_read_reg(cmd, 3, buf, 3); + if (!res) + { + // Get fw info. + cmd[1] = buf[2]; cmd[2] = buf[1]; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + { + fw->fw_id = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4]; + fw->ftb_ver = (buf[6] << 8) | buf[5]; + } + + cmd[2]++; + res = touch_read_reg(cmd, 3, buf, 8); + if (!res) + fw->fw_rev = (buf[7] << 8) | buf[6]; + } + + return res; +} + +int touch_sys_reset() +{ + u8 cmd[3] = { 0, 0x28, 0x80 }; // System reset cmd. + for (u8 retries = 0; retries < 3; retries++) + { + if (touch_command(STMFTS_WRITE_REG, cmd, 3)) + { + msleep(10); + continue; + } + msleep(10); + if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20)) + continue; + else + return 0; + } + + return 1; +} + +int touch_panel_ito_test(u8 *err) +{ + int res = 0; + + // Reset touchscreen module. + if (touch_sys_reset()) + return res; + + // Do ITO Production test. + u8 cmd[2] = { 1, 0 }; + if (touch_command(STMFTS_ITO_CHECK, cmd, 2)) + return res; + + u32 timer = get_tmr_ms() + 2000; + while (true) + { + u8 tmp[8] = {0}; + i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT); + if (tmp[1] == 0xF && tmp[2] == 0x5) + { + if (err) + { + err[0] = tmp[3]; + err[1] = tmp[4]; + } + + res = 1; + break; + } + + if (get_tmr_ms() > timer) + break; + } + + // Reset touchscreen module. + touch_sys_reset(); + + return res; +} + +int touch_get_fb_info(u8 *buf) +{ + u8 tmp[5]; + + u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0 }; + int res = 0; + + + for (u32 i = 0; i < 0x10000; i+=4) + { + if (!res) + { + cmd[1] = (i >> 8) & 0xFF; + cmd[2] = i & 0xFF; + memset(tmp, 0xCC, 5); + res = touch_read_reg(cmd, 3, tmp, 5); + memcpy(&buf[i], tmp + 1, 4); + } + } + + return res; +} + +int touch_sense_enable() +{ + // Enable auto tuning calibration and multi-touch sensing. + u8 cmd = 1; + if (touch_command(STMFTS_AUTO_CALIBRATION, &cmd, 1)) + return 0; + + if (touch_command(STMFTS_MS_MT_SENSE_ON, NULL, 0)) + return 0; + + if (touch_command(STMFTS_CLEAR_EVENT_STACK, NULL, 0)) + return 0; + + return 1; +} + +int touch_execute_autotune() +{ + // Reset touchscreen module. + if (touch_sys_reset()) + return 0; + + // Trim low power oscillator. + if (touch_command(STMFTS_LP_TIMER_CALIB, NULL, 0)) + return 0; + msleep(200); + + // Apply Mutual Sense Compensation tuning. + if (touch_command(STMFTS_MS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000)) + return 0; + + // Apply Self Sense Compensation tuning. + if (touch_command(STMFTS_SS_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000)) + return 0; + + // Save Compensation data to EEPROM. + if (touch_command(STMFTS_SAVE_CX_TUNING, NULL, 0)) + return 0; + if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000)) + return 0; + + return touch_sense_enable(); +} + +static int touch_init() +{ + // Initialize touchscreen module. + if (touch_sys_reset()) + return 0; + + return touch_sense_enable(); +} + +int touch_power_on() +{ + // Enables LDO6 for touchscreen VDD/AVDD supply + max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, + MAX77620_LDO_CFG2_ADE_ENABLE | (3 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + + // Configure touchscreen GPIO. + PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1; + gpio_config(GPIO_PORT_J, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_J, GPIO_PIN_7, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH); + + // IRQ and more. + // PINMUX_AUX(PINMUX_AUX_TOUCH_INT) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 3; + // gpio_config(GPIO_PORT_X, GPIO_PIN_1, GPIO_MODE_GPIO); + // gpio_write(GPIO_PORT_X, GPIO_PIN_1, GPIO_LOW); + + // Configure Touscreen and GCAsic shared GPIO. + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; + PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; + gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); + + // Initialize I2C3. + pinmux_config_i2c(I2C_3); + clock_enable_i2c(I2C_3); + i2c_init(I2C_3); + + // Wait for the touchscreen module to get ready. + touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20); + + // Check for forced boot time calibration. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + u8 err[2]; + if (touch_panel_ito_test(err)) + if (!err[0] && !err[1]) + return touch_execute_autotune(); + } + + // Initialize touchscreen. + u32 retries = 3; + while (retries) + { + if (touch_init()) + return 1; + retries--; + } + + return 0; +} + +void touch_power_off() +{ + // Disable touchscreen power. + gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW); + + // Disables LDO6 for touchscreen VDD, AVDD supply + max77620_regulator_enable(REGULATOR_LDO6, 0); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, + MAX77620_LDO_CFG2_ADE_ENABLE | (2 << 3) | (MAX77620_POWER_MODE_NORMAL << MAX77620_LDO_POWER_MODE_SHIFT)); + + clock_disable_i2c(I2C_3); +} \ No newline at end of file diff --git a/ariane/src/bdk/input/touch.h b/ariane/src/bdk/input/touch.h new file mode 100644 index 0000000..9245be3 --- /dev/null +++ b/ariane/src/bdk/input/touch.h @@ -0,0 +1,157 @@ +/* + * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller + * + * Copyright (c) 2018 langerhans + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TOUCH_H_ +#define __TOUCH_H_ + +#include + +#define STMFTS_I2C_ADDR 0x49 + +/* I2C commands */ +#define STMFTS_READ_INFO 0x80 +#define STMFTS_READ_STATUS 0x84 +#define STMFTS_READ_ONE_EVENT 0x85 +#define STMFTS_READ_ALL_EVENT 0x86 +#define STMFTS_LATEST_EVENT 0x87 +#define STMFTS_SLEEP_IN 0x90 +#define STMFTS_SLEEP_OUT 0x91 +#define STMFTS_MS_MT_SENSE_OFF 0x92 +#define STMFTS_MS_MT_SENSE_ON 0x93 +#define STMFTS_SS_HOVER_SENSE_OFF 0x94 +#define STMFTS_SS_HOVER_SENSE_ON 0x95 +#define STMFTS_LP_TIMER_CALIB 0x97 +#define STMFTS_MS_KEY_SENSE_OFF 0x9A +#define STMFTS_MS_KEY_SENSE_ON 0x9B +#define STMFTS_SYSTEM_RESET 0xA0 +#define STMFTS_CLEAR_EVENT_STACK 0xA1 +#define STMFTS_FULL_FORCE_CALIBRATION 0xA2 +#define STMFTS_MS_CX_TUNING 0xA3 +#define STMFTS_SS_CX_TUNING 0xA4 +#define STMFTS_ITO_CHECK 0xA7 +#define STMFTS_RELEASEINFO 0xAA +#define STMFTS_WRITE_REG 0xB6 +#define STMFTS_AUTO_CALIBRATION 0xC3 +#define STMFTS_NOISE_WRITE 0xC7 +#define STMFTS_NOISE_READ 0xC8 +#define STMFTS_RW_FRAMEBUFFER_REG 0xD0 +#define STMFTS_SAVE_CX_TUNING 0xFC + +#define STMFTS_UNK0 0xB8 //Request compensation +#define STMFTS_UNK1 0xCF +#define STMFTS_UNK2 0xF7 +#define STMFTS_UNK3 0xFA +#define STMFTS_UNK4 0xF9 +#define STMFTS_UNK5 0x62 + + +/* events */ +#define STMFTS_EV_NO_EVENT 0x00 +#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02 +#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03 +#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04 +#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05 +#define STMFTS_EV_HOVER_ENTER 0x07 +#define STMFTS_EV_HOVER_LEAVE 0x08 +#define STMFTS_EV_HOVER_MOTION 0x09 +#define STMFTS_EV_KEY_STATUS 0x0e +#define STMFTS_EV_ERROR 0x0f +#define STMFTS_EV_NOISE_READ 0x17 +#define STMFTS_EV_NOISE_WRITE 0x18 + +#define STMFTS_EV_CONTROLLER_READY 0x10 +#define STMFTS_EV_STATUS 0x16 +#define STMFTS_EV_DEBUG 0xDB + +#define STMFTS_EV_STATUS_MS_CX_TUNING_DONE 1 +#define STMFTS_EV_STATUS_SS_CX_TUNING_DONE 2 +#define STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE 4 + +/* multi touch related event masks */ +#define STMFTS_MASK_EVENT_ID 0x0F +#define STMFTS_MASK_TOUCH_ID 0xF0 +#define STMFTS_MASK_LEFT_EVENT 0x0F +#define STMFTS_MASK_X_MSB 0x0F +#define STMFTS_MASK_Y_LSB 0xF0 + +/* key related event masks */ +#define STMFTS_MASK_KEY_NO_TOUCH 0x00 +#define STMFTS_MASK_KEY_MENU 0x01 +#define STMFTS_MASK_KEY_BACK 0x02 + +#define STMFTS_EVENT_SIZE 8 +#define STMFTS_STACK_DEPTH 32 +#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH) +#define STMFTS_MAX_FINGERS 10 + +typedef enum _touch_ito_error { + ITO_NO_ERROR = 0, + ITO_FORCE_OPEN, + ITO_SENSE_OPEN, + ITO_FORCE_SHRT_GND, + ITO_SENSE_SHRT_GND, + ITO_FORCE_SHRT_VCM, + ITO_SENSE_SHRT_VCM, + ITO_FORCE_SHRT_FORCE, + ITO_SENSE_SHRT_SENSE, + ITO_F2E_SENSE, + ITO_FPC_FORCE_OPEN, + ITO_FPC_SENSE_OPEN, + ITO_KEY_FORCE_OPEN, + ITO_KEY_SENSE_OPEN, + ITO_RESERVED0, + ITO_RESERVED1, + ITO_RESERVED2, + ITO_MAX_ERR_REACHED = 0xFF +} touch_ito_error; + +typedef struct _touch_event { + u8 raw[8]; + u16 type; // Event type. + u16 x; // Horizontal coordinates. + u16 y; // Vertical coordinates. + u32 z; + u8 fingers; + bool touch; +} touch_event; + +typedef struct _touch_info { + u16 chip_id; + u16 fw_ver; + u16 config_id; + u16 config_ver; +} touch_info; + +typedef struct _touch_fw_info_t { + u32 fw_id; + u16 ftb_ver; + u16 fw_rev; +} touch_fw_info_t; + +void touch_poll(touch_event *event); +touch_event touch_poll_wait(); +int touch_get_fw_info(touch_fw_info_t *fw); +touch_info touch_get_info(); +int touch_panel_ito_test(u8 *err); +int touch_execute_autotune(); +int touch_sense_enable(); +int touch_power_on(); +void touch_power_off(); + +#endif /* __TOUCH_H_ */ \ No newline at end of file diff --git a/ariane/src/bdk/libs/compr/blz.c b/ariane/src/bdk/libs/compr/blz.c new file mode 100644 index 0000000..685ef4a --- /dev/null +++ b/ariane/src/bdk/libs/compr/blz.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018 rajkosto + * Copyright (c) 2018 SciresM + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "blz.h" + +const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter) +{ + if (compDataLen < sizeof(blz_footer)) + return NULL; + + const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)]; + if (outFooter != NULL) + memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4. + + return srcFooter; +} + +// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! +int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) +{ + u32 addl_size = footer->addl_size; + u32 header_size = footer->header_size; + u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; + + unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size; + u32 cmp_ofs = cmp_and_hdr_size - header_size; + u32 out_ofs = cmp_and_hdr_size + addl_size; + + while (out_ofs) + { + unsigned char control = cmp_start[--cmp_ofs]; + for (unsigned int i=0; i<8; i++) + { + if (control & 0x80) + { + if (cmp_ofs < 2) + return 0; // Out of bounds. + + cmp_ofs -= 2; + u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs]; + u32 seg_size = ((seg_val >> 12) & 0xF) + 3; + u32 seg_ofs = (seg_val & 0x0FFF) + 3; + if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds. + seg_size = out_ofs; + + out_ofs -= seg_size; + + for (unsigned int j = 0; j < seg_size; j++) + cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; + } + else + { + // Copy directly. + if (cmp_ofs < 1) + return 0; //out of bounds + + cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; + } + control <<= 1; + if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done. + return 1; + } + } + + return 1; +} + +int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize) +{ + blz_footer footer; + const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer); + if (compFooterPtr == NULL) + return 0; + + // Decompression must be done in-place, so need to copy the relevant compressed data first. + unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData; + memcpy(dstData, compData, numCompBytes); + memset(&dstData[numCompBytes], 0, dstSize - numCompBytes); + + return blz_uncompress_inplace(dstData, compDataLen, &footer); +} diff --git a/ariane/src/bdk/libs/compr/blz.h b/ariane/src/bdk/libs/compr/blz.h new file mode 100644 index 0000000..a1cce37 --- /dev/null +++ b/ariane/src/bdk/libs/compr/blz.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 rajkosto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _BLZ_H_ +#define _BLZ_H_ + +#include + +typedef struct _blz_footer +{ + u32 cmp_and_hdr_size; + u32 header_size; + u32 addl_size; +} blz_footer; + +// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL. +const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter); +// Returns 0 on failure. +int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer); +// Returns 0 on failure. +int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize); + +#endif diff --git a/ariane/src/lib/lz.c b/ariane/src/bdk/libs/compr/lz.c similarity index 100% rename from ariane/src/lib/lz.c rename to ariane/src/bdk/libs/compr/lz.c diff --git a/ariane/src/lib/lz.h b/ariane/src/bdk/libs/compr/lz.h similarity index 100% rename from ariane/src/lib/lz.h rename to ariane/src/bdk/libs/compr/lz.h diff --git a/ariane/src/lib/diskio.h b/ariane/src/bdk/libs/fatfs/diskio.h similarity index 79% rename from ariane/src/lib/diskio.h rename to ariane/src/bdk/libs/fatfs/diskio.h index 20ebde9..88332f5 100644 --- a/ariane/src/lib/diskio.h +++ b/ariane/src/bdk/libs/fatfs/diskio.h @@ -9,8 +9,7 @@ extern "C" { #endif -#include "integer.h" - +#include /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -24,6 +23,14 @@ typedef enum { RES_PARERR /* 4: Invalid Parameter */ } DRESULT; +typedef enum { + DRIVE_SD = 0, + DRIVE_RAM = 1, + DRIVE_EMMC = 2, + DRIVE_BIS = 3, + DRIVE_EBIS = 4, +} DDRIVE; + /*---------------------------------------*/ /* Prototypes for disk control functions */ @@ -34,6 +41,7 @@ DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +DRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff); /* Disk Status Bits (DSTATUS) */ @@ -46,11 +54,12 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ -#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define SET_SECTOR_COUNT 1 /* Set media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ diff --git a/ariane/src/lib/ff.c b/ariane/src/bdk/libs/fatfs/ff.c similarity index 92% rename from ariane/src/lib/ff.c rename to ariane/src/bdk/libs/fatfs/ff.c index 25afaf7..7a94aea 100644 --- a/ariane/src/lib/ff.c +++ b/ariane/src/bdk/libs/fatfs/ff.c @@ -1,5 +1,22 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13b / +/ FatFs - Generic FAT Filesystem Module R0.13c (p4) / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. @@ -21,8 +38,10 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ +#include -#define EFSPRINTF(...) +#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); +//#define EFSPRINTF(...) /*-------------------------------------------------------------------------- @@ -30,11 +49,20 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 63463 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ + + /* Character code support macros */ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') @@ -44,18 +72,18 @@ #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) -/* Additional file attribute bits for internal use */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - /* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + /* Name status flags in fn[11] */ #define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ @@ -68,13 +96,13 @@ #define NS_NONAME 0x80 /* Not followed */ -/* Limits and boundaries */ -#define MAX_DIR 0x200000 /* Max size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ -#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ -#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ +/* exFAT directory entry types */ +#define ET_BITMAP 0x81 /* Allocation bitmap */ +#define ET_UPCASE 0x82 /* Up-case table */ +#define ET_VLABEL 0x83 /* Volume label */ +#define ET_FILEDIR 0x85 /* File and directory */ +#define ET_STREAM 0xC0 /* Stream extension */ +#define ET_FILENAME 0xC1 /* Name extension */ /* FatFs refers the FAT structure as simple byte array instead of structure member @@ -522,6 +550,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ + static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct737[] = TBL_CT737; @@ -563,6 +592,15 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); ---------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/* Print error header */ +/*-----------------------------------------------------------------------*/ + +void print_error() +{ + gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF); +} + /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ @@ -1094,7 +1132,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ if (res == FR_OK) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ - mem_set(fs->win, 0, SS(fs)); + mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); @@ -1294,7 +1332,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { @@ -1332,9 +1370,9 @@ static FRESULT change_bitmap ( clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ - i = clst / 8 % SS(fs); /* Byte offset in the sector */ - bm = 1 << (clst % 8); /* Bit mask in the byte */ + sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { @@ -1407,7 +1445,7 @@ static FRESULT fill_last_frag ( static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ - DWORD pclst /* Previous cluster of clst (0:entire chain) */ + DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; @@ -1645,7 +1683,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ sect = clst2sect(fs, clst); /* Top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */ - mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ /* Allocate a temporary buffer */ for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; @@ -1875,7 +1913,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; @@ -1911,15 +1949,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } @@ -2155,33 +2193,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ - /* Load 85 entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; - /* Load C0 entry */ + /* Load stream-extension entry */ res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; - /* Load C1 entries */ - i = 2 * SZDIRE; /* C1 offset to load */ + /* Load file-name entries */ + i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); @@ -2286,16 +2324,16 @@ static void create_xdir ( WCHAR wc; - /* Create 85,C0 entry */ + /* Create file-directory and stream-extension entry */ mem_set(dirb, 0, 2 * SZDIRE); - dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ - dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ + dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; + dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - /* Create C1 entries */ - i = SZDIRE * 2; /* Top of C1 entries */ + /* Create file-name entries */ + i = SZDIRE * 2; /* Top of file_name entries */ nlen = nc1 = 0; wc = 1; do { - dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ st_word(dirb + i, wc); /* Store it */ @@ -2319,8 +2357,8 @@ static void create_xdir ( /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -#define dir_read_file(dp) dir_read(dp, 0) -#define dir_read_label(dp) dir_read(dp, 1) +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ @@ -2329,7 +2367,7 @@ static FRESULT dir_read ( { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE a, c; + BYTE attr, b; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif @@ -2337,16 +2375,16 @@ static FRESULT dir_read ( while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { + b = dp->dir[DIR_Name]; /* Test for the entry type */ + if (b == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { - if (c == 0x83) break; /* Volume label entry? */ + if (b == ET_VLABEL) break; /* Volume label entry? */ } else { - if (c == 0x85) { /* Start of the file entry block? */ + if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2358,19 +2396,19 @@ static FRESULT dir_read ( } else #endif { /* On the FAT/FAT32 volume */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ - if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of an LFN sequence? */ + if (attr == AM_LFN) { /* An LFN entry is found */ + if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; + b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ @@ -2379,7 +2417,7 @@ static FRESULT dir_read ( } } #else /* Non LFN configuration */ - if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2419,7 +2457,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ - while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ + while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif @@ -2498,17 +2536,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ - res = dir_alloc(dp, nent); /* Allocate entries */ + res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ - if (dp->obj.stat & 4) { /* Has the directory been stretched? */ + if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ dp->obj.stat &= ~4; res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; - if (dp->obj.sclust != 0) { /* Is it a sub directory? */ + if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ DIR dj; res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ @@ -2640,6 +2678,7 @@ static void get_fileinfo ( { UINT si, di; #if FF_USE_LFN + BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else @@ -2700,9 +2739,10 @@ static void get_fileinfo ( if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { - for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } @@ -3233,7 +3273,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ stat = disk_status(fs->pdrv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ - EFSPRINTF("Write protected!"); + EFSPRINTF("WPEN1"); return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is valid */ @@ -3247,11 +3287,11 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ - EFSPRINTF("Medium not ready or hard error!"); + EFSPRINTF("MDNR"); return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ - EFSPRINTF("Write protected!"); + EFSPRINTF("WPEN2"); return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ @@ -3259,7 +3299,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ @@ -3275,11 +3315,11 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) { - EFSPRINTF("Disk I/O error - Could not load boot record!"); + EFSPRINTF("BRNL"); return FR_DISK_ERR; /* An error occured in the disk I/O layer */ } if (fmt >= 2) { - EFSPRINTF("No FAT/FAT32/exFAT filesystem found!"); + EFSPRINTF("NOFAT"); return FR_NO_FILESYSTEM; /* No FAT volume is found */ } @@ -3288,72 +3328,73 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; + DWORD so, cv, bcl; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ - if (i < BPB_ZeroedEx + 53) { - EFSPRINTF("exFAT - Zero filler check failed!"); - return FR_NO_FILESYSTEM; - } + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; - if (ld_word(fs->win + BPB_FSVerEx) != 0x100) { - EFSPRINTF("exFAT - Version check failed!"); - return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ - } + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ - EFSPRINTF("exFAT - Bytes per sector does not match physical sector size!"); + EFSPRINTF("EXSPS"); return FR_NO_FILESYSTEM; } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ - if (maxlba >= 0x100000000) { - EFSPRINTF("exFAT - Cannot handle volume LBA with 32-bit LBA!"); - return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ - } + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) { - EFSPRINTF("exFAT - Multiple or no file allocation tables found!"); + EFSPRINTF("EXFNF"); return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ } fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ - if (fs->csize == 0) { - EFSPRINTF("exFAT - Cluster size is not between 1KB - 32KB!"); - return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ - } + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ - if (nclst > MAX_EXFAT) { - EFSPRINTF("exFAT - Total clusters exceed allowed!"); - return FR_NO_FILESYSTEM; /* (Too many clusters) */ - } + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ fs->n_fatent = nclst + 2; /* Boundaries and Limits */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) { - EFSPRINTF("exFAT - Volume size is lower than required!"); - return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ - } + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); - /* Check if bitmap location is in assumption (at the first cluster) */ - if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) { - EFSPRINTF("exFAT - Bitmap location not at first cluster!"); - return FR_DISK_ERR; + /* Get bitmap location and check if it is contiguous (implementation assumption) */ + so = i = 0; + for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ + if (i == 0) { + if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ + if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) { + EFSPRINTF("EXBM1C"); + return FR_DISK_ERR; + } + so++; + } + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + i = (i + SZDIRE) % SS(fs); /* Next entry */ } - for (i = 0; i < SS(fs); i += SZDIRE) { - if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ - } - if (i == SS(fs)) { - EFSPRINTF("exFAT - Bitmap allocation is missing!"); + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) { + EFSPRINTF("EXBMM"); return FR_NO_FILESYSTEM; } + fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ + for (;;) { /* Check if bitmap is contiguous */ + if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; + cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + if (cv == 0xFFFFFFFF) break; /* Last link? */ + if (cv != ++bcl) { + EFSPRINTF("EXBMM"); + return FR_NO_FILESYSTEM; /* Fragmented? */ + } + } + #if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif @@ -3362,7 +3403,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) { - EFSPRINTF("FAT - Bytes per sector does not match physical sector size!"); + EFSPRINTF("32SPS"); return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ } @@ -3371,52 +3412,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ - if (fs->n_fats != 1 && fs->n_fats != 2) { - EFSPRINTF("FAT - No or more than 2 file allocation tables found!"); - return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - } + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ fasize *= fs->n_fats; /* Number of sectors for FAT area */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ - if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) { - EFSPRINTF("FAT - Cluster size is not a power of 2!"); - return FR_NO_FILESYSTEM; /* (Must be power of 2) */ - } + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / SZDIRE)) { - EFSPRINTF("FAT - Root directory entries are not sector aligned!"); - return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - } + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (nrsv == 0) { - EFSPRINTF("FAT - Zero reserved sectors!"); - return FR_NO_FILESYSTEM; /* (Must not be 0) */ - } + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) { - EFSPRINTF("FAT - Invalid volume size!"); - return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - } + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (nclst == 0) { - EFSPRINTF("FAT - Invalid volume size!"); - return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - } + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = 0; if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; - if (fmt == 0) { - EFSPRINTF("FAT - Not compatible FAT12/16/32 filesystem!"); - return FR_NO_FILESYSTEM; - } + if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ fs->n_fatent = nclst + 2; /* Number of FAT entries */ @@ -3424,29 +3444,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { - if (ld_word(fs->win + BPB_FSVer32) != 0) { - EFSPRINTF("FAT32 - Not a 0.0 revision!"); - return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ - } - if (fs->n_rootdir != 0) { - EFSPRINTF("FAT32 - Root entry sector is not 0!"); - return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - } + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { - if (fs->n_rootdir == 0) { - EFSPRINTF("FAT - Root entry sector is 0!"); - return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ - } + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } - if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) { - EFSPRINTF("FAT - FAT size is not the required size!"); - return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ - } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !FF_FS_READONLY /* Get FSInfo if available */ @@ -3557,7 +3565,7 @@ FRESULT f_mount ( /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) { - EFSPRINTF("Invalid drive!"); + EFSPRINTF("IDRIVE!"); return FR_INVALID_DRIVE; } cfs = FatFs[vol]; /* Pointer to fs object */ @@ -3742,7 +3750,7 @@ FRESULT f_open ( fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY - mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ + mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ @@ -3797,17 +3805,16 @@ FRESULT f_read ( UINT rcnt, cc, csect; BYTE *rbuff = (BYTE*)buff; - + UINT br_tmp; + if (!br) + br = &br_tmp; *br = 0; /* Clear read byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { - EFSPRINTF("File object Validation!"); + EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } - if (!(fp->flag & FA_READ)) { - EFSPRINTF("Access denied!"); - LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - } + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ @@ -3829,20 +3836,17 @@ FRESULT f_read ( } } if (clst < 2) { - EFSPRINTF("Cluster status check or Internal error!"); + EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } if (clst == 0xFFFFFFFF) { - EFSPRINTF("Disk error (cluster hard error)!"); + EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Update current cluster */ } sect = clst2sect(fs, fp->clust); /* Get current sector */ - if (sect == 0) { - EFSPRINTF("Get current sector error!"); - ABORT(fs, FR_INT_ERR); - } + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Read maximum contiguous sectors directly */ @@ -3850,7 +3854,7 @@ FRESULT f_read ( cc = fs->csize - csect; } if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) { - EFSPRINTF("Read - Low level disk I/O!"); + EFSPRINTF("RLIO"); ABORT(fs, FR_DISK_ERR); } #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ @@ -3872,17 +3876,17 @@ FRESULT f_read ( #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { - EFSPRINTF("Write-back dirty sector cache!"); + EFSPRINTF("RDC"); ABORT(fs, FR_DISK_ERR); - } - fp->flag &= (BYTE)~FA_DIRTY; - } + } + fp->flag &= (BYTE)~FA_DIRTY; + } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { - EFSPRINTF("Read - Low level disk I/O!\n(fill sector cache)"); - ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ - } - } + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { + EFSPRINTF("RSC"); + ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + } + } #endif fp->sect = sect; } @@ -3902,6 +3906,92 @@ FRESULT f_read ( +#if FF_FASTFS && FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* Fast Read Aligned Sized File Without a Cache */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read_fast ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btr /* Number of bytes to read */ +) +{ + FRESULT res; + FATFS *fs; + UINT csize_bytes; + DWORD clst; + UINT count = 0; + FSIZE_t work_sector = 0; + FSIZE_t sector_base = 0; + BYTE *wbuff = (BYTE*)buff; + + // TODO support sector reading inside a cluster + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { + EFSPRINTF("FOV"); + LEAVE_FF(fs, res); /* Check validity */ + } + + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + FSIZE_t remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + csize_bytes = fs->csize * SS(fs); + + if (!fp->fptr) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + } else { + if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } + } + if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; /* Set working cluster */ + + sector_base = clst2sect(fs, fp->clust); + count += fs->csize; + btr -= csize_bytes; + fp->fptr += csize_bytes; + + while (btr) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + + if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; + + work_sector = clst2sect(fs, fp->clust); + if ((work_sector - sector_base) == count) count += fs->csize; + else { + if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + wbuff += count * SS(fs); + + sector_base = work_sector; + count = fs->csize; + } + + fp->fptr += MIN(btr, csize_bytes); + btr -= MIN(btr, csize_bytes); + + // TODO: what about if data is smaller than cluster? + // Must read-write back that cluster. + + if (!btr) { /* Final cluster/sectors read. */ + if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + } + + LEAVE_FF(fs, FR_OK); +} +#endif + + + + #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ @@ -3920,17 +4010,16 @@ FRESULT f_write ( UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; - + UINT bw_tmp; + if (!bw) + bw = &bw_tmp; *bw = 0; /* Clear write byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { - EFSPRINTF("File object Validation!"); + EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } - if (!(fp->flag & FA_WRITE)) { - EFSPRINTF("Access denied!"); - LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - } + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { @@ -3958,15 +4047,15 @@ FRESULT f_write ( } } if (clst == 0) { - EFSPRINTF("Could not allocate a new cluster\n(disk full or low level disk I/O error)!"); + EFSPRINTF("DSKFULL"); break; /* Could not allocate a new cluster (disk full) */ } if (clst == 1) { - EFSPRINTF("Cluster status check or Internal error!"); + EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } if (clst == 0xFFFFFFFF) { - EFSPRINTF("Disk error (cluster hard error)!"); + EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Update current cluster */ @@ -3976,18 +4065,12 @@ FRESULT f_write ( if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { - EFSPRINTF("Write-back sector cache!"); - ABORT(fs, FR_DISK_ERR); - } + if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clst2sect(fs, fp->clust); /* Get current sector */ - if (sect == 0) { - EFSPRINTF("Get current sector error!"); - ABORT(fs, FR_INT_ERR); - } + if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Write maximum contiguous sectors directly */ @@ -3995,7 +4078,7 @@ FRESULT f_write ( cc = fs->csize - csect; } if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) { - EFSPRINTF("Write - Low level disk I/O!"); + EFSPRINTF("WLIO"); ABORT(fs, FR_DISK_ERR); } #if FF_FS_MINIMIZE <= 2 @@ -4023,7 +4106,6 @@ FRESULT f_write ( if (fp->sect != sect && /* Fill sector cache with file data */ fp->fptr < fp->obj.objsize && disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { - EFSPRINTF("Read - Low level disk I/O!\n(Could not fill sector cache with file data)"); ABORT(fs, FR_DISK_ERR); } #endif @@ -4049,6 +4131,97 @@ FRESULT f_write ( +#if FF_FASTFS && FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* Fast Write Aligned Sized File Without a Cache */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write_fast ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw /* Number of bytes to write */ +) +{ + FRESULT res; + FATFS *fs; + UINT csize_bytes; + DWORD clst; + UINT count = 0; + FSIZE_t work_sector = 0; + FSIZE_t sector_base = 0; + const BYTE *wbuff = (const BYTE*)buff; + + // TODO support sector writing inside a cluster + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { + EFSPRINTF("FOV"); + LEAVE_FF(fs, res); /* Check validity */ + } + + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + csize_bytes = fs->csize * SS(fs); + + if (!fp->fptr) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + } else { + if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } + } + + if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; /* Set working cluster */ + + sector_base = clst2sect(fs, fp->clust); + count += fs->csize; + btw -= csize_bytes; + fp->fptr += csize_bytes; + + while (btw) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + + if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } + else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } + + fp->clust = clst; + + work_sector = clst2sect(fs, fp->clust); + if ((work_sector - sector_base) == count) count += fs->csize; + else { + if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + wbuff += count * SS(fs); + + sector_base = work_sector; + count = fs->csize; + } + + fp->fptr += MIN(btw, csize_bytes); + btw -= MIN(btw, csize_bytes); + + // what about if data is smaller than cluster? + // Probably must read-write back that cluster. + if (!btw) { /* Final cluster/sectors write. */ + if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} +#endif + + + + /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ @@ -4067,7 +4240,7 @@ FRESULT f_sync ( if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !FF_FS_TINY - if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } @@ -4262,15 +4435,16 @@ FRESULT f_getcwd ( TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; -#endif #if FF_STR_VOLUME_ID const char *vp; +#endif #endif FILINFO fno; DEF_NAMBUF /* Get logical drive */ + buff[0] = 0; /* Set null string to get current volume */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; @@ -4289,7 +4463,7 @@ FRESULT f_getcwd ( res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ - res = dir_read_file(&dj); + res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); @@ -4504,6 +4678,37 @@ FRESULT f_lseek ( +#if FF_FASTFS && FF_USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* Seek File Read/Write Pointer */ +/*-----------------------------------------------------------------------*/ + +DWORD *f_expand_cltbl ( + FIL* fp, /* Pointer to the file object */ + UINT tblsz, /* Size of table */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ + if (!fp->cltbl) { /* Allocate memory for cluster link table */ + fp->cltbl = (DWORD *)ff_memalloc(tblsz); + fp->cltbl[0] = tblsz; + } + if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ + ff_memfree(fp->cltbl); + fp->cltbl = NULL; + EFSPRINTF("CLTBLSZ"); + return NULL; + } + f_lseek(fp, 0); + + return fp->cltbl; +} +#endif + + + + #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ @@ -4621,7 +4826,7 @@ FRESULT f_readdir ( res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); - res = dir_read_file(dp); /* Read an item */ + res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ @@ -4744,7 +4949,7 @@ FRESULT f_getfree ( /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { - *fatfs = fs; /* Return ptr to the fs object */ + if (fatfs) *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; @@ -4766,7 +4971,7 @@ FRESULT f_getfree ( UINT b; clst = fs->n_fatent - 2; /* Number of clusters */ - sect = fs->database; /* Assuming bitmap starts at cluster 2 */ + sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ if (i == 0) { @@ -4929,7 +5134,7 @@ FRESULT f_unlink ( #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read_file(&sdj); /* Test if the directory is empty */ + res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } @@ -4967,73 +5172,69 @@ FRESULT f_mkdir ( { FRESULT res; DIR dj; + FFOBJID sobj; FATFS *fs; - BYTE *dir; DWORD dcl, pcl, tm; DEF_NAMBUF - /* Get logical drive */ - res = find_volume(&path, &fs, FA_WRITE); + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + if (res == FR_OK) res = FR_EXIST; /* Name collision? */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } - if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ - dj.obj.objsize = (DWORD)fs->csize * SS(fs); + if (res == FR_NO_FILE) { /* It is clear to create a new directory */ + sobj.fs = fs; /* New object id to create a new chain */ + dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ - if (dcl == 1) res = FR_INT_ERR; - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ + if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); - if (res == FR_OK) { /* Initialize the new directory table */ - res = dir_clear(fs, dcl); /* Clean up the new table */ - if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ - dir = fs->win; - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - st_dword(dir + DIR_ModTime, tm); - st_clust(fs, dir, dcl); - mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ - dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - st_clust(fs, dir + SZDIRE, pcl); - fs->wflag = 1; - } - } if (res == FR_OK) { - res = dir_register(&dj); /* Register the object to the directoy */ + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ + mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ + fs->win[DIR_Name] = '.'; + fs->win[DIR_Attr] = AM_DIR; + st_dword(fs->win + DIR_ModTime, tm); + st_clust(fs, fs->win, dcl); + mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ + fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, fs->win + SZDIRE, pcl); + fs->wflag = 1; + } + res = dir_register(&dj); /* Register the object to the parent directoy */ + } } if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ - st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { - dir = dj.dir; - st_dword(dir + DIR_ModTime, tm); /* Created time */ - st_clust(fs, dir, dcl); /* Table start cluster */ - dir[DIR_Attr] = AM_DIR; /* Attribute */ + st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dj.dir, dcl); /* Table start cluster */ + dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } else { - remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); @@ -5273,7 +5474,7 @@ FRESULT f_getlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read_label(&dj); /* Find a volume label entry */ + res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { @@ -5418,7 +5619,7 @@ FRESULT f_setlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read_label(&dj); /* Get volume label entry */ + res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ @@ -5440,7 +5641,7 @@ FRESULT f_setlabel ( if (res == FR_OK) { mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { @@ -5637,7 +5838,7 @@ FRESULT f_mkfs ( UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ + const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ @@ -5701,7 +5902,7 @@ FRESULT f_mkfs ( } else { /* Create a single-partition in this function */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } @@ -5745,7 +5946,7 @@ FRESULT f_mkfs ( b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ - if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ @@ -5826,11 +6027,11 @@ FRESULT f_mkfs ( /* Initialize the root directory */ mem_set(buf, 0, szb_buf); - buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ - buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ - buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ @@ -5925,6 +6126,9 @@ FRESULT f_mkfs ( if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ + if (n % n_fats) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } sz_fat += n / n_fats; } @@ -5988,13 +6192,13 @@ FRESULT f_mkfs ( st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ @@ -6318,8 +6522,7 @@ typedef struct { /* Putchar output buffer and work area */ } putbuff; -static -void putc_bfd ( /* Buffered write with code conversion */ +static void putc_bfd ( /* Buffered write with code conversion */ putbuff* pb, TCHAR c ) @@ -6430,7 +6633,7 @@ void putc_bfd ( /* Buffered write with code conversion */ #else /* Write it in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ - if (wc == 0) return;; + if (wc == 0) return; if (wc >= 0x100) { pb->buf[i++] = (BYTE)(wc >> 8); nc++; } @@ -6450,8 +6653,7 @@ void putc_bfd ( /* Buffered write with code conversion */ } -static -int putc_flush ( /* Flush left characters in the buffer */ +static int putc_flush ( /* Flush left characters in the buffer */ putbuff* pb ) { @@ -6464,8 +6666,7 @@ int putc_flush ( /* Flush left characters in the buffer */ } -static -void putc_init ( /* Initialize write buffer */ +static void putc_init ( /* Initialize write buffer */ putbuff* pb, FIL* fp ) diff --git a/ariane/src/lib/ff.h b/ariane/src/bdk/libs/fatfs/ff.h similarity index 92% rename from ariane/src/lib/ff.h rename to ariane/src/bdk/libs/fatfs/ff.h index edef011..a83cf63 100644 --- a/ariane/src/lib/ff.h +++ b/ariane/src/bdk/libs/fatfs/ff.h @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.13b / +/ FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. @@ -20,14 +20,14 @@ #ifndef FF_DEFINED -#define FF_DEFINED 63463 /* Revision ID */ +#define FF_DEFINED 86604 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif -#include "integer.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ +#include /* Basic integer types */ +#include /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). @@ -95,8 +95,9 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { - BYTE fs_type; /* Filesystem type (0:N/A) */ - BYTE pdrv; /* Physical drive number */ + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ @@ -133,8 +134,10 @@ typedef struct { DWORD fatbase; /* FAT base sector */ DWORD dirbase; /* Root directory base sector/cluster */ DWORD database; /* Data base sector */ +#if FF_FS_EXFAT + DWORD bitbase; /* Allocation bitmap base sector */ +#endif DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -145,7 +148,7 @@ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT @@ -165,6 +168,9 @@ typedef struct { /* File object structure (FIL) */ typedef struct { +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ +#endif FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ @@ -178,9 +184,6 @@ typedef struct { #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif } FIL; @@ -243,7 +246,12 @@ typedef enum { FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ +#if FF_FASTFS + FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ + FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */ +#else FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +#endif } FRESULT; @@ -255,6 +263,8 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */ +FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ @@ -276,7 +286,8 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ @@ -365,12 +376,15 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ +#define AM_DEV 0x40 /* Device */ +#define AM_RVD 0x80 /* Reserved */ #ifdef __cplusplus } #endif -#endif /* FF_DEFINED */ \ No newline at end of file +#endif /* FF_DEFINED */ diff --git a/ariane/src/lib/ffunicode.c b/ariane/src/bdk/libs/fatfs/ffunicode.c similarity index 99% rename from ariane/src/lib/ffunicode.c rename to ariane/src/bdk/libs/fatfs/ffunicode.c index befbbf4..9f03963 100644 --- a/ariane/src/lib/ffunicode.c +++ b/ariane/src/bdk/libs/fatfs/ffunicode.c @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13a */ +/* Unicode handling functions for FatFs R0.13c */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / @@ -7,7 +7,7 @@ / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2017, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -25,16 +25,15 @@ #include "ff.h" -#if FF_USE_LFN /* This module is blanked when non-LFN configuration */ +#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ -#if FF_DEFINED != 63463 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) - /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ @@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ return uni; } - -#endif /* #if FF_USE_LFN */ \ No newline at end of file +#endif /* #if FF_USE_LFN */ diff --git a/ariane/src/bdk/libs/lv_conf.h b/ariane/src/bdk/libs/lv_conf.h new file mode 100644 index 0000000..ab7f311 --- /dev/null +++ b/ariane/src/bdk/libs/lv_conf.h @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#include +#include +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +# define LV_MEM_SIZE NYX_LV_MEM_SZ /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +# define LV_MEM_ADR NYX_LV_MEM_ADR /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (1280) +#define LV_VER_RES (720) + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI 100 + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ + +/*Screen refresh period in milliseconds*/ +#define LV_REFR_PERIOD 33 + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#define LV_VDB_SIZE (LV_VER_RES * LV_HOR_RES) + + /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ + + /* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR NYX_LV_VDB_ADR + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#define LV_VDB_DOUBLE 0 + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#define LV_VDB2_ADR 0 + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 33 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME 1000 //Fix keyb /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/ +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 0 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ + +/*Feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 0 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW 0 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 0 /*1: Enable file system (might be required for images*/ +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ + +/*Compiler settings*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ + +/*HAL settings*/ +#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#if LV_TICK_CUSTOM == 1 +#define LV_TICK_CUSTOM_INCLUDE /*Header for the sys time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (get_tmr_ms()) /*Expression evaluating to current systime in ms*/ +#endif /*LV_TICK_CUSTOM*/ + + +/*Log settings*/ +#define USE_LV_LOG 0 /*Enable/disable the log module*/ +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ +# define LV_LOG_PRINTF 1 +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ + +#define USE_LV_THEME_HEKATE 1 /*Flat theme with bold colors and light shadows*/ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#define LV_FONT_QUALITY 8 + +#define USE_UBUNTU_MONO LV_FONT_QUALITY + +#define USE_INTERUI_20 LV_FONT_QUALITY +#define USE_INTERUI_30 LV_FONT_QUALITY + +#define USE_HEKATE_SYMBOL_20 USE_INTERUI_20 +#define USE_HEKATE_SYMBOL_30 USE_INTERUI_30 +#define USE_HEKATE_SYMBOL_120 LV_FONT_QUALITY + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#define LV_FONT_CUSTOM_DECLARE + +#define LV_FONT_DEFAULT &interui_30 /*Always set a default font from the built-in fonts*/ + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#define LV_OBJ_REALIGN 1 // 0 in OG gui /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 0 /*Enable indexed (palette) images*/ +# define LV_IMG_CF_ALPHA 0 /*Enable alpha indexed images*/ +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 + +/*Arc (dependencies: -)*/ +#define USE_LV_ARC 0 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +# if USE_LV_TABVIEW != 0 +# define LV_TABVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/*Tileview (dependencies: lv_page) */ +#define USE_LV_TILEVIEW 0 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/ +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 0 + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#define USE_LV_GAUGE 0 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 0 + +/*Table (dependencies: lv_label)*/ +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 0 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#define USE_LV_SPINBOX 0 + +/*Calendar (dependencies: -)*/ +#define USE_LV_CALENDAR 0 + +/*Preload (dependencies: lv_arc)*/ +#define USE_LV_PRELOAD 0 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +/*Canvas (dependencies: lv_img)*/ +#define USE_LV_CANVAS 0 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 0 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif + +/*Image Button (dependencies: lv_btn*/ +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 0 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +# define LV_DDLIST_ANIM_TIME 100 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +#endif /*LV_CONF_H*/ + diff --git a/ariane/src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md b/ariane/src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c7d7eeb --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/ariane/src/bdk/libs/lvgl/docs/CONTRIBUTING.md b/ariane/src/bdk/libs/lvgl/docs/CONTRIBUTING.md new file mode 100644 index 0000000..5d1d912 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/docs/CONTRIBUTING.md @@ -0,0 +1,103 @@ +# Contributing to Littlev Graphics Library + +**Welcome! It's glad to see that you are interested in contributing to LittlevGL! There are several types of task where you can help to build a better library! Let's see how to get started!** + + +There are many different possibilities to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can: +- answer other's questions +- report and/or fix bugs +- suggest and/or implement new features +- improve and/or translate the documentation +- write a blog post about your experiences + +But first, start with the most Frequently Asked Questions. + +## FAQ about contributing + +### What license does my code need to be under? + +Any code added to LittlevGL must be licensed under [MIT](https://choosealicense.com/licenses/mit/) or another license that is fully compatible. Contributions under other licenses are highly likely to be rejected. + +If you borrow code from another project, please make sure to add their copyright notice to your contribution. + +### Where do I ask questions, give feedback, or report bugs? + +We use the [forum](http://forum.littlevgl.com/) for questions, feature suggestions, and discussions. + +We use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) to report bugs. + +For both of these there are some rules: +- Be kind and friendly. +- Speak about one thing in one issue. +- Give feedback and close the issue if your question is answered. +- Explain exactly what you experience or expect. _"The button is not working"_ is not enough info to get help. +- For most issues you should send an absolute minimal code example in order to reproduce the issue. Ideally this should be easily usable in the PC simulator. +- Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) to format your post. +- If you don't get any answer in a week write a comment like "Can somebody help?". Maybe your issue wasn't noticed. + +### How can I send fixes and improvements? +Merging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide about them: +1. **Fork** the [lvgl repository](https://github.com/littlevgl/lvgl). To do this click the "Fork" button in the top right corner. It will "copy" the `lvgl` repository to your GitHub account (`https://github.com/your_name?tab=repositories`) +2. **Clone** the forked repository and add your updates +3. **Create a PR** on the GitHub on the page of you `lvgl` repository(`https://github.com/your_name/lvgl`) by hitting the "New pull request" button +4. **Set the base branch**. It means where you want to merge your update. Bugfixes for the last release go to `master`, new features to the actual `dev-x.y` branch. +5. **Describe** what is in the update. An example code is welcome if applicable. + +Some advice: +- If you are not sure about your fix or feature it's better to open an issue first, and discuss the details there. +- Maybe your fix or update won't be perfect at first. Don't be afraid, just improve it and push the new commits. The PR will be updated accordingly. +- If your update needs some extra work it's okay to say: _"I'm busy now and I will improve it soon"_ or _"Sorry, I don't have time to improve it, I hope it helps in this form too"_. So it's better to say don't have time to continue then saying nothing. +- Please read and follow this [guide about the coding style](https://docs.littlevgl.com/#Coding-Style-Guide) + + +### Where is the documentation? + +You can read the documentation here: https://docs.littlevgl.com/ +You can edit the documentation here: https://github.com/littlevgl/doc + +### Where is the blog? + +You can read the blog here: https://blog.littlevgl.com/ +You can edit the blog here: https://github.com/littlevgl/blog + + +## So how and where can I contribute? + +### Answering other's questions + +It's a great way to contribute to the library if you already use it. Just go the [issue tracker](https://github.com/littlevgl/lvgl/issues), read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion. + +### Reporting and/or fixing bugs +For simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet. + +### Suggesting and/or implementing new features +If you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started. + +During the implementation don't forget the [Code style guide](https://docs.littlevgl.com/#Coding-Style-Guide). + +### Improving and/or translating the documentation + +The documentation of LittlevGL is written in Markdown and available [here](https://github.com/littlevgl/doc) for editing. If you find some parts of the documentation obscure or insufficient just search the related `.md` file, hit the edit icon and add your updates. This way a new Pull request will be generated automatically. + +If you can devote more time to improve the documentation you can translate it! +1. Just copy the English `.md` files from the root folder to `locale/LANGUAGE_CODE` (language code is e.g. DE, FR, ES etc) +2. Append the language code the end of files (e.g. Welcome_fr.md) +3. Update the filenames in `_Sidebar.md` +4. Translate the page(s) you want +5. Create a Pull request + +### Writing a blog post about your experiences + +Have ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick? +You can share your knowledge on LittelvGL's blog! It's super easy to add your own post: +- Fork and clone the [blog repository](https://github.com/littlevgl/blog) +- Add your post in Markdown to the `_posts` folder. +- Store the images and other resources in a dedicated folder in `assets` +- Create a Pull Request + +The blog uses [Jekyll](https://jekyllrb.com/) to convert the `.md` files to a webpage. You can easily [run Jekyll offline](https://jekyllrb.com/docs/) to check your post before creating the Pull request + +## Summary + +I hope you have taken a liking to contribute to LittelvGL. A helpful and friendly community is waiting for you! :) + diff --git a/ariane/src/bdk/libs/lvgl/docs/astyle_c b/ariane/src/bdk/libs/lvgl/docs/astyle_c new file mode 100644 index 0000000..9b9d7f3 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/docs/astyle_c @@ -0,0 +1 @@ +--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent= diff --git a/ariane/src/bdk/libs/lvgl/docs/astyle_h b/ariane/src/bdk/libs/lvgl/docs/astyle_h new file mode 100644 index 0000000..d9c7633 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/docs/astyle_h @@ -0,0 +1 @@ +--convert-tabs --indent=spaces=4 diff --git a/ariane/src/bdk/libs/lvgl/licence.txt b/ariane/src/bdk/libs/lvgl/licence.txt new file mode 100644 index 0000000..beaef1d --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/licence.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Softwareâ€), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS ISâ€, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_core.mk b/ariane/src/bdk/libs/lvgl/lv_core/lv_core.mk new file mode 100644 index 0000000..9992e3f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_core.mk @@ -0,0 +1,12 @@ +CSRCS += lv_group.c +CSRCS += lv_indev.c +CSRCS += lv_obj.c +CSRCS += lv_refr.c +CSRCS += lv_style.c +CSRCS += lv_vdb.c +CSRCS += lv_lang.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core +VPATH += :$(LVGL_DIR)/lvgl/lv_core + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core" diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_group.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_group.c new file mode 100644 index 0000000..3fd4120 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_group.c @@ -0,0 +1,554 @@ +/** + * @file lv_group.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_group.h" +#if USE_LV_GROUP != 0 +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void style_mod_def(lv_style_t * style); +static void style_mod_edit_def(lv_style_t * style); +static void lv_group_refocus(lv_group_t *g); +static void obj_to_foreground(lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void) +{ + lv_group_t * group = lv_mem_alloc(sizeof(lv_group_t)); + lv_mem_assert(group); + if(group == NULL) return NULL; + lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *)); + + group->style_mod = style_mod_def; + group->style_mod_edit = style_mod_edit_def; + group->obj_focus = NULL; + group->frozen = 0; + group->focus_cb = NULL; + group->click_focus = 1; + group->editing = 0; + + return group; +} + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group) +{ + /*Defocus the the currently focused object*/ + if(group->obj_focus != NULL) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + /*Remove the objects from the group*/ + lv_obj_t ** obj; + LL_READ(group->obj_ll, obj) { + (*obj)->group_p = NULL; + } + + lv_ll_clear(&(group->obj_ll)); + lv_mem_free(group); +} + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) +{ + if(group == NULL) return; + + /*If the object is already in a group and focused then defocus it*/ + if(obj->group_p) { + if(lv_obj_is_focused(obj)) { + lv_group_refocus(obj->group_p); + + LV_LOG_INFO("group: assign object to an other group"); + } + } + + obj->group_p = group; + lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll); + lv_mem_assert(next); + if(next == NULL) return; + *next = obj; + + /* If the head and the tail is equal then there is only one object in the linked list. + * In this case automatically activate it*/ + if(lv_ll_get_head(&group->obj_ll) == next) { + lv_group_refocus(group); + } +} + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj) +{ + lv_group_t * g = obj->group_p; + if(g == NULL) return; + if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/ + + /*Focus on the next object*/ + if(*g->obj_focus == obj) { + /*If this is the only object in the group then focus to nothing.*/ + if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + } + /*If there more objects in the group then focus to the next/prev object*/ + else { + lv_group_refocus(g); + } + } + + /* If the focuses object is still the same then it was the only object in the group but it will be deleted. + * Set the `obj_focus` to NULL to get back to the initial state of the group with zero objects*/ + if(*g->obj_focus == obj) { + g->obj_focus = NULL; + } + + /*Search the object and remove it from its group */ + lv_obj_t ** i; + LL_READ(g->obj_ll, i) { + if(*i == obj) { + lv_ll_rem(&g->obj_ll, i); + lv_mem_free(i); + obj->group_p = NULL; + break; + } + } +} + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj) +{ + lv_group_t * g = obj->group_p; + if(g == NULL) return; + + if(g->frozen != 0) return; + + /*On defocus edit mode must be leaved*/ + lv_group_set_editing(g, false); + + lv_obj_t ** i; + LL_READ(g->obj_ll, i) { + if(*i == obj) { + if(g->obj_focus == i) return; /*Don't focus the already focused object again*/ + if(g->obj_focus != NULL) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*g->obj_focus); + } + + g->obj_focus = i; + + if(g->obj_focus != NULL) { + (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_FOCUS, NULL); + if(g->focus_cb) g->focus_cb(g); + lv_obj_invalidate(*g->obj_focus); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*g->obj_focus); + } + break; + } + } +} + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group) +{ + if(group->frozen) return; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + lv_obj_t ** obj_next; + if(group->obj_focus == NULL) obj_next = lv_ll_get_head(&group->obj_ll); + else obj_next = lv_ll_get_next(&group->obj_ll, group->obj_focus); + + if(obj_next == NULL) { + if(group->wrap) obj_next = lv_ll_get_head(&group->obj_ll); + else obj_next = lv_ll_get_tail(&group->obj_ll); + } + group->obj_focus = obj_next; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + + if(group->focus_cb) group->focus_cb(group); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*group->obj_focus); + } +} + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group) +{ + if(group->frozen) return; + + if(group->obj_focus) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + } + + lv_obj_t ** obj_next; + if(group->obj_focus == NULL) obj_next = lv_ll_get_tail(&group->obj_ll); + else obj_next = lv_ll_get_prev(&group->obj_ll, group->obj_focus); + + if(obj_next == NULL) { + if(group->wrap) obj_next = lv_ll_get_tail(&group->obj_ll); + else obj_next = lv_ll_get_head(&group->obj_ll); + } + group->obj_focus = obj_next; + + if(group->obj_focus != NULL) { + (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL); + lv_obj_invalidate(*group->obj_focus); + + if(group->focus_cb) group->focus_cb(group); + + /*If the object or its parent has `top == true` bring it to the foregorund*/ + obj_to_foreground(*group->obj_focus); + } + +} + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en) +{ + if(en == false) group->frozen = 0; + else group->frozen = 1; +} + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c) +{ + lv_obj_t * act = lv_group_get_focused(group); + if(act == NULL) return LV_RES_OK; + + return act->signal_func(act, LV_SIGNAL_CONTROLL, &c); +} + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func) +{ + group->style_mod = style_mod_func; + if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus); +} + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func) +{ + group->style_mod_edit = style_mod_func; + if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus); +} + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb) +{ + group->focus_cb = focus_cb; +} + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit) +{ + uint8_t en_val = edit ? 1 : 0; + + if(en_val == group->editing) return; /*Do not set the same mode again*/ + + group->editing = en_val; + lv_obj_t * focused = lv_group_get_focused(group); + + if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave edit mode*/ + + lv_obj_invalidate(focused); +} + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en) +{ + group->click_focus = en ? 1 : 0; +} + +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy) { + group->refocus_policy = policy & 0x01; +} + +static void lv_group_refocus(lv_group_t *g) { + /*Refocus must temporarily allow wrapping to work correctly*/ + uint8_t temp_wrap = g->wrap; + g->wrap = 1; + + if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT) + lv_group_focus_next(g); + else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV) + lv_group_focus_prev(g); + /*Restore wrap property*/ + g->wrap = temp_wrap; +} + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_wrap(lv_group_t * group, bool en) +{ + group->wrap = en ? 1 : 0; +} + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style) +{ + lv_style_copy(&group->style_tmp, style); + + if(group->editing) { + if(group->style_mod_edit) group->style_mod_edit(&group->style_tmp); + } else { + if(group->style_mod) group->style_mod(&group->style_tmp); + } + return &group->style_tmp; +} + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group) +{ + if(!group) return NULL; + if(group->obj_focus == NULL) return NULL; + + return *group->obj_focus; +} + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->style_mod ; +} + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->style_mod_edit; +} + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group) +{ + if(!group) return false; + return group->focus_cb; +} + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group) +{ + if(!group) return false; + return group->editing ? true : false; +} + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group) +{ + if(!group) return false; + return group->click_focus ? true : false; +} + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group) +{ + if(!group) return false; + return group->wrap ? true : false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Default style modifier function + * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN. + */ +static void style_mod_def(lv_style_t * style) +{ +#if LV_COLOR_DEPTH != 1 + + /*Make the style to be a little bit orange*/ + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_ORANGE; + + /*If not empty or has border then emphasis the border*/ + if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20; + + style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_ORANGE, LV_OPA_70); + style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_ORANGE, LV_OPA_70); + style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_ORANGE, LV_OPA_60); + + style->text.color = lv_color_mix(style->text.color, LV_COLOR_ORANGE, LV_OPA_70); +#else + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_BLACK; + style->body.border.width = 2; + +#endif + +} + +/** + * Default style modifier function + * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN. + */ +static void style_mod_edit_def(lv_style_t * style) +{ +#if LV_COLOR_DEPTH != 1 + + /*Make the style to be a little bit orange*/ + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_GREEN; + + /*If not empty or has border then emphasis the border*/ + if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20; + + style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_GREEN, LV_OPA_70); + style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_GREEN, LV_OPA_70); + style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_GREEN, LV_OPA_60); + + style->text.color = lv_color_mix(style->text.color, LV_COLOR_GREEN, LV_OPA_70); +#else + style->body.border.opa = LV_OPA_COVER; + style->body.border.color = LV_COLOR_BLACK; + style->body.border.width = 3; + +#endif + +} + +static void obj_to_foreground(lv_obj_t * obj) +{ + /*Search for 'top' attribute*/ + lv_obj_t * i = obj; + lv_obj_t * last_top = NULL; + while(i != NULL) { + if(i->top != 0) last_top = i; + i = lv_obj_get_parent(i); + } + + if(last_top != NULL) { + /*Move the last_top object to the foreground*/ + lv_obj_t * par = lv_obj_get_parent(last_top); + /*After list change it will be the new head*/ + lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); + lv_obj_invalidate(last_top); + } +} + +#endif /*USE_LV_GROUP != 0*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_group.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_group.h new file mode 100644 index 0000000..6be9b5c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_group.h @@ -0,0 +1,247 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ +/*For compatibility in signal function define the keys regardless to LV_GROUP*/ +#define LV_GROUP_KEY_UP 17 /*0x11*/ +#define LV_GROUP_KEY_DOWN 18 /*0x12*/ +#define LV_GROUP_KEY_RIGHT 19 /*0x13*/ +#define LV_GROUP_KEY_LEFT 20 /*0x14*/ +#define LV_GROUP_KEY_ESC 27 /*0x1B*/ +#define LV_GROUP_KEY_DEL 127 /*0x7F*/ +#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/ +#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/ +#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/ +#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/ + +#if USE_LV_GROUP != 0 +/********************** + * TYPEDEFS + **********************/ +struct _lv_group_t; + +typedef void (*lv_group_style_mod_func_t)(lv_style_t *); +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); + +typedef struct _lv_group_t +{ + lv_ll_t obj_ll; /*Linked list to store the objects in the group */ + lv_obj_t ** obj_focus; /*The object in focus*/ + lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/ + lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/ + lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ + lv_style_t style_tmp; /*Stores the modified style of the focused object */ + uint8_t frozen :1; /*1: can't focus to new object*/ + uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/ + uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */ + uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/ + uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/ +} lv_group_t; + +typedef enum _lv_group_refocus_policy_t { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void); + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group); + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj); + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group); + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group); + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en); + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c); + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb); + +/** + * Set whether the next or previous item in a group is focused if the currently focussed obj is deleted. + * @param group pointer to a group + * @param new refocus policy enum + */ +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy); + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit); + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en); + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +void lv_group_set_wrap(lv_group_t * group, bool en); + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group); + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group); + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group); + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group); + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group); + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GROUP != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.c new file mode 100644 index 0000000..763abf7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.c @@ -0,0 +1,971 @@ +/** + * @file lv_indev_proc.c + * + */ + +/********************* + * INCLUDES + ********************/ +#include "lv_indev.h" + +#include "../lv_hal/lv_hal_tick.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_refr.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_rbasic.h" +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +#if LV_INDEV_READ_PERIOD != 0 +static void indev_proc_task(void * param); +static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data); +static void indev_proc_press(lv_indev_proc_t * proc); +static void indev_proc_release(lv_indev_proc_t * proc); +static void indev_proc_reset_query_handler(lv_indev_t * indev); +static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj); +static void indev_drag(lv_indev_proc_t * state); +static void indev_drag_throw(lv_indev_proc_t * state); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_indev_t * indev_act; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void) +{ +#if LV_INDEV_READ_PERIOD != 0 + lv_task_create(indev_proc_task, LV_INDEV_READ_PERIOD, LV_TASK_PRIO_MID, NULL); +#endif + + lv_indev_reset(NULL); /*Reset all input devices*/ +} + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void) +{ + return indev_act; +} + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev) +{ + if(indev == NULL) return LV_INDEV_TYPE_NONE; + + return indev->driver.type; +} +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev) +{ + if(indev) indev->proc.reset_query = 1; + else { + lv_indev_t * i = lv_indev_next(NULL); + while(i) { + i->proc.reset_query = 1; + i = lv_indev_next(i); + } + } +} + +/** + * Reset the long press state of an input device + * @param indev pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev) +{ + indev->proc.long_pr_sent = 0; + indev->proc.longpr_rep_timestamp = lv_tick_get(); + indev->proc.pr_timestamp = lv_tick_get(); +} + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable) +{ + lv_indev_t * i = lv_indev_next(NULL); + + while(i) { + if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0; + i = lv_indev_next(i); + } +} + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj) +{ + if(indev->driver.type != LV_INDEV_TYPE_POINTER) return; + + indev->cursor = cur_obj; + if (indev->cursor) + { + lv_obj_set_parent(indev->cursor, lv_layer_sys()); + lv_obj_set_pos(indev->cursor, indev->proc.act_point.x, indev->proc.act_point.y); + } +} + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group) +{ + if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) indev->group = group; +} +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points) +{ + if(indev->driver.type == LV_INDEV_TYPE_BUTTON) indev->btn_points = points; +} + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback) +{ + indev->feedback = feedback; +} + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point) +{ + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) { + point->x = -1; + point->y = -1; + } else { + point->x = indev->proc.act_point.x; + point->y = indev->proc.act_point.y; + } +} + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev) +{ + if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0; + else return indev->proc.last_key; +} + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev) +{ + if(indev == NULL) return false; + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false; + return indev->proc.drag_in_prog == 0 ? false : true; +} + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point) +{ + if(indev == NULL) { + point->x = 0; + point->y = 0; + return; + } + + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) { + point->x = 0; + point->y = 0; + } else { + point->x = indev->proc.vect.x; + point->y = indev->proc.vect.y; + } +} + +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev) +{ + uint32_t t; + + if(indev) return t = lv_tick_elaps(indev->last_activity_time); + + lv_indev_t * i; + t = UINT16_MAX; + i = lv_indev_next(NULL); + while(i) { + t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time)); + i = lv_indev_next(i); + } + + return t; +} + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev) +{ + return indev->feedback; +} + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev) +{ + indev->proc.wait_unil_release = 1; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_INDEV_READ_PERIOD != 0 +/** + * Called periodically to handle the input devices + * @param param unused + */ +static void indev_proc_task(void * param) +{ + (void)param; + + + LV_LOG_TRACE("indev task started"); + + lv_indev_data_t data; + lv_indev_t * i; + i = lv_indev_next(NULL); + + /*Read and process all indevs*/ + while(i) { + indev_act = i; + + /*Handle reset query before processing the point*/ + indev_proc_reset_query_handler(i); + + if(i->proc.disabled == 0) { + bool more_to_read; + do { + /*Read the data*/ + more_to_read = lv_indev_read(i, &data); + indev_proc_reset_query_handler(i); /*The active object might deleted even in the read function*/ + i->proc.state = data.state; + + if(i->proc.state == LV_INDEV_STATE_PR) { + i->last_activity_time = lv_tick_get(); + } + + if(i->driver.type == LV_INDEV_TYPE_POINTER) { + indev_pointer_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) { + indev_keypad_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_ENCODER) { + indev_encoder_proc(i, &data); + } else if(i->driver.type == LV_INDEV_TYPE_BUTTON) { + indev_button_proc(i, &data); + } + /*Handle reset query if it happened in during processing*/ + indev_proc_reset_query_handler(i); + } while(more_to_read); + } + i = lv_indev_next(i); /*Go to the next indev*/ + } + + indev_act = NULL; /*End of indev processing, so no act indev*/ + + LV_LOG_TRACE("indev task finished"); +} + + +/** + * Process a new point from LV_INDEV_TYPE_POINTER input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data) +{ + /*Move the cursor if set and moved*/ + if(i->cursor != NULL && + (i->proc.last_point.x != data->point.x || + i->proc.last_point.y != data->point.y)) { + /*Use cursor's center as pointer*/ + uint32_t off_x = lv_obj_get_width(i->cursor) >> 1; + uint32_t off_y = lv_obj_get_height(i->cursor) >> 1; + lv_obj_set_pos(i->cursor, data->point.x - off_x, data->point.y - off_y); + } + + i->proc.act_point.x = data->point.x; + i->proc.act_point.y = data->point.y; + + if(i->proc.state == LV_INDEV_STATE_PR) { +#if LV_INDEV_POINT_MARKER != 0 + lv_area_t area; + area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1); + area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1); + area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER); +#endif + indev_proc_press(&i->proc); + } else { + indev_proc_release(&i->proc); + } + + i->proc.last_point.x = i->proc.act_point.x; + i->proc.last_point.y = i->proc.act_point.y; +} + +/** + * Process a new point from LV_INDEV_TYPE_KEYPAD input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data) +{ +#if USE_LV_GROUP + if(i->group == NULL) return; + + /*Key press happened*/ + if(data->state == LV_INDEV_STATE_PR && + i->proc.last_state == LV_INDEV_STATE_REL) { + i->proc.pr_timestamp = lv_tick_get(); + lv_obj_t * focused = lv_group_get_focused(i->group); + if(focused && data->key == LV_GROUP_KEY_ENTER) { + focused->signal_func(focused, LV_SIGNAL_PRESSED, indev_act); + } + } + /*Pressing*/ + else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) { + if(data->key == LV_GROUP_KEY_ENTER && + i->proc.long_pr_sent == 0 && + lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + /*On enter long press leave edit mode.*/ + lv_obj_t * focused = lv_group_get_focused(i->group); + if(focused) { + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + i->proc.long_pr_sent = 1; + } + } + } + /*Release happened*/ + else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) { + /*The user might clear the key when it was released. Always release the pressed key*/ + data->key = i->proc.last_key; + + /* Edit mode is not used by KEYPAD devices. + * So leave edit mode if we are in it before focusing on the next/prev object*/ + if(data->key == LV_GROUP_KEY_NEXT || data->key == LV_GROUP_KEY_PREV) { + lv_group_set_editing(i->group, false); + } + + if(data->key == LV_GROUP_KEY_NEXT) { + lv_group_focus_next(i->group); + } else if(data->key == LV_GROUP_KEY_PREV) { + lv_group_focus_prev(i->group); + } else if(data->key == LV_GROUP_KEY_ENTER) { + if(!i->proc.long_pr_sent) { + lv_group_send_data(i->group, data->key); + } + } else { + lv_group_send_data(i->group, data->key); + } + + if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/ + + i->proc.pr_timestamp = 0; + i->proc.long_pr_sent = 0; + } + + i->proc.last_state = data->state; + i->proc.last_key = data->key; +#else + (void)data; /*Unused*/ + (void)i; /*Unused*/ +#endif +} + +/** + * Process a new point from LV_INDEV_TYPE_ENCODER input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + */ +static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data) +{ +#if USE_LV_GROUP + if(i->group == NULL) return; + + /*Process the steps first. They are valid only with released button*/ + if(data->state == LV_INDEV_STATE_REL) { + /*In edit mode send LEFT/RIGHT keys*/ + if(lv_group_get_editing(i->group)) { + int32_t s; + if(data->enc_diff < 0) { + for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_LEFT); + } else if(data->enc_diff > 0) { + for(s = 0; s < data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_RIGHT); + } + } + /*In navigate mode focus on the next/prev objects*/ + else { + int32_t s; + if(data->enc_diff < 0) { + for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(i->group); + } else if(data->enc_diff > 0) { + for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(i->group); + } + } + } + + /*Key press happened*/ + if(data->state == LV_INDEV_STATE_PR && + i->proc.last_state == LV_INDEV_STATE_REL) { + i->proc.pr_timestamp = lv_tick_get(); + } + /*Pressing*/ + else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) { + if(i->proc.long_pr_sent == 0 && + lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + /*On enter long press leave edit mode.*/ + lv_obj_t * focused = lv_group_get_focused(i->group); + + bool editable = false; + if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable); + + if(editable) { + if(i->group->obj_ll.head != i->group->obj_ll.tail) + lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/ + else if(focused) + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + } + /*If not editable then just send a long press signal*/ + else { + if(focused) + focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act); + } + i->proc.long_pr_sent = 1; + } + } + /*Release happened*/ + else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) { + lv_obj_t * focused = lv_group_get_focused(i->group); + bool editable = false; + if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable); + + /*The button was released on a non-editable object. Just send enter*/ + if(!editable) { + lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); + } + /*An object is being edited and the button is releases. Just send enter */ + else if(i->group->editing) { + if(!i->proc.long_pr_sent || i->group->obj_ll.head == i->group->obj_ll.tail) + lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); /*Ignore long pressed enter release because it comes from mode switch*/ + } + /*If the focused object is editable and now in navigate mode then enter edit mode*/ + else if(editable && !i->group->editing && !i->proc.long_pr_sent) { + lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/ + } + + if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/ + + i->proc.pr_timestamp = 0; + i->proc.long_pr_sent = 0; + } + + i->proc.last_state = data->state; + i->proc.last_key = data->key; +#else + (void)data; /*Unused*/ + (void)i; /*Unused*/ +#endif +} + +/** + * Process new points from a input device. indev->state.pressed has to be set + * @param indev pointer to an input device state + * @param x x coordinate of the next point + * @param y y coordinate of the next point + */ +static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data) +{ + i->proc.act_point.x = i->btn_points[data->btn].x; + i->proc.act_point.y = i->btn_points[data->btn].y; + + /*Still the same point is pressed*/ + if(i->proc.last_point.x == i->proc.act_point.x && + i->proc.last_point.y == i->proc.act_point.y && + data->state == LV_INDEV_STATE_PR) { +#if LV_INDEV_POINT_MARKER != 0 + lv_area_t area; + area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1); + area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1); + area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1); + lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER); +#endif + indev_proc_press(&i->proc); + } else { + /*If a new point comes always make a release*/ + indev_proc_release(&i->proc); + } + + i->proc.last_point.x = i->proc.act_point.x; + i->proc.last_point.y = i->proc.act_point.y; +} + +/** + * Process the pressed state of LV_INDEV_TYPE_POINER input devices + * @param indev pointer to an input device 'proc' + */ +static void indev_proc_press(lv_indev_proc_t * proc) +{ + lv_obj_t * pr_obj = proc->act_obj; + + if(proc->wait_unil_release != 0) return; + + /*If there is no last object then search*/ + if(proc->act_obj == NULL) { + pr_obj = indev_search_obj(proc, lv_layer_top()); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act()); + } + /*If there is last object but it is not dragged and not protected also search*/ + else if(proc->drag_in_prog == 0 && + lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now act_obj != NULL*/ + pr_obj = indev_search_obj(proc, lv_layer_top()); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act()); + } + /*If a dragable or a protected object was the last then keep it*/ + else { + + } + + /*If a new object was found reset some variables and send a pressed signal*/ + if(pr_obj != proc->act_obj) { + + proc->last_point.x = proc->act_point.x; + proc->last_point.y = proc->act_point.y; + + /*If a new object found the previous was lost, so send a signal*/ + if(proc->act_obj != NULL) { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act); + if(proc->reset_query != 0) return; + } + + proc->act_obj = pr_obj; /*Save the pressed object*/ + proc->last_obj = proc->act_obj; /*Refresh the last_obj*/ + + if(proc->act_obj != NULL) { + /* Save the time when the obj pressed. + * It is necessary to count the long press time.*/ + proc->pr_timestamp = lv_tick_get(); + proc->long_pr_sent = 0; + proc->drag_range_out = 0; + proc->drag_in_prog = 0; + proc->drag_sum.x = 0; + proc->drag_sum.y = 0; + proc->vect.x = 0; + proc->vect.y = 0; + + /*Search for 'top' attribute*/ + lv_obj_t * i = proc->act_obj; + lv_obj_t * last_top = NULL; + while(i != NULL) { + if(i->top != 0) last_top = i; + i = lv_obj_get_parent(i); + } + + if(last_top != NULL) { + /*Move the last_top object to the foreground*/ + lv_obj_t * par = lv_obj_get_parent(last_top); + /*After list change it will be the new head*/ + lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); + lv_obj_invalidate(last_top); + } + + /*Send a signal about the press*/ + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSED, indev_act); + if(proc->reset_query != 0) return; + } + } + + /*Calculate the vector*/ + proc->vect.x = proc->act_point.x - proc->last_point.x; + proc->vect.y = proc->act_point.y - proc->last_point.y; + + /*If there is active object and it can be dragged run the drag*/ + if(proc->act_obj != NULL) { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSING, indev_act); + if(proc->reset_query != 0) return; + + indev_drag(proc); + if(proc->reset_query != 0) return; + + /*If there is no drag then check for long press time*/ + if(proc->drag_in_prog == 0 && proc->long_pr_sent == 0) { + /*Send a signal about the long press if enough time elapsed*/ + if(lv_tick_elaps(proc->pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) { + pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act); + if(proc->reset_query != 0) return; + + /*Mark the signal sending to do not send it again*/ + proc->long_pr_sent = 1; + + /*Save the long press time stamp for the long press repeat handler*/ + proc->longpr_rep_timestamp = lv_tick_get(); + } + } + /*Send long press repeated signal*/ + if(proc->drag_in_prog == 0 && proc->long_pr_sent == 1) { + /*Send a signal about the long press repeate if enough time elapsed*/ + if(lv_tick_elaps(proc->longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) { + pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act); + if(proc->reset_query != 0) return; + proc->longpr_rep_timestamp = lv_tick_get(); + + } + } + } +} + +/** + * Process the released state of LV_INDEV_TYPE_POINER input devices + * @param proc pointer to an input device 'proc' + */ +static void indev_proc_release(lv_indev_proc_t * proc) +{ + if(proc->wait_unil_release != 0) { + proc->act_obj = NULL; + proc->last_obj = NULL; + proc->pr_timestamp = 0; + proc->longpr_rep_timestamp = 0; + proc->wait_unil_release = 0; + } + + /*Forgot the act obj and send a released signal */ + if(proc->act_obj != NULL) { + /* If the object was protected against press lost then it possible that + * the object is already not pressed but still it is the `act_obj`. + * In this case send the `LV_SIGNAL_RELEASED` if the indev is ON the `act_obj` */ + if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST)) { + /* Search the object on the current current coordinates. + * The start object is the object itself. If not ON it the the result will be NULL*/ + lv_obj_t * obj_on = indev_search_obj(proc, proc->act_obj); + if(obj_on == proc->act_obj) proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act); + else proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act); + + } + /* The simple case: `act_obj` was not protected against press lost. + * If it is already not pressed then was handled in `indev_proc_press`*/ + else { + proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act); + } + + if(proc->reset_query != 0) return; + + /*Handle click focus*/ +#if USE_LV_GROUP + /*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/ + lv_group_t * act_g = lv_obj_get_group(proc->act_obj); + if(lv_group_get_editing(act_g)) { + lv_group_set_editing(act_g, false); + } + + /*Check, if the parent is in a group focus on it.*/ + if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_CLICK_FOCUS) == false) { /*Respect the click protection*/ + lv_group_t * g = lv_obj_get_group(proc->act_obj); + lv_obj_t * parent = proc->act_obj; + + while(g == NULL) { + parent = lv_obj_get_parent(parent); + if(parent == NULL) break; + if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/ + parent = NULL; + break; + } + g = lv_obj_get_group(parent); + } + + if(g != NULL && parent != NULL) + if(lv_group_get_click_focus(g)) { + lv_group_focus_obj(parent); + } + } +#endif + + if(proc->reset_query != 0) return; + proc->act_obj = NULL; + proc->pr_timestamp = 0; + proc->longpr_rep_timestamp = 0; + } + + /*The reset can be set in the signal function. + * In case of reset query ignore the remaining parts.*/ + if(proc->last_obj != NULL && proc->reset_query == 0) { + indev_drag_throw(proc); + if(proc->reset_query != 0) return; + } +} + +/** + * Process a new point from LV_INDEV_TYPE_BUTTON input device + * @param i pointer to an input device + * @param data pointer to the data read from the input device + * Reset input device if a reset query has been sent to it + * @param indev pointer to an input device + */ +static void indev_proc_reset_query_handler(lv_indev_t * indev) +{ + if(indev->proc.reset_query) { + indev->proc.act_obj = NULL; + indev->proc.last_obj = NULL; + indev->proc.drag_range_out = 0; + indev->proc.drag_in_prog = 0; + indev->proc.long_pr_sent = 0; + indev->proc.pr_timestamp = 0; + indev->proc.longpr_rep_timestamp = 0; + indev->proc.drag_sum.x = 0; + indev->proc.drag_sum.y = 0; + indev->proc.reset_query = 0; + } +} +/** + * Search the most top, clickable object on the last point of an input device + * @param proc pointer to the `lv_indev_proc_t` part of the input device + * @param obj pointer to a start object, typically the screen + * @return pointer to the found object or NULL if there was no suitable object + */ +static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj) +{ + lv_obj_t * found_p = NULL; + + /*If the point is on this object*/ + /*Check its children too*/ + if(lv_area_is_point_on(&obj->coords, &proc->act_point)) { + lv_obj_t * i; + + LL_READ(obj->child_ll, i) { + found_p = indev_search_obj(proc, i); + + /*If a child was found then break*/ + if(found_p != NULL) { + break; + } + } + + /*If then the children was not ok, and this obj is clickable + * and it or its parent is not hidden then save this object*/ + if(found_p == NULL && lv_obj_get_click(obj) != false) { + lv_obj_t * hidden_i = obj; + while(hidden_i != NULL) { + if(lv_obj_get_hidden(hidden_i) == true) break; + hidden_i = lv_obj_get_parent(hidden_i); + } + /*No parent found with hidden == true*/ + if(hidden_i == NULL) found_p = obj; + } + + } + + return found_p; +} + +/** + * Handle the dragging of indev_proc_p->act_obj + * @param indev pointer to a input device state + */ +static void indev_drag(lv_indev_proc_t * state) +{ + lv_obj_t * drag_obj = state->act_obj; + + /*If drag parent is active check recursively the drag_parent attribute*/ + while(lv_obj_get_drag_parent(drag_obj) != false && + drag_obj != NULL) { + drag_obj = lv_obj_get_parent(drag_obj); + } + + if(drag_obj == NULL) return; + + if(lv_obj_get_drag(drag_obj) == false) return; + + /*Count the movement by drag*/ + state->drag_sum.x += state->vect.x; + state->drag_sum.y += state->vect.y; + + /*Enough move?*/ + if(state->drag_range_out == 0) { + /*If a move is greater then LV_DRAG_LIMIT then begin the drag*/ + if(LV_MATH_ABS(state->drag_sum.x) >= LV_INDEV_DRAG_LIMIT || + LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT) { + state->drag_range_out = 1; + } + } + + /*If the drag limit is stepped over then handle the dragging*/ + if(state->drag_range_out != 0) { + /*Set new position if the vector is not zero*/ + if(state->vect.x != 0 || + state->vect.y != 0) { + /*Get the coordinates of the object and modify them*/ + lv_coord_t act_x = lv_obj_get_x(drag_obj); + lv_coord_t act_y = lv_obj_get_y(drag_obj); + uint16_t inv_buf_size = lv_refr_get_buf_size(); /*Get the number of currently invalidated areas*/ + + lv_coord_t prev_x = drag_obj->coords.x1; + lv_coord_t prev_y = drag_obj->coords.y1; + lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); + lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); + + lv_obj_set_pos(drag_obj, act_x + state->vect.x, act_y + state->vect.y); + + /*Set the drag in progress flag if the object is really moved*/ + + if(drag_obj->coords.x1 != prev_x || drag_obj->coords.y1 != prev_y) { + if(state->drag_range_out != 0) { /*Send the drag begin signal on first move*/ + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act); + if(state->reset_query != 0) return; + } + state->drag_in_prog = 1; + } + /*If the object didn't moved then clear the invalidated areas*/ + else { + /*In a special case if the object is moved on a page and + * the scrollable has fit == true and the object is dragged of the page then + * while its coordinate is not changing only the parent's size is reduced */ + lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); + lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); + if(act_par_w == prev_par_w && act_par_h == prev_par_h) { + uint16_t new_inv_buf_size = lv_refr_get_buf_size(); + lv_refr_pop_from_buf(new_inv_buf_size - inv_buf_size); + } + } + } + } +} + +/** + * Handle throwing by drag if the drag is ended + * @param indev pointer to an input device state + */ +static void indev_drag_throw(lv_indev_proc_t * state) +{ + if(state->drag_in_prog == 0) return; + + /*Set new position if the vector is not zero*/ + lv_obj_t * drag_obj = state->last_obj; + + /*If drag parent is active check recursively the drag_parent attribute*/ + while(lv_obj_get_drag_parent(drag_obj) != false && + drag_obj != NULL) { + drag_obj = lv_obj_get_parent(drag_obj); + } + + if(drag_obj == NULL) return; + + /*Return if the drag throw is not enabled*/ + if(lv_obj_get_drag_throw(drag_obj) == false) { + state->drag_in_prog = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + return; + } + + /*Reduce the vectors*/ + state->vect.x = state->vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + state->vect.y = state->vect.y * (100 - LV_INDEV_DRAG_THROW) / 100; + + if(state->vect.x != 0 || + state->vect.y != 0) { + /*Get the coordinates and modify them*/ + lv_area_t coords_ori; + lv_obj_get_coords(drag_obj, &coords_ori); + lv_coord_t act_x = lv_obj_get_x(drag_obj) + state->vect.x; + lv_coord_t act_y = lv_obj_get_y(drag_obj) + state->vect.y; + lv_obj_set_pos(drag_obj, act_x, act_y); + + lv_area_t coord_new; + lv_obj_get_coords(drag_obj, &coord_new); + + /*If non of the coordinates are changed then do not continue throwing*/ + if((coords_ori.x1 == coord_new.x1 || state->vect.x == 0) && + (coords_ori.y1 == coord_new.y1 || state->vect.y == 0)) { + state->drag_in_prog = 0; + state->vect.x = 0; + state->vect.y = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + + } + } + /*If the vectors become 0 -> drag_in_prog = 0 and send a drag end signal*/ + else { + state->drag_in_prog = 0; + drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act); + } +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.h new file mode 100644 index 0000000..19b047c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_indev.h @@ -0,0 +1,157 @@ +/** + * @file lv_indev_proc.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_core/lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void); + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void); + + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev); + +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev); + +/** + * Reset the long press state of an input device + * @param indev_proc pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev); + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable); + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj); + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group); +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points); + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback); + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point); + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev); + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev); + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev); + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.c new file mode 100644 index 0000000..c96ed78 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.c @@ -0,0 +1,117 @@ +/** + * @file lv_lang.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_lang.h" +#if USE_LV_MULTI_LANG + +#include "lv_obj.h" +#include "../lv_misc/lv_gc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lang_set_core(lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ +static uint8_t lang_act = 0; +static const void * (*get_txt)(uint16_t); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id) +{ + lang_act = lang_id; + + lv_obj_t * i; + LL_READ(LV_GC_ROOT(_lv_scr_ll), i) { + i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL); + + lang_set_core(i); + } + + lang_set_core(lv_scr_act()); +} + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)) +{ + get_txt = fp; +} + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id) +{ + if(get_txt == NULL) { + LV_LOG_WARN("lv_lang_get_text: text_func is not specified"); + return NULL; /*No text_get function specified */ + } + if(txt_id == LV_LANG_TXT_ID_NONE) { + LV_LOG_WARN("lv_lang_get_text: attempts to get invalid text ID"); + return NULL; /*Invalid txt_id*/ + } + + return get_txt(txt_id); +} + + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void) +{ + return lang_act; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Change the language of the children. (Called recursively) + * @param obj pointer to an object + */ +static void lang_set_core(lv_obj_t * obj) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL); + + lang_set_core(i); + } +} + +#endif /*USE_LV_MULTI_LANG*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.h new file mode 100644 index 0000000..5d76f64 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_lang.h @@ -0,0 +1,74 @@ +/** + * @file lv_lang.h + * + */ + +#ifndef LV_LANG_H +#define LV_LANG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_MULTI_LANG + +#include + +/********************* + * DEFINES + *********************/ +#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id); + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)); + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id); + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_MULTI_LANG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.c new file mode 100644 index 0000000..95c41a8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.c @@ -0,0 +1,1986 @@ +/** + * @file lv_base_obj.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "lv_indev.h" +#include "lv_refr.h" +#include "lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_draw/lv_draw_rbasic.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_ufs.h" +#include +#include +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ +#define LV_OBJ_DEF_WIDTH (LV_DPI) +#define LV_OBJ_DEF_HEIGHT (2 * LV_DPI / 3) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff); +static void report_style_mod_core(void * style_p, lv_obj_t * obj); +static void refresh_children_style(lv_obj_t * obj); +static void delete_children(lv_obj_t * obj); +static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); +static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ + +static bool _lv_initialized = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void) +{ + /* Do nothing if already initialized */ + if (_lv_initialized) + return; + + LV_GC_ROOT(_lv_def_scr) = NULL; + LV_GC_ROOT(_lv_act_scr) = NULL; + LV_GC_ROOT(_lv_top_layer) = NULL; + LV_GC_ROOT(_lv_sys_layer) = NULL; + LV_GC_ROOT(_lv_disp_list) = NULL; + LV_GC_ROOT(_lv_indev_list) = NULL; + + LV_LOG_TRACE("lv_init started"); + + /*Initialize the lv_misc modules*/ + lv_mem_init(); + lv_task_init(); + +#if USE_LV_FILESYSTEM + lv_fs_init(); + lv_ufs_init(); +#endif + + lv_font_init(); +#if USE_LV_ANIMATION + lv_anim_init(); +#endif + + /*Init. the sstyles*/ + lv_style_init(); + + /*Initialize the screen refresh system*/ + lv_refr_init(); + + /*Create the default screen*/ + lv_ll_init(&LV_GC_ROOT(_lv_scr_ll), sizeof(lv_obj_t)); + LV_GC_ROOT(_lv_def_scr) = lv_obj_create(NULL, NULL); + + LV_GC_ROOT(_lv_act_scr) = LV_GC_ROOT(_lv_def_scr); + + LV_GC_ROOT(_lv_top_layer) = lv_obj_create(NULL, NULL); + lv_obj_set_style(LV_GC_ROOT(_lv_top_layer), &lv_style_transp_fit); + + LV_GC_ROOT(_lv_sys_layer) = lv_obj_create(NULL, NULL); + lv_obj_set_style(LV_GC_ROOT(_lv_sys_layer), &lv_style_transp_fit); + + /*Refresh the screen*/ + lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr)); + +#if LV_INDEV_READ_PERIOD != 0 + /*Init the input device handling*/ + lv_indev_init(); +#endif + + _lv_initialized = true; + LV_LOG_INFO("lv_init ready"); +} + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) +{ + + lv_obj_t * new_obj = NULL; + /*Create a screen if the parent is NULL*/ + if(parent == NULL) { + LV_LOG_TRACE("Screen create started"); + + new_obj = lv_ll_ins_head(&LV_GC_ROOT(_lv_scr_ll)); + lv_mem_assert(new_obj); + if(new_obj == NULL) return NULL; + + new_obj->par = NULL; /*Screens has no a parent*/ + lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); + + /*Set coordinates to full screen size*/ + new_obj->coords.x1 = 0; + new_obj->coords.y1 = 0; + new_obj->coords.x2 = LV_HOR_RES - 1; + new_obj->coords.y2 = LV_VER_RES - 1; + new_obj->ext_size = 0; + + /*Init realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = LV_ALIGN_CENTER; + new_obj->realign.xofs = 0; + new_obj->realign.yofs = 0; + new_obj->realign.base = NULL; + new_obj->realign.auto_realign = 0; +#endif + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + new_obj->style_p = th->bg; + } else { + new_obj->style_p = &lv_style_scr; + } + /*Set virtual functions*/ + lv_obj_set_signal_func(new_obj, lv_obj_signal); + lv_obj_set_design_func(new_obj, lv_obj_design); + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = 0; +#endif + +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = NULL; +#endif + +#if USE_LV_GROUP + new_obj->group_p = NULL; +#endif + /*Set attributes*/ + new_obj->click = 0; + new_obj->drag = 0; + new_obj->drag_throw = 0; + new_obj->drag_parent = 0; + new_obj->hidden = 0; + new_obj->top = 0; + new_obj->opa_scale_en = 0; + new_obj->protect = LV_PROTECT_NONE; + new_obj->opa_scale = LV_OPA_COVER; + + new_obj->ext_attr = NULL; + + LV_LOG_INFO("Screen create ready"); + } + /*parent != NULL create normal obj. on a parent*/ + else { + LV_LOG_TRACE("Object create started"); + + new_obj = lv_ll_ins_head(&(parent)->child_ll); + lv_mem_assert(new_obj); + if(new_obj == NULL) return NULL; + + + new_obj->par = parent; /*Set the parent*/ + lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); + + /*Set coordinates left top corner of parent*/ + new_obj->coords.x1 = parent->coords.x1; + new_obj->coords.y1 = parent->coords.y1; + new_obj->coords.x2 = parent->coords.x1 + + LV_OBJ_DEF_WIDTH; + new_obj->coords.y2 = parent->coords.y1 + + LV_OBJ_DEF_HEIGHT; + new_obj->ext_size = 0; + + /*Init realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = LV_ALIGN_CENTER; + new_obj->realign.xofs = 0; + new_obj->realign.yofs = 0; + new_obj->realign.base = NULL; + new_obj->realign.auto_realign = 0; +#endif + /*Set appearance*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + new_obj->style_p = th->panel; + } else { + new_obj->style_p = &lv_style_plain_color; + } + + /*Set virtual functions*/ + lv_obj_set_signal_func(new_obj, lv_obj_signal); + lv_obj_set_design_func(new_obj, lv_obj_design); + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = 0; +#endif +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = NULL; +#endif +#if USE_LV_GROUP + new_obj->group_p = NULL; +#endif + + /*Set attributes*/ + new_obj->click = 1; + new_obj->drag = 0; + new_obj->drag_throw = 0; + new_obj->drag_parent = 0; + new_obj->hidden = 0; + new_obj->top = 0; + new_obj->protect = LV_PROTECT_NONE; + new_obj->opa_scale = LV_OPA_COVER; + new_obj->opa_scale_en = 0; + + new_obj->ext_attr = NULL; + } + + if(copy != NULL) { + lv_area_copy(&new_obj->coords, ©->coords); + new_obj->ext_size = copy->ext_size; + + /*Set free data*/ +#ifdef LV_OBJ_FREE_NUM_TYPE + new_obj->free_num = copy->free_num; +#endif +#if LV_OBJ_FREE_PTR != 0 + new_obj->free_ptr = copy->free_ptr; +#endif + + /*Copy realign*/ +#if LV_OBJ_REALIGN + new_obj->realign.align = copy->realign.align; + new_obj->realign.xofs = copy->realign.xofs; + new_obj->realign.yofs = copy->realign.yofs; + new_obj->realign.base = copy->realign.base; + new_obj->realign.auto_realign = copy->realign.auto_realign; +#endif + + /*Set attributes*/ + new_obj->click = copy->click; + new_obj->drag = copy->drag; + new_obj->drag_throw = copy->drag_throw; + new_obj->drag_parent = copy->drag_parent; + new_obj->hidden = copy->hidden; + new_obj->top = copy->top; + + new_obj->opa_scale_en = copy->opa_scale_en; + new_obj->protect = copy->protect; + new_obj->opa_scale = copy->opa_scale; + + new_obj->style_p = copy->style_p; + +#if USE_LV_GROUP + /*Add to the same group*/ + if(copy->group_p != NULL) { + lv_group_add_obj(copy->group_p, new_obj); + } +#endif + + /*Set the same coordinates for non screen objects*/ + if(lv_obj_get_parent(copy) != NULL && parent != NULL) { + lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy)); + } else { + lv_obj_set_pos(new_obj, 0, 0); + } + + LV_LOG_INFO("Object create ready"); + } + + + /*Send a signal to the parent to notify it about the new child*/ + if(parent != NULL) { + parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, new_obj); + + /*Invalidate the area if not screen created*/ + lv_obj_invalidate(new_obj); + } + + return new_obj; +} + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj) +{ + lv_obj_invalidate(obj); + + /*Delete from the group*/ +#if USE_LV_GROUP + if(obj->group_p != NULL) lv_group_remove_obj(obj); +#endif + + /*Remove the animations from this object*/ +#if USE_LV_ANIMATION + lv_anim_del(obj, NULL); +#endif + + /*Recursively delete the children*/ + lv_obj_t * i; + lv_obj_t * i_next; + i = lv_ll_get_head(&(obj->child_ll)); + while(i != NULL) { + /*Get the next object before delete this*/ + i_next = lv_ll_get_next(&(obj->child_ll), i); + + /*Call the recursive del to the child too*/ + delete_children(i); + + /*Set i to the next node*/ + i = i_next; + } + + /*Remove the object from parent's children list*/ + lv_obj_t * par = lv_obj_get_parent(obj); + if(par == NULL) { /*It is a screen*/ + lv_ll_rem(&LV_GC_ROOT(_lv_scr_ll), obj); + } else { + lv_ll_rem(&(par->child_ll), obj); + } + + /* Reset all input devices if + * the currently pressed object is deleted*/ + lv_indev_t * indev = lv_indev_next(NULL); + while(indev) { + if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) { + lv_indev_reset(indev); + } + indev = lv_indev_next(indev); + } + + /* All children deleted. + * Now clean up the object specific data*/ + obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL); + + /*Delete the base objects*/ + if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr); + lv_mem_free(obj); /*Free the object itself*/ + + /*Send a signal to the parent to notify it about the child delete*/ + if(par != NULL) { + par->signal_func(par, LV_SIGNAL_CHILD_CHG, NULL); + } + + return LV_RES_INV; +} + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t * obj) +{ + lv_obj_t * child = lv_obj_get_child(obj, NULL); + lv_obj_t * child_next; + while(child) { + /* Read the next child before deleting the current + * because the next couldn't be read from a deleted (invalid) node*/ + child_next = lv_obj_get_child(obj, child); + lv_obj_del(child); + child = child_next; + } +} + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj) +{ + if(lv_obj_get_hidden(obj)) return; + + /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/ + lv_obj_t * obj_scr = lv_obj_get_screen(obj); + if(obj_scr == lv_scr_act() || + obj_scr == lv_layer_top() || + obj_scr == lv_layer_sys()) { + /*Truncate recursively to the parents*/ + lv_area_t area_trunc; + lv_obj_t * par = lv_obj_get_parent(obj); + bool union_ok = true; + /*Start with the original coordinates*/ + lv_coord_t ext_size = obj->ext_size; + lv_area_copy(&area_trunc, &obj->coords); + area_trunc.x1 -= ext_size; + area_trunc.y1 -= ext_size; + area_trunc.x2 += ext_size; + area_trunc.y2 += ext_size; + + /*Check through all parents*/ + while(par != NULL) { + union_ok = lv_area_intersect(&area_trunc, &area_trunc, &par->coords); + if(union_ok == false) break; /*If no common parts with parent break;*/ + if(lv_obj_get_hidden(par)) return; /*If the parent is hidden then the child is hidden and won't be drawn*/ + + par = lv_obj_get_parent(par); + } + + if(union_ok != false) lv_inv_area(&area_trunc); + } +} + + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr) +{ + LV_GC_ROOT(_lv_act_scr) = scr; + + lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr)); +} + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) +{ + if(obj->par == NULL) { + LV_LOG_WARN("Can't set the parent of a screen"); + return; + } + + if(parent == NULL) { + LV_LOG_WARN("Can't set parent == NULL to an object"); + return; + } + + + lv_obj_invalidate(obj); + + lv_point_t old_pos; + old_pos.x = lv_obj_get_x(obj); + old_pos.y = lv_obj_get_y(obj); + + lv_obj_t * old_par = obj->par; + + lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj); + obj->par = parent; + lv_obj_set_pos(obj, old_pos.x, old_pos.y); + + /*Notify the original parent because one of its children is lost*/ + old_par->signal_func(old_par, LV_SIGNAL_CHILD_CHG, NULL); + + /*Notify the new parent about the child*/ + parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, obj); + + lv_obj_invalidate(obj); +} + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) +{ + /*Convert x and y to absolute coordinates*/ + lv_obj_t * par = obj->par; + x = x + par->coords.x1; + y = y + par->coords.y1; + + /*Calculate and set the movement*/ + lv_point_t diff; + diff.x = x - obj->coords.x1; + diff.y = y - obj->coords.y1; + + /* Do nothing if the position is not changed */ + /* It is very important else recursive positioning can + * occur without position change*/ + if(diff.x == 0 && diff.y == 0) return; + + /*Invalidate the original area*/ + lv_obj_invalidate(obj); + + /*Save the original coordinates*/ + lv_area_t ori; + lv_obj_get_coords(obj, &ori); + + obj->coords.x1 += diff.x; + obj->coords.y1 += diff.y; + obj->coords.x2 += diff.x; + obj->coords.y2 += diff.y; + + refresh_children_position(obj, diff.x, diff.y); + + /*Inform the object about its new coordinates*/ + obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori); + + /*Send a signal to the parent too*/ + par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + + /*Invalidate the new area*/ + lv_obj_invalidate(obj); +} + + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x) +{ + lv_obj_set_pos(obj, x, lv_obj_get_y(obj)); +} + + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y) +{ + lv_obj_set_pos(obj, lv_obj_get_x(obj), y); +} + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) +{ + + /* Do nothing if the size is not changed */ + /* It is very important else recursive resizing can + * occur without size change*/ + if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) { + return; + } + + /*Invalidate the original area*/ + lv_obj_invalidate(obj); + + /*Save the original coordinates*/ + lv_area_t ori; + lv_obj_get_coords(obj, &ori); + + //Set the length and height + obj->coords.x2 = obj->coords.x1 + w - 1; + obj->coords.y2 = obj->coords.y1 + h - 1; + + + /*Send a signal to the object with its new coordinates*/ + obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori); + + /*Send a signal to the parent too*/ + lv_obj_t * par = lv_obj_get_parent(obj); + if(par != NULL) par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + + /*Invalidate the new area*/ + lv_obj_invalidate(obj); + + /*Automatically realign the object if required*/ +#if LV_OBJ_REALIGN + if(obj->realign.auto_realign) lv_obj_realign(obj); +#endif +} + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w) +{ + lv_obj_set_size(obj, w, lv_obj_get_height(obj)); +} + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h) +{ + lv_obj_set_size(obj, lv_obj_get_width(obj), h); +} + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod) +{ + lv_coord_t new_x = lv_obj_get_x(obj); + lv_coord_t new_y = lv_obj_get_y(obj); + + if(base == NULL) { + base = lv_obj_get_parent(obj); + } + + switch(align) { + case LV_ALIGN_CENTER: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_IN_TOP_LEFT: + new_x = 0; + new_y = 0; + break; + case LV_ALIGN_IN_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = 0; + break; + + case LV_ALIGN_IN_TOP_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = 0; + break; + + case LV_ALIGN_IN_BOTTOM_LEFT: + new_x = 0; + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + case LV_ALIGN_IN_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_IN_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_IN_LEFT_MID: + new_x = 0; + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_IN_RIGHT_MID: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_TOP_LEFT: + new_x = 0; + new_y = -lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_TOP_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_BOTTOM_LEFT: + new_x = 0; + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base); + break; + + case LV_ALIGN_OUT_LEFT_TOP: + new_x = - lv_obj_get_width(obj); + new_y = 0; + break; + + case LV_ALIGN_OUT_LEFT_MID: + new_x = - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_LEFT_BOTTOM: + new_x = - lv_obj_get_width(obj); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + + case LV_ALIGN_OUT_RIGHT_TOP: + new_x = lv_obj_get_width(base); + new_y = 0; + break; + + case LV_ALIGN_OUT_RIGHT_MID: + new_x = lv_obj_get_width(base); + new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; + break; + + case LV_ALIGN_OUT_RIGHT_BOTTOM: + new_x = lv_obj_get_width(base); + new_y = lv_obj_get_height(base) - lv_obj_get_height(obj); + break; + } + + /*Bring together the coordination system of base and obj*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_coord_t base_abs_x = base->coords.x1; + lv_coord_t base_abs_y = base->coords.y1; + lv_coord_t par_abs_x = par->coords.x1; + lv_coord_t par_abs_y = par->coords.y1; + new_x += x_mod + base_abs_x; + new_y += y_mod + base_abs_y; + new_x -= par_abs_x; + new_y -= par_abs_y; + + lv_obj_set_pos(obj, new_x, new_y); + +#if LV_OBJ_REALIGN + /*Save the last align parameters to use them in `lv_obj_realign`*/ + obj->realign.align = align; + obj->realign.xofs = x_mod; + obj->realign.yofs = y_mod; + obj->realign.base = base; + obj->realign.origo_align = 0; +#endif +} + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod) +{ + lv_coord_t new_x = lv_obj_get_x(obj); + lv_coord_t new_y = lv_obj_get_y(obj); + + lv_coord_t obj_w_half = lv_obj_get_width(obj) / 2; + lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2; + + if(base == NULL) { + base = lv_obj_get_parent(obj); + } + + switch(align) { + case LV_ALIGN_CENTER: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_IN_TOP_LEFT: + new_x = -obj_w_half; + new_y = -obj_h_half; + break; + case LV_ALIGN_IN_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_IN_TOP_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_IN_BOTTOM_LEFT: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + case LV_ALIGN_IN_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_IN_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_IN_LEFT_MID: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_IN_RIGHT_MID: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_LEFT: + new_x = -obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_TOP_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_LEFT: + new_x = -obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_MID: + new_x = lv_obj_get_width(base) / 2 - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_BOTTOM_RIGHT: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_TOP: + new_x = - obj_w_half ; + new_y = - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_MID: + new_x = - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_LEFT_BOTTOM: + new_x = - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_TOP: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = -obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_MID: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) / 2 - obj_h_half; + break; + + case LV_ALIGN_OUT_RIGHT_BOTTOM: + new_x = lv_obj_get_width(base) - obj_w_half; + new_y = lv_obj_get_height(base) - obj_h_half; + break; + } + + /*Bring together the coordination system of base and obj*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_coord_t base_abs_x = base->coords.x1; + lv_coord_t base_abs_y = base->coords.y1; + lv_coord_t par_abs_x = par->coords.x1; + lv_coord_t par_abs_y = par->coords.y1; + new_x += x_mod + base_abs_x; + new_y += y_mod + base_abs_y; + new_x -= par_abs_x; + new_y -= par_abs_y; + + lv_obj_set_pos(obj, new_x, new_y); + +#if LV_OBJ_REALIGN + /*Save the last align parameters to use them in `lv_obj_realign`*/ + obj->realign.align = align; + obj->realign.xofs = x_mod; + obj->realign.yofs = y_mod; + obj->realign.base = base; + obj->realign.origo_align = 1; +#endif +} + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj) +{ +#if LV_OBJ_REALIGN + if(obj->realign.origo_align) lv_obj_align_origo(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); + else lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); +#else + (void) obj; + LV_LOG_WARN("lv_obj_realaign: no effect because LV_OBJ_REALIGN = 0"); +#endif +} + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en) +{ +#if LV_OBJ_REALIGN + obj->realign.auto_realign = en ? 1 : 0; +#else + (void) obj; + (void) en; + LV_LOG_WARN("lv_obj_set_auto_realign: no effect because LV_OBJ_REALIGN = 0"); +#endif +} + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style) +{ + obj->style_p = style; + + /*Send a signal about style change to every children with NULL style*/ + refresh_children_style(obj); + + /*Notify the object about the style change too*/ + lv_obj_refresh_style(obj); +} + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj) +{ + lv_obj_invalidate(obj); + obj->signal_func(obj, LV_SIGNAL_STYLE_CHG, NULL); + lv_obj_invalidate(obj); + +} + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style) +{ + lv_obj_t * i; + LL_READ(LV_GC_ROOT(_lv_scr_ll), i) { + if(i->style_p == style || style == NULL) { + lv_obj_refresh_style(i); + } + + report_style_mod_core(style, i); + } +} + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en) +{ + if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ + + obj->hidden = en == false ? 0 : 1; + + if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ + + lv_obj_t * par = lv_obj_get_parent(obj); + par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj); + +} + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en) +{ + obj->click = (en == true ? 1 : 0); +} + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en) +{ + obj->top = (en == true ? 1 : 0); +} + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en) +{ + if(en == true) lv_obj_set_click(obj, true); /*Drag is useless without enabled clicking*/ + obj->drag = (en == true ? 1 : 0); +} + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en) +{ + obj->drag_throw = (en == true ? 1 : 0); +} + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en) +{ + obj->drag_parent = (en == true ? 1 : 0); +} + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en) +{ + obj->opa_scale_en = en ? 1 : 0; +} + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale) +{ + obj->opa_scale = opa_scale; + lv_obj_invalidate(obj); +} + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot) +{ + obj->protect |= prot; +} + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot) +{ + prot = (~prot) & 0xFF; + obj->protect &= prot; +} + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp) +{ + obj->signal_func = fp; +} + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp) +{ + obj->design_func = fp; +} + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return Normal pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size) +{ + obj->ext_attr = lv_mem_realloc(obj->ext_attr, ext_size); + + return (void *)obj->ext_attr; +} + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj) +{ + obj->ext_size = 0; + obj->signal_func(obj, LV_SIGNAL_REFR_EXT_SIZE, NULL); + + lv_obj_invalidate(obj); +} + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num) +{ + obj->free_num = free_num; +} +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p) +{ + obj->free_ptr = free_p; +} +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb)(lv_obj_t *)) +{ + lv_obj_t * par = lv_obj_get_parent(obj); + + /*Get the direction*/ + bool out = (type & LV_ANIM_DIR_MASK) == LV_ANIM_IN ? false : true; + type = type & (~LV_ANIM_DIR_MASK); + + lv_anim_t a; + a.var = obj; + a.time = time; + a.act_time = (int32_t) - delay; + a.end_cb = (void(*)(void *))cb; + a.path = lv_anim_path_linear; + a.playback_pause = 0; + a.repeat_pause = 0; + a.playback = 0; + a.repeat = 0; + + /*Init to ANIM_IN*/ + switch(type) { + case LV_ANIM_FLOAT_LEFT: + a.fp = (void(*)(void *, int32_t))lv_obj_set_x; + a.start = -lv_obj_get_width(obj); + a.end = lv_obj_get_x(obj); + break; + case LV_ANIM_FLOAT_RIGHT: + a.fp = (void(*)(void *, int32_t))lv_obj_set_x; + a.start = lv_obj_get_width(par); + a.end = lv_obj_get_x(obj); + break; + case LV_ANIM_FLOAT_TOP: + a.fp = (void(*)(void *, int32_t))lv_obj_set_y; + a.start = -lv_obj_get_height(obj); + a.end = lv_obj_get_y(obj); + break; + case LV_ANIM_FLOAT_BOTTOM: + a.fp = (void(*)(void *, int32_t))lv_obj_set_y; + a.start = lv_obj_get_height(par); + a.end = lv_obj_get_y(obj); + break; + case LV_ANIM_GROW_H: + a.fp = (void(*)(void *, int32_t))lv_obj_set_width; + a.start = 0; + a.end = lv_obj_get_width(obj); + break; + case LV_ANIM_GROW_V: + a.fp = (void(*)(void *, int32_t))lv_obj_set_height; + a.start = 0; + a.end = lv_obj_get_height(obj); + break; + case LV_ANIM_NONE: + a.fp = NULL; + a.start = 0; + a.end = 0; + break; + default: + break; + } + + /*Swap start and end in case of ANIM OUT*/ + if(out != false) { + int32_t tmp = a.start; + a.start = a.end; + a.end = tmp; + } + + lv_anim_create(&a); +} + +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void) +{ + return LV_GC_ROOT(_lv_act_scr); +} + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void) +{ + return LV_GC_ROOT(_lv_top_layer); +} + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void) +{ + return LV_GC_ROOT(_lv_sys_layer); +} + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj) +{ + const lv_obj_t * par = obj; + const lv_obj_t * act_p; + + do { + act_p = par; + par = lv_obj_get_parent(act_p); + } while(par != NULL); + + return (lv_obj_t *)act_p; +} + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj) +{ + return obj->par; +} + +/** + * Iterate through the children of an object (start from the "youngest") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child) +{ + lv_obj_t * result = NULL; + + if(child == NULL) { + result = lv_ll_get_head(&obj->child_ll); + } else { + result = lv_ll_get_next(&obj->child_ll, child); + } + + return result; +} + +/** + * Iterate through the children of an object (start from the "oldest") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child) +{ + lv_obj_t * result = NULL; + + if(child == NULL) { + result = lv_ll_get_tail(&obj->child_ll); + } else { + result = lv_ll_get_prev(&obj->child_ll, child); + } + + return result; +} + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj) +{ + lv_obj_t * i; + uint16_t cnt = 0; + + LL_READ(obj->child_ll, i) cnt++; + + return cnt; +} + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p) +{ + lv_area_copy(cords_p, &obj->coords); +} + + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj) +{ + lv_coord_t rel_x; + lv_obj_t * parent = lv_obj_get_parent(obj); + rel_x = obj->coords.x1 - parent->coords.x1; + + return rel_x; +} + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj) +{ + lv_coord_t rel_y; + lv_obj_t * parent = lv_obj_get_parent(obj); + rel_y = obj->coords.y1 - parent->coords.y1; + + return rel_y; +} + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj) +{ + return lv_area_get_width(&obj->coords); +} + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj) +{ + return lv_area_get_height(&obj->coords); +} + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj) +{ + return obj->ext_size; +} + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj) +{ +#if LV_OBJ_REALIGN + return obj->realign.auto_realign ? true : false; +#else + (void) obj; + return false; +#endif +} + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj) +{ + lv_style_t * style_act = obj->style_p; + if(style_act == NULL) { + lv_obj_t * par = obj->par; + + while(par) { + if(par->style_p) { + if(par->style_p->glass == 0) { +#if USE_LV_GROUP == 0 + style_act = par->style_p; +#else + /*Is a parent is focused then use then focused style*/ + lv_group_t * g = lv_obj_get_group(par); + if(lv_group_get_focused(g) == par) { + style_act = lv_group_mod_style(g, par->style_p); + } else { + style_act = par->style_p; + } +#endif + break; + } + } + par = par->par; + } + } +#if USE_LV_GROUP + if(obj->group_p) { + if(lv_group_get_focused(obj->group_p) == obj) { + style_act = lv_group_mod_style(obj->group_p, style_act); + } + } +#endif + + if(style_act == NULL) style_act = &lv_style_plain; + + return style_act; +} + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj) +{ + return obj->hidden == 0 ? false : true; +} + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj) +{ + return obj->click == 0 ? false : true; +} + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feture is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj) +{ + return obj->top == 0 ? false : true; +} + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj) +{ + return obj->drag == 0 ? false : true; +} + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj) +{ + return obj->drag_throw == 0 ? false : true; +} + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj) +{ + return obj->drag_parent == 0 ? false : true; +} + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj) +{ + return obj->opa_scale_en == 0 ? false : true; +} + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj) +{ + const lv_obj_t * parent = obj; + + while(parent) { + if(parent->opa_scale_en) return parent->opa_scale; + parent = lv_obj_get_parent(parent); + } + + return LV_OPA_COVER; +} + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj) +{ + return obj->protect ; +} + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot) +{ + return (obj->protect & prot) == 0 ? false : true ; +} + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj) +{ + return obj->signal_func; +} + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj) +{ + return obj->design_func; +} + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj) +{ + return obj->ext_attr; +} + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf) +{ + lv_obj_type_t tmp; + + memset(buf, 0, sizeof(lv_obj_type_t)); + memset(&tmp, 0, sizeof(lv_obj_type_t)); + + obj->signal_func(obj, LV_SIGNAL_GET_TYPE, &tmp); + + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(tmp.type[cnt] == NULL) break; + } + + + /*Swap the order. The real type comes first*/ + uint8_t i; + for(i = 0; i < cnt; i++) { + buf->type[i] = tmp.type[cnt - 1 - i]; + } +} + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj) +{ + return obj->free_num; +} +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj) +{ + return obj->free_ptr; +} +#endif + + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj) +{ + return obj->group_p; +} + +/** + * Tell whether the ohe object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj) +{ + if(obj->group_p) { + if(lv_group_get_focused(obj->group_p) == obj) return true; + } + + return false; +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the base objects. + * @param obj pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * @param return true/false, depends on 'mode' + */ +static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + + /* Because of the radius it is not sure the area is covered + * Check the areas where there is no radius*/ + lv_style_t * style = lv_obj_get_style(obj); + if(style->body.empty != 0) return false; + + uint16_t r = style->body.radius; + + if(r == LV_RADIUS_CIRCLE) return false; + + lv_area_t area_tmp; + + /*Check horizontally without radius*/ + lv_obj_get_coords(obj, &area_tmp); + area_tmp.x1 += r; + area_tmp.x2 -= r; + if(lv_area_is_in(mask_p, &area_tmp) == false) return false; + + /*Check vertically without radius*/ + lv_obj_get_coords(obj, &area_tmp); + area_tmp.y1 += r; + area_tmp.y2 -= r; + if(lv_area_is_in(mask_p, &area_tmp) == false) return false; + + } else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_style_t * style = lv_obj_get_style(obj); + lv_draw_rect(&obj->coords, mask_p, style, lv_obj_get_opa_scale(obj)); + } + + return true; +} + +/** + * Signal function of the basic object + * @param obj pointer to an object + * @param sign signal type + * @param param parameter for the signal (depends on signal type) + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) +{ + (void)param; + + lv_res_t res = LV_RES_OK; + + lv_style_t * style = lv_obj_get_style(obj); + + lv_indev_t *indev_act = lv_indev_get_act(); + + if(sign > _LV_SIGNAL_FEEDBACK_SECTION_START && sign < _LV_SIGNAL_FEEDBACK_SECTION_END) { + if(indev_act != NULL && indev_act->feedback != NULL) + indev_act->feedback(indev_act, sign); + } + + if(sign == LV_SIGNAL_CHILD_CHG) { + /*Return 'invalid' if the child change signal is not enabled*/ + if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV; + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + if(style->body.shadow.width > obj->ext_size) obj->ext_size = style->body.shadow.width; + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_refresh_ext_size(obj); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + buf->type[0] = "lv_obj"; + } + + return res; +} + +/** + * Reposition the children of an object. (Called recursively) + * @param obj pointer to an object which children will be repositioned + * @param x_diff x coordinate shift + * @param y_diff y coordinate shift + */ +static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + i->coords.x1 += x_diff; + i->coords.y1 += y_diff; + i->coords.x2 += x_diff; + i->coords.y2 += y_diff; + + refresh_children_position(i, x_diff, y_diff); + } +} + +/** + * Refresh the style of all children of an object. (Called recursively) + * @param style_p refresh objects only with this style. + * @param obj pointer to an object + */ +static void report_style_mod_core(void * style_p, lv_obj_t * obj) +{ + lv_obj_t * i; + LL_READ(obj->child_ll, i) { + if(i->style_p == style_p || style_p == NULL) { + refresh_children_style(i); + lv_obj_refresh_style(i); + } + + report_style_mod_core(style_p, i); + } +} + +/** + * Recursively refresh the style of the children. Go deeper until a not NULL style is found + * because the NULL styles are inherited from the parent + * @param obj pointer to an object + */ +static void refresh_children_style(lv_obj_t * obj) +{ + lv_obj_t * child = lv_obj_get_child(obj, NULL); + while(child != NULL) { + if(child->style_p == NULL) { + refresh_children_style(child); /*Check children too*/ + lv_obj_refresh_style(child); /*Notify the child about the style change*/ + } else if(child->style_p->glass) { + /*Children with 'glass' parent might be effected if their style == NULL*/ + refresh_children_style(child); + } + child = lv_obj_get_child(obj, child); + } +} + +/** + * Called by 'lv_obj_del' to delete the children objects + * @param obj pointer to an object (all of its children will be deleted) + */ +static void delete_children(lv_obj_t * obj) +{ + lv_obj_t * i; + lv_obj_t * i_next; + i = lv_ll_get_head(&(obj->child_ll)); + + /*Remove from the group; remove before transversing children so that + * the object still has access to all children during the + * LV_SIGNAL_DEFOCUS call*/ +#if USE_LV_GROUP + if(obj->group_p != NULL) lv_group_remove_obj(obj); +#endif + + while(i != NULL) { + /*Get the next object before delete this*/ + i_next = lv_ll_get_next(&(obj->child_ll), i); + + /*Call the recursive del to the child too*/ + delete_children(i); + + /*Set i to the next node*/ + i = i_next; + } + + /*Remove the animations from this object*/ +#if USE_LV_ANIMATION + lv_anim_del(obj, NULL); +#endif + + + /* Reset the input devices if + * the currently pressed object is deleted*/ + lv_indev_t * indev = lv_indev_next(NULL); + while(indev) { + if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) { + lv_indev_reset(indev); + } + indev = lv_indev_next(indev); + } + + /*Remove the object from parent's children list*/ + lv_obj_t * par = lv_obj_get_parent(obj); + lv_ll_rem(&(par->child_ll), obj); + + /* Clean up the object specific data*/ + obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL); + + /*Delete the base objects*/ + if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr); + lv_mem_free(obj); /*Free the object itself*/ + +} diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.h new file mode 100644 index 0000000..0ebd916 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_obj.h @@ -0,0 +1,840 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_style.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_ll.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/*Error check of lv_conf.h*/ +#if LV_HOR_RES == 0 || LV_VER_RES == 0 +#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0" +#endif + +#if LV_ANTIALIAS > 1 +#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1" +#endif + +#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0 +#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled" +#endif + +#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES +#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)" +#endif + +#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0 +#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)" +#endif + + +#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/ + +#define LV_MAX_ANCESTOR_NUM 8 + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +enum +{ + LV_DESIGN_DRAW_MAIN, + LV_DESIGN_DRAW_POST, + LV_DESIGN_COVER_CHK, +}; +typedef uint8_t lv_design_mode_t; + +typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); + +enum +{ + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +enum +{ + /*General signals*/ + LV_SIGNAL_CLEANUP, + LV_SIGNAL_CHILD_CHG, + LV_SIGNAL_CORD_CHG, + LV_SIGNAL_STYLE_CHG, + LV_SIGNAL_REFR_EXT_SIZE, + LV_SIGNAL_LANG_CHG, + LV_SIGNAL_GET_TYPE, + + _LV_SIGNAL_FEEDBACK_SECTION_START, + /*Input device related*/ + LV_SIGNAL_PRESSED, + LV_SIGNAL_PRESSING, + LV_SIGNAL_PRESS_LOST, + LV_SIGNAL_RELEASED, + LV_SIGNAL_LONG_PRESS, + LV_SIGNAL_LONG_PRESS_REP, + LV_SIGNAL_DRAG_BEGIN, + LV_SIGNAL_DRAG_END, + + /*Group related*/ + LV_SIGNAL_FOCUS, + LV_SIGNAL_DEFOCUS, + LV_SIGNAL_CONTROLL, + _LV_SIGNAL_FEEDBACK_SECTION_END, + LV_SIGNAL_GET_EDITABLE, +}; +typedef uint8_t lv_signal_t; + +typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param); + +enum +{ + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + +#if LV_OBJ_REALIGN +typedef struct { + const struct _lv_obj_t * base; + lv_coord_t xofs; + lv_coord_t yofs; + lv_align_t align; + uint8_t auto_realign :1; + uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/ +}lv_reailgn_t; +#endif + + +typedef struct _lv_obj_t +{ + struct _lv_obj_t * par; /*Pointer to the parent object*/ + lv_ll_t child_ll; /*Linked list to store the children objects*/ + + lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/ + + lv_signal_func_t signal_func; /*Object type specific signal function*/ + lv_design_func_t design_func; /*Object type specific design function*/ + + void * ext_attr; /*Object type specific extended data*/ + lv_style_t * style_p; /*Pointer to the object's style*/ + +#if LV_OBJ_FREE_PTR != 0 + void * free_ptr; /*Application specific pointer (set it freely)*/ +#endif + +#if USE_LV_GROUP != 0 + void * group_p; /*Pointer to the group of the object*/ +#endif + /*Attributes and states*/ + uint8_t click :1; /*1: Can be pressed by an input device*/ + uint8_t drag :1; /*1: Enable the dragging*/ + uint8_t drag_throw :1; /*1: Enable throwing with drag*/ + uint8_t drag_parent :1; /*1: Parent will be dragged instead*/ + uint8_t hidden :1; /*1: Object is hidden*/ + uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/ + uint8_t opa_scale_en :1; /*1: opa_scale is set*/ + uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/ + lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/ + + lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/ +#if LV_OBJ_REALIGN + lv_reailgn_t realign; +#endif + +#ifdef LV_OBJ_FREE_NUM_TYPE + LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/ +#endif +} lv_obj_t; + +typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj); + +/*Protect some attributes (max. 8 bit)*/ +enum +{ + LV_PROTECT_NONE = 0x00, + LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/ + LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/ + LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/ + LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/ + LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/ + LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/ +}; +typedef uint8_t lv_protect_t; + + +/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/ +typedef struct { + const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */ +} lv_obj_type_t; + +enum +{ + LV_ANIM_NONE = 0, + LV_ANIM_FLOAT_TOP, /*Float from/to the top*/ + LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/ + LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/ + LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/ + LV_ANIM_GROW_H, /*Grow/shrink horizontally*/ + LV_ANIM_GROW_V, /*Grow/shrink vertically*/ +}; +typedef uint8_t lv_anim_builtin_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void); + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy); + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj); + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t *obj); + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr); + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent); + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj); + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en); + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style); + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj); + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style); + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en); + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en); + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en); + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en); + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); + +/** + * Set editable parameter Used by groups and keyboard/encoder control. + * Editable object has something inside to choose (the elements of a list) + * @param obj pointer to an object + * @param en true: enable editing + */ +//void lv_obj_set_editable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale); + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp); + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp); + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size); + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p); +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *)); +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void); + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void); + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj); + +/** + * Iterate through the children of an object (start from the "youngest, lastly created") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Iterate through the children of an object (start from the "oldest", firstly created) + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj); + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p); + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj); + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj); + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj); + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj); + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj); + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj); + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj); + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feature is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj); + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj); + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj); + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj); + + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj); + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj); + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj); + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot); + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj); + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj); + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj); + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj); +#endif + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj); + + +/** + * Tell whether the object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj); + +#endif + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.c new file mode 100644 index 0000000..1087304 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.c @@ -0,0 +1,614 @@ +/** + * @file lv_refr.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_refr.h" +#include "lv_vdb.h" +#include "../lv_hal/lv_hal_tick.h" +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_mem.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_INV_FIFO_SIZE +#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */ +#endif + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_area_t area; + uint8_t joined; +} lv_join_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_refr_task(void * param); +static void lv_refr_join_area(void); +static void lv_refr_areas(void); +#if LV_VDB_SIZE == 0 +static void lv_refr_area_no_vdb(const lv_area_t * area_p); +#else +static void lv_refr_area_with_vdb(const lv_area_t * area_p); +static void lv_refr_area_part_vdb(const lv_area_t * area_p); +#endif +static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj); +static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p); +static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_join_t inv_buf[LV_INV_FIFO_SIZE]; +static uint16_t inv_buf_p; +static void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/ +static void (*round_cb)(lv_area_t *); /*If set then called to modify invalidated areas for special display controllers*/ +static uint32_t px_num; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void) +{ + inv_buf_p = 0; + memset(inv_buf, 0, sizeof(inv_buf)); + + lv_task_t * task; + task = lv_task_create(lv_refr_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL); + lv_task_ready(task); /*Be sure the screen will be refreshed immediately on start up*/ +} + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void) +{ + lv_refr_task(NULL); +} + + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p) +{ + /*Clear the invalidate buffer if the parameter is NULL*/ + if(area_p == NULL) { + inv_buf_p = 0; + return; + } + + lv_area_t scr_area; + scr_area.x1 = 0; + scr_area.y1 = 0; + scr_area.x2 = LV_HOR_RES - 1; + scr_area.y2 = LV_VER_RES - 1; + + lv_area_t com_area; + bool suc; + + suc = lv_area_intersect(&com_area, area_p, &scr_area); + + /*The area is truncated to the screen*/ + if(suc != false) { + if(round_cb) round_cb(&com_area); + + /*Save only if this area is not in one of the saved areas*/ + uint16_t i; + for(i = 0; i < inv_buf_p; i++) { + if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return; + } + + /*Save the area*/ + if(inv_buf_p < LV_INV_FIFO_SIZE) { + lv_area_copy(&inv_buf[inv_buf_p].area, &com_area); + } else {/*If no place for the area add the screen*/ + inv_buf_p = 0; + lv_area_copy(&inv_buf[inv_buf_p].area, &scr_area); + } + inv_buf_p ++; + } +} + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + * time_ms: refresh time in [ms] + * px_num: not the drawn pixels but the number of affected pixels of the screen + * (more pixels are drawn because of overlapping objects) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)) +{ + monitor_cb = cb; +} + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t *)) +{ + round_cb = cb; +} + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void) +{ + return inv_buf_p; +} + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num) +{ + if(inv_buf_p < num) inv_buf_p = 0; + else inv_buf_p -= num; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Called periodically to handle the refreshing + * @param param unused + */ +static void lv_refr_task(void * param) +{ + (void)param; + + LV_LOG_TRACE("display refresh task started"); + + uint32_t start = lv_tick_get(); + + if(lv_disp_get_active() == NULL) { + LV_LOG_TRACE("No display is registered"); + return; + } + + lv_refr_join_area(); + + lv_refr_areas(); + + /*If refresh happened ...*/ + if(inv_buf_p != 0) { + + /*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/ +#if LV_VDB_TRUE_DOUBLE_BUFFERED + lv_vdb_t * vdb_p = lv_vdb_get(); + vdb_p->area.x1 = 0; + vdb_p->area.x2 = LV_HOR_RES-1; + vdb_p->area.y1 = 0; + vdb_p->area.y2 = LV_VER_RES - 1; + + /*Flush the content of the VDB*/ + lv_vdb_flush(); + + /* With true double buffering the flushing should be only the address change of the current frame buffer + * Wait until the address change is ready and copy the active content to the other frame buffer (new active VDB) + * The changes will be written to the new VDB.*/ + lv_vdb_t * vdb_act = lv_vdb_get_active(); + lv_vdb_t * vdb_ina = lv_vdb_get_inactive(); + + uint8_t * buf_act = (uint8_t *) vdb_act->buf; + uint8_t * buf_ina = (uint8_t *) vdb_ina->buf; + + uint16_t a; + for(a = 0; a < inv_buf_p; a++) { + if(inv_buf[a].joined == 0) { + lv_coord_t y; + uint32_t start_offs = ((LV_HOR_RES * inv_buf[a].area.y1 + inv_buf[a].area.x1) * LV_VDB_PX_BPP) >> 3; + uint32_t line_length = (lv_area_get_width(&inv_buf[a].area) * LV_VDB_PX_BPP) >> 3; + + for(y = inv_buf[a].area.y1; y <= inv_buf[a].area.y2; y++) { + memcpy(buf_act + start_offs, buf_ina + start_offs, line_length); + start_offs += (LV_HOR_RES * LV_VDB_PX_BPP) >> 3; + } + } + } + +#endif + + /*Clean up*/ + memset(inv_buf, 0, sizeof(inv_buf)); + inv_buf_p = 0; + + /*Call monitor cb if present*/ + if(monitor_cb != NULL) { + monitor_cb(lv_tick_elaps(start), px_num); + } + } + + LV_LOG_TRACE("display refresh task finished"); +} + + +/** + * Join the areas which has got common parts + */ +static void lv_refr_join_area(void) +{ + uint32_t join_from; + uint32_t join_in; + lv_area_t joined_area; + for(join_in = 0; join_in < inv_buf_p; join_in++) { + if(inv_buf[join_in].joined != 0) continue; + + /*Check all areas to join them in 'join_in'*/ + for(join_from = 0; join_from < inv_buf_p; join_from++) { + /*Handle only unjoined areas and ignore itself*/ + if(inv_buf[join_from].joined != 0 || join_in == join_from) { + continue; + } + + /*Check if the areas are on each other*/ + if(lv_area_is_on(&inv_buf[join_in].area, + &inv_buf[join_from].area) == false) { + continue; + } + + lv_area_join(&joined_area, &inv_buf[join_in].area, + &inv_buf[join_from].area); + + /*Join two area only if the joined area size is smaller*/ + if(lv_area_get_size(&joined_area) < + (lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) { + lv_area_copy(&inv_buf[join_in].area, &joined_area); + + /*Mark 'join_form' is joined into 'join_in'*/ + inv_buf[join_from].joined = 1; + } + } + } +} + +/** + * Refresh the joined areas + */ +static void lv_refr_areas(void) +{ + px_num = 0; + uint32_t i; + + for(i = 0; i < inv_buf_p; i++) { + /*Refresh the unjoined areas*/ + if(inv_buf[i].joined == 0) { + /*If there is no VDB do simple drawing*/ +#if LV_VDB_SIZE == 0 + lv_refr_area_no_vdb(&inv_buf[i].area); +#else + /*If VDB is used...*/ + lv_refr_area_with_vdb(&inv_buf[i].area); +#endif + if(monitor_cb != NULL) px_num += lv_area_get_size(&inv_buf[i].area); + } + } + +} + +#if LV_VDB_SIZE == 0 +/** + * Refresh an area if there is no Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_no_vdb(const lv_area_t * area_p) +{ + lv_obj_t * top_p; + + /*Get top object which is not covered by others*/ + top_p = lv_refr_get_top_obj(area_p, lv_scr_act()); + + /*Do the refreshing*/ + lv_refr_obj_and_children(top_p, area_p); + + /*Also refresh top and sys layer unconditionally*/ + lv_refr_obj_and_children(lv_layer_top(), area_p); + lv_refr_obj_and_children(lv_layer_sys(), area_p); +} + +#else + +/** + * Refresh an area if there is Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_with_vdb(const lv_area_t * area_p) +{ + +#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0 + /*Calculate the max row num*/ + lv_coord_t w = lv_area_get_width(area_p); + lv_coord_t h = lv_area_get_height(area_p); + lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2; + + int32_t max_row = (uint32_t) LV_VDB_SIZE / w; + + if(max_row > h) max_row = h; + + + /*Round down the lines of VDB if rounding is added*/ + if(round_cb) { + lv_area_t tmp; + tmp.x1 = 0; + tmp.x2 = 0; + tmp.y1 = 0; + + lv_coord_t y_tmp = max_row - 1; + do { + tmp.y2 = y_tmp; + round_cb(&tmp); + + /*If this height fits into `max_row` then fine*/ + if(lv_area_get_height(&tmp) <= max_row) break; + + /*Decrement the height of the area until it fits into `max_row` after rounding*/ + y_tmp --; + } while(y_tmp != 0); + + if(y_tmp == 0) { + LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to small VDB)"); + return; + } else { + max_row = tmp.y2 + 1; + } + } + + /*Always use the full row*/ + lv_coord_t row; + lv_coord_t row_last = 0; + for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) { + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Calc. the next y coordinates of VDB*/ + vdb_p->area.x1 = area_p->x1; + vdb_p->area.x2 = area_p->x2; + vdb_p->area.y1 = row; + vdb_p->area.y2 = row + max_row - 1; + if(vdb_p->area.y2 > y2) vdb_p->area.y2 = y2; + row_last = vdb_p->area.y2; + lv_refr_area_part_vdb(area_p); + } + + /*If the last y coordinates are not handled yet ...*/ + if(y2 != row_last) { + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Calc. the next y coordinates of VDB*/ + vdb_p->area.x1 = area_p->x1; + vdb_p->area.x2 = area_p->x2; + vdb_p->area.y1 = row; + vdb_p->area.y2 = y2; + + /*Refresh this part too*/ + lv_refr_area_part_vdb(area_p); + } +#else + lv_vdb_t * vdb_p = lv_vdb_get(); + vdb_p->area.x1 = 0; + vdb_p->area.x2 = LV_HOR_RES-1; + vdb_p->area.y1 = 0; + vdb_p->area.y2 = LV_VER_RES - 1; + lv_refr_area_part_vdb(area_p); +#endif +} + +/** + * Refresh a part of an area which is on the actual Virtual Display Buffer + * @param area_p pointer to an area to refresh + */ +static void lv_refr_area_part_vdb(const lv_area_t * area_p) +{ + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + lv_obj_t * top_p; + + /*Get the new mask from the original area and the act. VDB + It will be a part of 'area_p'*/ + lv_area_t start_mask; + lv_area_intersect(&start_mask, area_p, &vdb_p->area); + + /*Get the most top object which is not covered by others*/ + top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act()); + + /*Do the refreshing from the top object*/ + lv_refr_obj_and_children(top_p, &start_mask); + + /*Also refresh top and sys layer unconditionally*/ + lv_refr_obj_and_children(lv_layer_top(), &start_mask); + lv_refr_obj_and_children(lv_layer_sys(), &start_mask); + + /* In true double buffered mode flush only once when all areas were rendered. + * In normal mode flush after every area */ +#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0 + /*Flush the content of the VDB*/ + lv_vdb_flush(); +#endif +} + +#endif /*LV_VDB_SIZE == 0*/ + +/** + * Search the most top object which fully covers an area + * @param area_p pointer to an area + * @param obj the first object to start the searching (typically a screen) + * @return + */ +static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj) +{ + lv_obj_t * i; + lv_obj_t * found_p = NULL; + + /*If this object is fully cover the draw area check the children too */ + if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) { + LL_READ(obj->child_ll, i) { + found_p = lv_refr_get_top_obj(area_p, i); + + /*If a children is ok then break*/ + if(found_p != NULL) { + break; + } + } + + /*If no better children check this object*/ + if(found_p == NULL) { + lv_style_t * style = lv_obj_get_style(obj); + if(style->body.opa == LV_OPA_COVER && + obj->design_func(obj, area_p, LV_DESIGN_COVER_CHK) != false && + lv_obj_get_opa_scale(obj) == LV_OPA_COVER) { + found_p = obj; + } + } + } + + return found_p; +} + +/** + * Make the refreshing from an object. Draw all its children and the youngers too. + * @param top_p pointer to an objects. Start the drawing from it. + * @param mask_p pointer to an area, the objects will be drawn only here + */ +static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p) +{ + /* Normally always will be a top_obj (at least the screen) + * but in special cases (e.g. if the screen has alpha) it won't. + * In this case use the screen directly */ + if(top_p == NULL) top_p = lv_scr_act(); + + /*Refresh the top object and its children*/ + lv_refr_obj(top_p, mask_p); + + /*Draw the 'younger' sibling objects because they can be on top_obj */ + lv_obj_t * par; + lv_obj_t * i; + lv_obj_t * border_p = top_p; + + par = lv_obj_get_parent(top_p); + + /*Do until not reach the screen*/ + while(par != NULL) { + /*object before border_p has to be redrawn*/ + i = lv_ll_get_prev(&(par->child_ll), border_p); + + while(i != NULL) { + /*Refresh the objects*/ + lv_refr_obj(i, mask_p); + i = lv_ll_get_prev(&(par->child_ll), i); + } + + /*The new border will be there last parents, + *so the 'younger' brothers of parent will be refreshed*/ + border_p = par; + /*Go a level deeper*/ + par = lv_obj_get_parent(par); + } + + /*Call the post draw design function of the parents of the to object*/ + par = lv_obj_get_parent(top_p); + while(par != NULL) { + par->design_func(par, mask_p, LV_DESIGN_DRAW_POST); + par = lv_obj_get_parent(par); + } +} + +/** + * Refresh an object an all of its children. (Called recursively) + * @param obj pointer to an object to refresh + * @param mask_ori_p pointer to an area, the objects will be drawn only here + */ +static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) +{ + /*Do not refresh hidden objects*/ + if(obj->hidden != 0) return; + + bool union_ok; /* Store the return value of area_union */ + /* Truncate the original mask to the coordinates of the parent + * because the parent and its children are visible only here */ + lv_area_t obj_mask; + lv_area_t obj_ext_mask; + lv_area_t obj_area; + lv_coord_t ext_size = obj->ext_size; + lv_obj_get_coords(obj, &obj_area); + obj_area.x1 -= ext_size; + obj_area.y1 -= ext_size; + obj_area.x2 += ext_size; + obj_area.y2 += ext_size; + union_ok = lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area); + + /*Draw the parent and its children only if they ore on 'mask_parent'*/ + if(union_ok != false) { + + /* Redraw the object */ + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN); + //usleep(5 * 1000); /*DEBUG: Wait after every object draw to see the order of drawing*/ + + + /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/ + lv_obj_get_coords(obj, &obj_area); + union_ok = lv_area_intersect(&obj_mask, mask_ori_p, &obj_area); + if(union_ok != false) { + lv_area_t mask_child; /*Mask from obj and its child*/ + lv_obj_t * child_p; + lv_area_t child_area; + LL_READ_BACK(obj->child_ll, child_p) { + lv_obj_get_coords(child_p, &child_area); + ext_size = child_p->ext_size; + child_area.x1 -= ext_size; + child_area.y1 -= ext_size; + child_area.x2 += ext_size; + child_area.y2 += ext_size; + /* Get the union (common parts) of original mask (from obj) + * and its child */ + union_ok = lv_area_intersect(&mask_child, &obj_mask, &child_area); + + /*If the parent and the child has common area then refresh the child */ + if(union_ok) { + /*Refresh the next children*/ + lv_refr_obj(child_p, &mask_child); + } + } + } + + /* If all the children are redrawn make 'post draw' design */ + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST); + + } +} diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.h new file mode 100644 index 0000000..b93cb10 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_refr.h @@ -0,0 +1,94 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void); + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void); + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p); + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void); + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num); +/********************** + * STATIC FUNCTIONS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_REFR_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_style.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_style.c new file mode 100644 index 0000000..02fbcb2 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_style.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "../lv_misc/lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define STYLE_MIX_MAX 256 +#define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/ + +#define VAL_PROP(v1, v2, r) v1 + (((v2-v1) * r) >> STYLE_MIX_SHIFT) +#define STYLE_ATTR_MIX(attr, r) if(start->attr != end->attr) {res->attr = VAL_PROP(start->attr, end->attr, r);} else {res->attr = start->attr;} + + +/********************** + * TYPEDEFS + **********************/ +#if USE_LV_ANIMATION +typedef struct { + lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it will be modified too*/ + lv_style_t style_end; + lv_style_t * style_anim; + void (*end_cb)(void *); +} lv_style_anim_dsc_t; +#endif + +/********************** + * STATIC PROTOTYPES + **********************/ +#if USE_LV_ANIMATION +static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val); +static void style_animation_common_end_cb(void * ptr); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +lv_style_t lv_style_scr; +lv_style_t lv_style_transp; +lv_style_t lv_style_transp_fit; +lv_style_t lv_style_transp_tight; +lv_style_t lv_style_plain; +lv_style_t lv_style_plain_color; +lv_style_t lv_style_pretty; +lv_style_t lv_style_pretty_color; +lv_style_t lv_style_btn_rel; +lv_style_t lv_style_btn_pr; +lv_style_t lv_style_btn_tgl_rel; +lv_style_t lv_style_btn_tgl_pr; +lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init(void) +{ + /* Not White/Black/Gray colors are created by HSV model with + * HUE = 210*/ + + /*Screen style*/ + lv_style_scr.glass = 0; + lv_style_scr.body.opa = LV_OPA_COVER; + lv_style_scr.body.main_color = LV_COLOR_BLACK; + lv_style_scr.body.grad_color = LV_COLOR_BLACK; + lv_style_scr.body.radius = 0; + lv_style_scr.body.padding.ver = LV_DPI / 12; + lv_style_scr.body.padding.hor = LV_DPI / 12; + lv_style_scr.body.padding.inner = LV_DPI / 12; + + lv_style_scr.body.border.color = LV_COLOR_WHITE; + lv_style_scr.body.border.opa = LV_OPA_COVER; + lv_style_scr.body.border.width = 0; + lv_style_scr.body.border.part = LV_BORDER_FULL; + + lv_style_scr.body.shadow.color = LV_COLOR_GRAY; + lv_style_scr.body.shadow.type = LV_SHADOW_FULL; + lv_style_scr.body.shadow.width = 0; + + lv_style_scr.text.opa = LV_OPA_COVER; + lv_style_scr.text.color = LV_COLOR_HEX(0xFBFBFB); + lv_style_scr.text.font = LV_FONT_DEFAULT; + lv_style_scr.text.letter_space = 3; // Important + lv_style_scr.text.line_space = 2; + + lv_style_scr.image.opa = LV_OPA_COVER; + lv_style_scr.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_scr.image.intense = LV_OPA_TRANSP; + + lv_style_scr.line.opa = LV_OPA_COVER; + lv_style_scr.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_scr.line.width = 2; + lv_style_scr.line.rounded = 0; + + /*Plain style (by default near the same as the screen style)*/ + memcpy(&lv_style_plain, &lv_style_scr, sizeof(lv_style_t)); + + /*Plain color style*/ + memcpy(&lv_style_plain_color, &lv_style_plain, sizeof(lv_style_t)); + lv_style_plain_color.text.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.image.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.line.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0); + lv_style_plain_color.body.main_color = LV_COLOR_MAKE(0x55, 0x96, 0xd8); + lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color; + + /*Pretty style */ + memcpy(&lv_style_pretty, &lv_style_plain, sizeof(lv_style_t)); + lv_style_pretty.text.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20); + lv_style_pretty.body.main_color = LV_COLOR_WHITE; + lv_style_pretty.body.grad_color = LV_COLOR_SILVER; + lv_style_pretty.body.radius = LV_DPI / 15; + lv_style_pretty.body.border.color = LV_COLOR_MAKE(0x40, 0x40, 0x40); + lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1; + lv_style_pretty.body.border.opa = LV_OPA_30; + + /*Pretty color style*/ + memcpy(&lv_style_pretty_color, &lv_style_pretty, sizeof(lv_style_t)); + lv_style_pretty_color.text.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0); + lv_style_pretty_color.image.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0); + lv_style_pretty_color.line.color = LV_COLOR_MAKE(0xc0, 0xc0, 0xc0); + lv_style_pretty_color.body.main_color = LV_COLOR_MAKE(0x6b, 0x9a, 0xc7); + lv_style_pretty_color.body.grad_color = LV_COLOR_MAKE(0x2b, 0x59, 0x8b); + lv_style_pretty_color.body.border.color = LV_COLOR_MAKE(0x15, 0x2c, 0x42); + + /*Transparent style*/ + memcpy(&lv_style_transp, &lv_style_plain, sizeof(lv_style_t)); + lv_style_transp.body.empty = 1; + lv_style_transp.glass = 1; + lv_style_transp.body.border.width = 0; + + /*Transparent fitting size*/ + memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t)); + lv_style_transp_fit.body.padding.hor = 0; + lv_style_transp_fit.body.padding.ver = 0; + + /*Transparent tight style*/ + memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t)); + lv_style_transp_tight.body.padding.inner = 0; + + /*Button released style*/ + memcpy(&lv_style_btn_rel, &lv_style_plain, sizeof(lv_style_t)); + lv_style_btn_rel.body.main_color = LV_COLOR_MAKE(0x76, 0xa2, 0xd0); + lv_style_btn_rel.body.grad_color = LV_COLOR_MAKE(0x19, 0x3a, 0x5d); + lv_style_btn_rel.body.radius = LV_DPI / 15; + lv_style_btn_rel.body.padding.hor = LV_DPI / 4; + lv_style_btn_rel.body.padding.ver = LV_DPI / 6; + lv_style_btn_rel.body.padding.inner = LV_DPI / 10; + lv_style_btn_rel.body.border.color = LV_COLOR_MAKE(0x0b, 0x19, 0x28); + lv_style_btn_rel.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1; + lv_style_btn_rel.body.border.opa = LV_OPA_70; + lv_style_btn_rel.body.shadow.color = LV_COLOR_GRAY; + lv_style_btn_rel.body.shadow.width = 0; + lv_style_btn_rel.text.color = LV_COLOR_MAKE(0xff, 0xff, 0xff); + lv_style_btn_rel.image.color = LV_COLOR_MAKE(0xff, 0xff, 0xff); + + /*Button pressed style*/ + memcpy(&lv_style_btn_pr, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_pr.body.main_color = LV_COLOR_MAKE(0x33, 0x62, 0x94); + lv_style_btn_pr.body.grad_color = LV_COLOR_MAKE(0x10, 0x26, 0x3c); + lv_style_btn_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + + /*Button toggle released style*/ + memcpy(&lv_style_btn_tgl_rel, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_tgl_rel.body.main_color = LV_COLOR_MAKE(0x0a, 0x11, 0x22); + lv_style_btn_tgl_rel.body.grad_color = LV_COLOR_MAKE(0x37, 0x62, 0x90); + lv_style_btn_tgl_rel.body.border.color = LV_COLOR_MAKE(0x01, 0x07, 0x0d); + lv_style_btn_tgl_rel.text.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + lv_style_btn_tgl_rel.image.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + lv_style_btn_tgl_rel.line.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4); + + /*Button toggle pressed style*/ + memcpy(&lv_style_btn_tgl_pr, &lv_style_btn_tgl_rel, sizeof(lv_style_t)); + lv_style_btn_tgl_pr.body.main_color = LV_COLOR_MAKE(0x02, 0x14, 0x27); + lv_style_btn_tgl_pr.body.grad_color = LV_COLOR_MAKE(0x2b, 0x4c, 0x70); + lv_style_btn_tgl_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_tgl_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + lv_style_btn_tgl_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6); + + /*Button inactive style*/ + memcpy(&lv_style_btn_ina, &lv_style_btn_rel, sizeof(lv_style_t)); + lv_style_btn_ina.body.main_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8); + lv_style_btn_ina.body.grad_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8); + lv_style_btn_ina.body.border.color = LV_COLOR_MAKE(0x90, 0x90, 0x90); + lv_style_btn_ina.text.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); + lv_style_btn_ina.image.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); + lv_style_btn_ina.line.color = LV_COLOR_MAKE(0x70, 0x70, 0x70); +} + + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src) +{ + memcpy(dest, src, sizeof(lv_style_t)); +} + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio) +{ + STYLE_ATTR_MIX(body.opa, ratio); + STYLE_ATTR_MIX(body.radius, ratio); + STYLE_ATTR_MIX(body.border.width, ratio); + STYLE_ATTR_MIX(body.border.opa, ratio); + STYLE_ATTR_MIX(body.shadow.width, ratio); + STYLE_ATTR_MIX(body.padding.hor, ratio); + STYLE_ATTR_MIX(body.padding.ver, ratio); + STYLE_ATTR_MIX(body.padding.inner, ratio); + STYLE_ATTR_MIX(text.line_space, ratio); + STYLE_ATTR_MIX(text.letter_space, ratio); + STYLE_ATTR_MIX(text.opa, ratio); + STYLE_ATTR_MIX(line.width, ratio); + STYLE_ATTR_MIX(line.opa, ratio); + STYLE_ATTR_MIX(image.intense, ratio); + STYLE_ATTR_MIX(image.opa, ratio); + + lv_opa_t opa = ratio == STYLE_MIX_MAX ? LV_OPA_COVER : ratio; + + res->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa); + res->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa); + res->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa); + res->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa); + res->text.color = lv_color_mix(end->text.color, start->text.color, opa); + res->image.color = lv_color_mix(end->image.color, start->image.color, opa); + res->line.color = lv_color_mix(end->line.color, start->line.color, opa); + + if(ratio < (STYLE_MIX_MAX >> 1)) { + res->body.empty = start->body.empty; + res->body.border.part = start->body.border.part; + res->glass = start->glass; + res->text.font = start->text.font; + res->body.shadow.type = start->body.shadow.type; + res->line.rounded = start->line.rounded; + } else { + res->body.empty = end->body.empty; + res->body.border.part = end->body.border.part; + res->glass = end->glass; + res->text.font = end->text.font; + res->body.shadow.type = end->body.shadow.type; + res->line.rounded = end->line.rounded; + } +} + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim) +{ + lv_style_anim_dsc_t * dsc; + dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t)); + lv_mem_assert(dsc); + if(dsc == NULL) return NULL; + + dsc->style_anim = anim->style_anim; + memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t)); + memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t)); + memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t)); + dsc->end_cb = anim->end_cb; + + + lv_anim_t a; + a.var = (void *)dsc; + a.start = 0; + a.end = STYLE_MIX_MAX; + a.fp = (lv_anim_fp_t)style_animator; + a.path = lv_anim_path_linear; + a.end_cb = style_animation_common_end_cb; + a.act_time = anim->act_time; + a.time = anim->time; + a.playback = anim->playback; + a.playback_pause = anim->playback_pause; + a.repeat = anim->repeat; + a.repeat_pause = anim->repeat_pause; + + lv_anim_create(&a); + + return dsc; +} + +#endif +/********************** + * STATIC FUNCTIONS + **********************/ +#if USE_LV_ANIMATION +/** + * Used by the style animations to set the values of a style according to start and end style. + * @param dsc the 'animated variable' set by lv_style_anim_create() + * @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES + */ +static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val) +{ + const lv_style_t * start = &dsc->style_start; + const lv_style_t * end = &dsc->style_end; + lv_style_t * act = dsc->style_anim; + + lv_style_mix(start, end, act, val); + + lv_obj_report_style_mod(dsc->style_anim); +} + +/** + * Called when a style animation is ready + * It called the user defined call back and free the allocated memories + * @param ptr the 'animated variable' set by lv_style_anim_create() + */ +static void style_animation_common_end_cb(void * ptr) +{ + lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/ + + if(dsc->end_cb) dsc->end_cb(dsc); + + lv_mem_free(dsc); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_style.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_style.h new file mode 100644 index 0000000..0ba03c8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_style.h @@ -0,0 +1,198 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/ + +/********************** + * TYPEDEFS + **********************/ + +/*Border types (Use 'OR'ed values)*/ +enum +{ + LV_BORDER_NONE = 0x00, + LV_BORDER_BOTTOM = 0x01, + LV_BORDER_TOP = 0x02, + LV_BORDER_LEFT = 0x04, + LV_BORDER_RIGHT = 0x08, + LV_BORDER_FULL = 0x0F, + LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_part_t; + +/*Shadow types*/ +enum +{ + LV_SHADOW_BOTTOM = 0, + LV_SHADOW_FULL, +}; +typedef uint8_t lv_shadow_type_t; + +typedef struct +{ + uint8_t glass :1; /*1: Do not inherit this style*/ + + struct { + lv_color_t main_color; + lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/ + lv_coord_t radius; + lv_opa_t opa; + + struct { + lv_color_t color; + lv_coord_t width; + lv_border_part_t part; + lv_opa_t opa; + } border; + + struct { + lv_color_t color; + lv_coord_t width; + lv_shadow_type_t type; + } shadow; + + struct { + lv_coord_t ver; + lv_coord_t hor; + lv_coord_t inner; + } padding; + + uint8_t empty :1; /*Transparent background (border still drawn)*/ + } body; + + + struct { + lv_color_t color; + const lv_font_t * font; + lv_coord_t letter_space; + lv_coord_t line_space; + lv_opa_t opa; + } text; + + struct { + lv_color_t color; + lv_opa_t intense; + lv_opa_t opa; + } image; + + struct { + lv_color_t color; + lv_coord_t width; + lv_opa_t opa; + uint8_t rounded :1; /*1: rounded line endings*/ + } line; +} lv_style_t; + +#if USE_LV_ANIMATION +typedef struct { + const lv_style_t * style_start; /*Pointer to the starting style*/ + const lv_style_t * style_end; /*Pointer to the destination style*/ + lv_style_t * style_anim; /*Pointer to a style to animate*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/ + int16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ +} lv_style_anim_t; + +/* Example initialization +lv_style_anim_t a; +a.style_anim = &style_to_anim; +a.style_start = &style_1; +a.style_end = &style_2; +a.act_time = 0; +a.time = 1000; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +a.end_cb = NULL; +lv_style_anim_create(&a); + */ +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init (void); + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src); + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio); + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim); +#endif + +/************************* + * GLOBAL VARIABLES + *************************/ +extern lv_style_t lv_style_scr; +extern lv_style_t lv_style_transp; +extern lv_style_t lv_style_transp_fit; +extern lv_style_t lv_style_transp_tight; +extern lv_style_t lv_style_plain; +extern lv_style_t lv_style_plain_color; +extern lv_style_t lv_style_pretty; +extern lv_style_t lv_style_pretty_color; +extern lv_style_t lv_style_btn_rel; +extern lv_style_t lv_style_btn_pr; +extern lv_style_t lv_style_btn_tgl_rel; +extern lv_style_t lv_style_btn_tgl_pr; +extern lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.c b/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.c new file mode 100644 index 0000000..38aae34 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.c @@ -0,0 +1,207 @@ +/** + * @file lv_vdb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_vdb.h" +#if LV_VDB_SIZE != 0 + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_log.h" +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_FLUSH_READY +#define LV_ATTRIBUTE_FLUSH_READY +#endif + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/*Simple VDB*/ +#if LV_VDB_DOUBLE == 0 +# if LV_VDB_ADR == 0 +/*If the buffer address is not specified simply allocate it*/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf[LV_VDB_SIZE_IN_BYTES]; +static lv_vdb_t vdb = {.buf = (lv_color_t *)vdb_buf}; +# else /*LV_VDB_ADR != 0*/ +/*If the buffer address is specified use that address*/ +static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR}; +# endif + +/*LV_VDB_DOUBLE != 0*/ +#else +/*Double VDB*/ +static uint8_t vdb_active = 0; +# if LV_VDB_ADR == 0 +/*If the buffer address is not specified simply allocate it*/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf1[LV_VDB_SIZE_IN_BYTES]; +static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf2[LV_VDB_SIZE_IN_BYTES]; +static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}}; +# else /*LV_VDB_ADR != 0*/ +/*If the buffer address is specified use that address*/ +static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}}; +# endif +#endif + +static volatile bool vdb_flushing = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void) +{ +#if LV_VDB_DOUBLE == 0 + /* Wait until VDB is flushing. + * (Until this user calls of 'lv_flush_ready()' in the display drivers's flush function*/ + while(vdb_flushing); + + return &vdb; +#else + /*If already there is an active do nothing*/ + return &vdb[vdb_active]; +#endif +} + +/** + * Flush the content of the VDB + */ +void lv_vdb_flush(void) +{ + lv_vdb_t * vdb_act = lv_vdb_get(); + if(!vdb_act) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Don't start a new flush while the previous is not finished*/ +#if LV_VDB_DOUBLE + while(vdb_flushing); +#endif /*LV_VDB_DOUBLE*/ + + vdb_flushing = true; + + /*Flush the rendered content to the display*/ + lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf); + + +#if LV_VDB_DOUBLE + /*Make the other VDB active. The content of the current will be kept until the next flush*/ + vdb_active++; + vdb_active &= 0x1; + + /*If the screen is transparent initialize it when the new VDB is selected*/ +# if LV_COLOR_SCREEN_TRANSP + memset(vdb[vdb_active].buf, 0x00, LV_VDB_SIZE_IN_BYTES); +# endif /*LV_COLOR_SCREEN_TRANSP*/ + +#endif /*#if LV_VDB_DOUBLE*/ + +} + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2) +{ +#if LV_VDB_DOUBLE == 0 + (void) buf2; /*unused*/ + vdb.buf = buf1; +#else + vdb[0].buf = buf1; + vdb[1].buf = buf2; +#endif +} + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +LV_ATTRIBUTE_FLUSH_READY void lv_flush_ready(void) +{ + vdb_flushing = false; + + /*If the screen is transparent initialize it when the flushing is ready*/ +#if LV_VDB_DOUBLE == 0 && LV_COLOR_SCREEN_TRANSP + memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES); +#endif +} + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void) +{ +#if LV_VDB_DOUBLE == 0 + return &vdb; +#else + return &vdb[vdb_active]; +#endif +} + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void) +{ +#if LV_VDB_DOUBLE == 0 + return &vdb; +#else + return &vdb[(vdb_active + 1) & 0x1]; +#endif +} + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void) +{ + return vdb_flushing; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#else + +/** + * Just for compatibility + */ +void lv_flush_ready(void) +{ + /*Do nothing. It is used only for VDB*/ +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.h b/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.h new file mode 100644 index 0000000..e94ba19 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_core/lv_vdb.h @@ -0,0 +1,119 @@ +/** + * @file lv_vdb.h + * + */ + +#ifndef LV_VDB_H +#define LV_VDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ + +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */ +#endif + + +#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0) +#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required" +#endif + + +/* The size of VDB in bytes. + * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes + * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up. + * E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/ +#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + lv_area_t area; + lv_color_t *buf; +} lv_vdb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void); + +/** + * Flush the content of the vdb + */ +void lv_vdb_flush(void); + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +void lv_flush_ready(void); + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void); + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void); + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void); + +/********************** + * MACROS + **********************/ + +#else /*LV_VDB_SIZE != 0*/ + +/*Just for compatibility*/ +void lv_flush_ready(void); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VDB_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.c new file mode 100644 index 0000000..af374e3 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.c @@ -0,0 +1,163 @@ +/** + * @file lv_draw.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include +#include "lv_draw.h" +#include "lv_draw_rbasic.h" +#include "lv_draw_vbasic.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_ufs.h" +#include "../lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +#if LV_VDB_SIZE != 0 +void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vpx; +void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vfill; +void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_vletter; +void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) = lv_vmap; +#else +void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rpx; +void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rfill; +void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_rletter; +void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) = lv_rmap; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa) +{ + /* How to calculate the opacity of pixels on the edges which makes the anti-aliasing? + * For example we have a line like this (y = -0.5 * x): + * + * | _ _ + * * * | + * + * Anti-aliased pixels come to the '*' characters + * Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn: + * 1. A real line should start on (0;0) and end on (2;1) + * 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average + * 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average + * 4. The equation: (px_id * 2 + 1) / (segment_width * 2) + * segment_width: the line segment which is being anti-aliased (was 2 in the example) + * px_id: pixel ID from 0 to (segment_width - 1) + * result: [0..1] coverage of the pixel + */ + + /*Accelerate the common segment sizes to avoid division*/ + static const lv_opa_t seg1[1] = {128}; + static const lv_opa_t seg2[2] = {64, 192}; + static const lv_opa_t seg3[3] = {42, 128, 212}; + static const lv_opa_t seg4[4] = {32, 96, 159, 223}; + static const lv_opa_t seg5[5] = {26, 76, 128, 178, 230}; + static const lv_opa_t seg6[6] = {21, 64, 106, 148, 191, 234}; + static const lv_opa_t seg7[7] = {18, 55, 91, 128, 164, 200, 237}; + static const lv_opa_t seg8[8] = {16, 48, 80, 112, 143, 175, 207, 239}; + + static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4, + seg5, seg6, seg7, seg8 + }; + + if(seg == 0) return LV_OPA_TRANSP; + else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * base_opa) >> 8; + else { + return ((px_id * 2 + 1) * base_opa) / (2 * seg); + } + +} + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) +{ + bool aa_inv = false; + if(length < 0) { + aa_inv = true; + length = -length; + } + + lv_coord_t i; + for(i = 0; i < length; i++) { + lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa); + if(aa_inv) px_opa = opa - px_opa; + px_fp(x, y + i, mask, color, px_opa); + } +} + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) +{ + bool aa_inv = false; + if(length < 0) { + aa_inv = true; + length = -length; + } + + lv_coord_t i; + for(i = 0; i < length; i++) { + lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa); + if(aa_inv) px_opa = opa - px_opa; + px_fp(x + i, y, mask, color, px_opa); + } +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.h new file mode 100644 index 0000000..cf50e98 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.h @@ -0,0 +1,115 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_core/lv_style.h" +#include "../lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; +typedef uint8_t lv_img_src_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa); + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +#endif + +/********************** + * GLOBAL VARIABLES + **********************/ +extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa); +extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.mk b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.mk new file mode 100644 index 0000000..a384eef --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw.mk @@ -0,0 +1,14 @@ +CSRCS += lv_draw_vbasic.c +CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw +VPATH += :$(LVGL_DIR)/lvgl/lv_draw + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw" diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c new file mode 100644 index 0000000..525e56b --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.c @@ -0,0 +1,264 @@ +/** + * @file lv_draw_arc.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_arc.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint16_t fast_atan2(int x, int y); +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); +static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end); +static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t thickness = style->line.width; + if(thickness > radius) thickness = radius; + + lv_coord_t r_out = radius; + lv_coord_t r_in = r_out - thickness; + int16_t deg_base; + int16_t deg; + lv_coord_t x_start[4]; + lv_coord_t x_end[4]; + + lv_color_t color = style->line.color; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + + + bool (*deg_test)(uint16_t, uint16_t, uint16_t); + if(start_angle <= end_angle) deg_test = deg_test_norm; + else deg_test = deg_test_inv; + + if(deg_test(270, start_angle, end_angle)) hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa); // Left Middle + if(deg_test(90, start_angle, end_angle)) hor_line(center_x + r_in, center_y, mask, thickness - 1, color, opa); // Right Middle + if(deg_test(180, start_angle, end_angle)) ver_line(center_x, center_y - r_out + 1, mask, thickness - 1, color, opa); // Top Middle + if(deg_test(0, start_angle, end_angle)) ver_line(center_x, center_y + r_in, mask, thickness - 1, color, opa); // Bottom middle + + uint32_t r_out_sqr = r_out * r_out; + uint32_t r_in_sqr = r_in * r_in; + int16_t xi; + int16_t yi; + for(yi = -r_out; yi < 0; yi++) { + x_start[0] = LV_COORD_MIN; + x_start[1] = LV_COORD_MIN; + x_start[2] = LV_COORD_MIN; + x_start[3] = LV_COORD_MIN; + x_end[0] = LV_COORD_MIN; + x_end[1] = LV_COORD_MIN; + x_end[2] = LV_COORD_MIN; + x_end[3] = LV_COORD_MIN; + for(xi = -r_out; xi < 0; xi++) { + + uint32_t r_act_sqr = xi * xi + yi * yi; + if(r_act_sqr > r_out_sqr) continue; + + deg_base = fast_atan2(xi, yi) - 180; + + deg = 180 + deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[0] == LV_COORD_MIN) x_start[0] = xi; + } else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) { + x_end[0] = xi - 1; + } + + deg = 360 - deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[1] == LV_COORD_MIN) x_start[1] = xi; + } else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) { + x_end[1] = xi - 1; + } + + deg = 180 - deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[2] == LV_COORD_MIN) x_start[2] = xi; + } else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) { + x_end[2] = xi - 1; + } + + deg = deg_base; + if(deg_test(deg, start_angle, end_angle)) { + if(x_start[3] == LV_COORD_MIN) x_start[3] = xi; + } else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) { + x_end[3] = xi - 1; + } + + if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/ + } + + + if(x_start[0] != LV_COORD_MIN) { + if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1; + hor_line(center_x + x_start[0], center_y + yi, mask, x_end[0] - x_start[0], color, opa); + } + + if(x_start[1] != LV_COORD_MIN) { + if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1; + hor_line(center_x + x_start[1], center_y - yi, mask, x_end[1] - x_start[1], color, opa); + } + + if(x_start[2] != LV_COORD_MIN) { + if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1; + hor_line(center_x - x_end[2], center_y + yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa); + } + + if(x_start[3] != LV_COORD_MIN) { + if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1; + hor_line(center_x - x_end[3], center_y - yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa); + } + + +#if LV_ANTIALIAS + /*TODO*/ + +#endif + + } +} + +static uint16_t fast_atan2(int x, int y) +{ + // Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com + // Converts any XY values including 0 to a degree value that should be + // within +/- 1 degree of the accurate value without needing + // large slow trig functions like ArcTan() or ArcCos(). + // NOTE! at least one of the X or Y values must be non-zero! + // This is the full version, for all 4 quadrants and will generate + // the angle in integer degrees from 0-360. + // Any values of X and Y are usable including negative values provided + // they are between -1456 and 1456 so the 16bit multiply does not overflow. + + unsigned char negflag; + unsigned char tempdegree; + unsigned char comp; + unsigned int degree; // this will hold the result + //signed int x; // these hold the XY vector at the start + //signed int y; // (and they will be destroyed) + unsigned int ux; + unsigned int uy; + + // Save the sign flags then remove signs and get XY as unsigned ints + negflag = 0; + if(x < 0) { + negflag += 0x01; // x flag bit + x = (0 - x); // is now + + } + ux = x; // copy to unsigned var before multiply + if(y < 0) { + negflag += 0x02; // y flag bit + y = (0 - y); // is now + + } + uy = y; // copy to unsigned var before multiply + + // 1. Calc the scaled "degrees" + if(ux > uy) { + degree = (uy * 45) / ux; // degree result will be 0-45 range + negflag += 0x10; // octant flag bit + } else { + degree = (ux * 45) / uy; // degree result will be 0-45 range + } + + // 2. Compensate for the 4 degree error curve + comp = 0; + tempdegree = degree; // use an unsigned char for speed! + if(tempdegree > 22) { // if top half of range + if(tempdegree <= 44) comp++; + if(tempdegree <= 41) comp++; + if(tempdegree <= 37) comp++; + if(tempdegree <= 32) comp++; // max is 4 degrees compensated + } else { // else is lower half of range + if(tempdegree >= 2) comp++; + if(tempdegree >= 6) comp++; + if(tempdegree >= 10) comp++; + if(tempdegree >= 15) comp++; // max is 4 degrees compensated + } + degree += comp; // degree is now accurate to +/- 1 degree! + + // Invert degree if it was X>Y octant, makes 0-45 into 90-45 + if(negflag & 0x10) degree = (90 - degree); + + // 3. Degree is now 0-90 range for this quadrant, + // need to invert it for whichever quadrant it was in + if(negflag & 0x02) { // if -Y + if(negflag & 0x01) // if -Y -X + degree = (180 + degree); + else // else is -Y +X + degree = (180 - degree); + } else { // else is +Y + if(negflag & 0x01) // if +Y -X + degree = (360 - degree); + } + return degree; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x, y + len); + + fill_fp(&area, mask, color, opa); +} + +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x + len, y); + + fill_fp(&area, mask, color, opa); +} + +static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end) +{ + if(deg >= start && deg <= end) return true; + else return false; +} + +static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end) +{ + if(deg >= start || deg <= end) { + return true; + } else return false; +} diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h new file mode 100644 index 0000000..203eabe --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_arc.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.c new file mode 100644 index 0000000..5c24aa8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.c @@ -0,0 +1,759 @@ +/** + * @file lv_draw_img.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_img.h" +#include "../lv_misc/lv_fs.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + +static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style); +static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static void lv_img_decoder_close(void); +static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/********************** + * STATIC VARIABLES + **********************/ +static bool decoder_custom; +static const void * decoder_src; +static lv_img_src_t decoder_src_type; +static lv_img_header_t decoder_header; +static const lv_style_t * decoder_style; +#if USE_LV_FILESYSTEM +static lv_fs_file_t decoder_file; +#endif +#if LV_IMG_CF_INDEXED +static lv_color_t decoder_index_map[256]; +#endif + +static lv_img_decoder_info_f_t lv_img_decoder_info_custom; +static lv_img_decoder_open_f_t lv_img_decoder_open_custom; +static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom; +static lv_img_decoder_close_f_t lv_img_decoder_close_custom; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale) +{ + if(src == NULL) { + LV_LOG_WARN("Image draw: src is NULL"); + lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); + lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL); + return; + } + + lv_res_t res; + res = lv_img_draw_core(coords, mask, src, style, opa_scale); + + if(res == LV_RES_INV) { + LV_LOG_WARN("Image draw error"); + lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); + lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL); + return; + } +} + + +/** + * + * @param src + * @param header + * @param style + * @return + */ +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header) +{ + header->always_zero = 0; + /*Try to get info with the custom functions first*/ + if(lv_img_decoder_info_custom) { + lv_res_t custom_res; + custom_res = lv_img_decoder_info_custom(src, header); + if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/ + } + + lv_img_src_t src_type = lv_img_src_get_type(src); + if(src_type == LV_IMG_SRC_VARIABLE) { + header->w = ((lv_img_dsc_t *)src)->header.w; + header->h = ((lv_img_dsc_t *)src)->header.h; + header->cf = ((lv_img_dsc_t *)src)->header.cf; + } +#if USE_LV_FILESYSTEM + else if(src_type == LV_IMG_SRC_FILE) { + lv_fs_file_t file; + lv_fs_res_t res; + uint32_t rn; + res = lv_fs_open(&file, src, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); + } + + /*Create a dummy header on fs error*/ + if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { + header->w = LV_DPI; + header->h = LV_DPI; + header->cf = LV_IMG_CF_UNKOWN; + } + + lv_fs_close(&file); + } +#endif + else if(src_type == LV_IMG_SRC_SYMBOL) { + /*The size depend on the font but it is unknown here. It should be handled outside of the function*/ + header->w = 1; + header->h = 1; + /* Symbols always have transparent parts. Important because of cover check in the design function. + * The actual value doesn't matter because lv_draw_label will draw it*/ + header->cf = LV_IMG_CF_ALPHA_1BIT; + } else { + LV_LOG_WARN("Image get info found unknown src type"); + return false; + } + return true; + +} + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf) +{ + uint8_t px_size = 0; + + switch(cf) { + case LV_IMG_CF_UNKOWN: + case LV_IMG_CF_RAW: + px_size = 0; + break; + case LV_IMG_CF_TRUE_COLOR: + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: + px_size = LV_COLOR_SIZE; + break; + case LV_IMG_CF_TRUE_COLOR_ALPHA: + px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; + break; + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_ALPHA_1BIT: + px_size = 1; + break; + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_ALPHA_2BIT: + px_size = 2; + break; + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_ALPHA_4BIT: + px_size = 4; + break; + case LV_IMG_CF_INDEXED_8BIT: + case LV_IMG_CF_ALPHA_8BIT: + px_size = 8; + break; + default: + px_size = 0; + break; + } + + return px_size; +} + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf) +{ + bool is_chroma_keyed = false; + + switch(cf) { + case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: + case LV_IMG_CF_RAW_CHROMA_KEYED: + case LV_IMG_CF_INDEXED_1BIT: + case LV_IMG_CF_INDEXED_2BIT: + case LV_IMG_CF_INDEXED_4BIT: + case LV_IMG_CF_INDEXED_8BIT: + is_chroma_keyed = true; + break; + default: + is_chroma_keyed = false; + break; + } + + return is_chroma_keyed; +} + + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf) +{ + bool has_alpha = false; + + switch(cf) { + case LV_IMG_CF_TRUE_COLOR_ALPHA: + case LV_IMG_CF_RAW_ALPHA: + case LV_IMG_CF_ALPHA_1BIT: + case LV_IMG_CF_ALPHA_2BIT: + case LV_IMG_CF_ALPHA_4BIT: + case LV_IMG_CF_ALPHA_8BIT: + has_alpha = true; + break; + default: + has_alpha = false; + break; + } + + return has_alpha; +} + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src) +{ + lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN; + + if(src == NULL) return img_src_type; + const uint8_t * u8_p = src; + + /*The first byte shows the type of the image source*/ + if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) { + img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/ + } else if(u8_p[0] >= 0x80) { + img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/ + } else { + img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/ + } + + if (LV_IMG_SRC_UNKNOWN == img_src_type) { + LV_LOG_WARN("lv_img_src_get_type: unknown image type"); + } + + return img_src_type; +} + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp) +{ + lv_img_decoder_info_custom = info_fp; + lv_img_decoder_open_custom = open_fp; + lv_img_decoder_read_line_custom = read_fp; + lv_img_decoder_close_custom = close_fp; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + + +static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale) +{ + + lv_area_t mask_com; /*Common area of mask and coords*/ + bool union_ok; + union_ok = lv_area_intersect(&mask_com, mask, coords); + if(union_ok == false) { + return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ + } + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t) style->image.opa * opa_scale) >> 8; + + lv_img_header_t header; + lv_res_t header_res; + header_res = lv_img_dsc_get_info(src, &header); + if(header_res != LV_RES_OK) { + LV_LOG_WARN("Image draw can't get image info"); + lv_img_decoder_close(); + return LV_RES_INV; + } + + bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf); + bool alpha_byte = lv_img_color_format_has_alpha(header.cf); + + const uint8_t * img_data = lv_img_decoder_open(src, style); + if(img_data == LV_IMG_DECODER_OPEN_FAIL) { + LV_LOG_WARN("Image draw cannot open the image resource"); + lv_img_decoder_close(); + return LV_RES_INV; + } + + /* The decoder open could open the image and gave the entire uncompressed image. + * Just draw it!*/ + if(img_data) { + map_fp(coords, mask, img_data, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense); + } + /* The whole uncompressed image is not available. Try to read it line-by-line*/ + else { + lv_coord_t width = lv_area_get_width(&mask_com); + +#if LV_COMPILER_VLA_SUPPORTED + uint8_t buf[(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1))]; +#else + uint8_t buf[LV_HOR_RES * ((LV_COLOR_DEPTH >> 3) + 1)]; /*+1 because of the possible alpha byte*/ +#endif + lv_area_t line; + lv_area_copy(&line, &mask_com); + lv_area_set_height(&line, 1); + lv_coord_t x = mask_com.x1 - coords->x1; + lv_coord_t y = mask_com.y1 - coords->y1; + lv_coord_t row; + lv_res_t read_res; + for(row = mask_com.y1; row <= mask_com.y2; row++) { + read_res = lv_img_decoder_read_line(x, y, width, buf); + if(read_res != LV_RES_OK) { + lv_img_decoder_close(); + LV_LOG_WARN("Image draw can't read the line"); + return LV_RES_INV; + } + map_fp(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense); + line.y1++; + line.y2++; + y++; + } + } + + lv_img_decoder_close(); + + return LV_RES_OK; +} + + +static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style) +{ + decoder_custom = false; + + /*Try to open with the custom functions first*/ + if(lv_img_decoder_open_custom) { + const uint8_t * custom_res; + custom_res = lv_img_decoder_open_custom(src, style); + if(custom_res != LV_IMG_DECODER_OPEN_FAIL) { + decoder_custom = true; /*Mark that custom decoder function should be used for this img source.*/ + return custom_res; /*Custom open supported this source*/ + } + } + + decoder_src = src; + decoder_style = style; + decoder_src_type = lv_img_src_get_type(src); + + lv_res_t header_res; + header_res = lv_img_dsc_get_info(src, &decoder_header); + if(header_res == LV_RES_INV) { + decoder_src = NULL; + decoder_src_type = LV_IMG_SRC_UNKNOWN; + LV_LOG_WARN("Built-in image decoder can't get the header info"); + return LV_IMG_DECODER_OPEN_FAIL; + } + + /*Open the file if it's a file*/ + if(decoder_src_type == LV_IMG_SRC_FILE) { +#if USE_LV_FILESYSTEM + lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder can't open the file"); + return LV_IMG_DECODER_OPEN_FAIL; + } +#else + LV_LOG_WARN("Image built-in decoder can read file because USE_LV_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + + + /*Process the different color formats*/ + lv_img_cf_t cf = decoder_header.cf; + if(cf == LV_IMG_CF_TRUE_COLOR || + cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's pointer*/ + return ((lv_img_dsc_t *)decoder_src)->data; + } else { + /*If it's file it need to be read line by line later*/ + return NULL; + } + } else if(cf == LV_IMG_CF_INDEXED_1BIT || + cf == LV_IMG_CF_INDEXED_2BIT || + cf == LV_IMG_CF_INDEXED_4BIT || + cf == LV_IMG_CF_INDEXED_8BIT) { + +#if LV_IMG_CF_INDEXED +#if USE_LV_FILESYSTEM + lv_color32_t palette_file[256]; +#endif + + lv_color32_t * palette_p = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(cf); + uint32_t palette_size = 1 << px_size; + + if(decoder_src_type == LV_IMG_SRC_FILE) { + /*Read the palette from file*/ +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, 4); /*Skip the header*/ + lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL); + palette_p = palette_file; +#else + LV_LOG_WARN("Image built-in decoder can read the palette because USE_LV_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + /*The palette begins in the beginning of the image data. Just point to it.*/ + palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data; + } + + uint32_t i; + for(i = 0; i < palette_size; i++) { + decoder_index_map[i] = LV_COLOR_MAKE(palette_p[i].red, palette_p[i].green, palette_p[i].blue); + } + return NULL; +#else + LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else if(cf == LV_IMG_CF_ALPHA_1BIT || + cf == LV_IMG_CF_ALPHA_2BIT || + cf == LV_IMG_CF_ALPHA_4BIT || + cf == LV_IMG_CF_ALPHA_8BIT) { +#if LV_IMG_CF_ALPHA + return NULL; /*Nothing to process*/ +#else + LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + LV_LOG_WARN("Image decoder open: unknown color format") + return LV_IMG_DECODER_OPEN_FAIL; + } +} + + +static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + /*Try to read the line with the custom functions*/ + if(decoder_custom) { + if(lv_img_decoder_read_line_custom) { + lv_res_t custom_res; + custom_res = lv_img_decoder_read_line_custom(x, y, len, buf); + return custom_res; + } else { + LV_LOG_WARN("Image open with custom decoder but read not supported") + } + return LV_RES_INV; /*It"s an error if not returned earlier*/ + } + + if(decoder_src_type == LV_IMG_SRC_FILE) { +#if USE_LV_FILESYSTEM + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + + lv_fs_res_t res; + + if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR || + decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3; + pos += 4; /*Skip the header*/ + res = lv_fs_seek(&decoder_file, pos); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder seek failed"); + return false; + } + uint32_t btr = len * (px_size >> 3); + uint32_t br = 0; + lv_fs_read(&decoder_file, buf, btr, &br); + if(res != LV_FS_RES_OK || btr != br) { + LV_LOG_WARN("Built-in image decoder read failed"); + return false; + } + } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_2BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_4BIT || + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) { + + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_2BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_4BIT || + decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder read not supports the color format"); + return false; + } +#else + LV_LOG_WARN("Image built-in decoder can't read file because USE_LV_FILESYSTEM = 0"); + return false; +#endif + } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + + if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || + img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + lv_img_built_in_decoder_line_alpha(x, y, len, buf); + } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || + img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + lv_img_built_in_decoder_line_indexed(x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder not supports the color format"); + return false; + } + } + + return true; +} + +static void lv_img_decoder_close(void) +{ + /*Try to close with the custom functions*/ + if(decoder_custom) { + if(lv_img_decoder_close_custom) lv_img_decoder_close_custom(); + return; + } + + /*It was opened with built-in decoder*/ + if(decoder_src) { +#if USE_LV_FILESYSTEM + if(decoder_src_type == LV_IMG_SRC_FILE) { + lv_fs_close(&decoder_file); + } +#endif + decoder_src_type = LV_IMG_SRC_UNKNOWN; + decoder_src = NULL; + } +} + +static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + +#if LV_IMG_CF_ALPHA + const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + + /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ + lv_color_t bg_color = decoder_style->image.color; + lv_coord_t i; + for(i = 0; i < len; i++) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; +#elif LV_COLOR_DEPTH == 32 + *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; +#else +#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" +#endif + } + + const lv_opa_t * opa_table = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + uint32_t ofs = 0; + int8_t pos = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_ALPHA_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + pos = 7 - (x & 0x7); + opa_table = alpha1_opa_table; + break; + case LV_IMG_CF_ALPHA_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + pos = 6 - ((x & 0x3) * 2); + opa_table = alpha2_opa_table; + break; + case LV_IMG_CF_ALPHA_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + pos = 4 - ((x & 0x1) * 4); + opa_table = alpha4_opa_table; + break; + case LV_IMG_CF_ALPHA_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + pos = 0; + break; + } + +#if USE_LV_FILESYSTEM +# if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +# else + uint8_t fs_buf[LV_HOR_RES]; +# endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN("Image built-in alpha line reader can't read file because USE_LV_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + + uint8_t byte_act = 0; + uint8_t val_act; + for(i = 0; i < len; i ++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = + decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; + +#else + LV_LOG_WARN("Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + +static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + +#if LV_IMG_CF_INDEXED + uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + int8_t pos = 0; + uint32_t ofs = 0; + switch(decoder_header.cf) { + case LV_IMG_CF_INDEXED_1BIT: + w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(decoder_header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + ofs += 8; /*Skip the palette*/ + pos = 7 - (x & 0x7); + break; + case LV_IMG_CF_INDEXED_2BIT: + w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(decoder_header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + ofs += 16; /*Skip the palette*/ + pos = 6 - ((x & 0x3) * 2); + break; + case LV_IMG_CF_INDEXED_4BIT: + w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(decoder_header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + ofs += 64; /*Skip the palette*/ + pos = 4 - ((x & 0x1) * 4); + break; + case LV_IMG_CF_INDEXED_8BIT: + w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + ofs += 1024; /*Skip the palette*/ + pos = 0; + break; + } + +#if USE_LV_FILESYSTEM +# if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +# else + uint8_t fs_buf[LV_HOR_RES]; +# endif +#endif + const uint8_t * data_tmp = NULL; + if(decoder_src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = decoder_src; + data_tmp = img_dsc->data + ofs; + } else { +#if USE_LV_FILESYSTEM + lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(&decoder_file, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN("Image built-in indexed line reader can't read file because USE_LV_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + lv_coord_t i; + lv_color_t * cbuf = (lv_color_t *) buf; + for(i = 0; i < len; i ++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + cbuf[i] = decoder_index_map[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; +#else + LV_LOG_WARN("Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.h new file mode 100644 index 0000000..31ed827 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_img.h @@ -0,0 +1,167 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1)) + +/********************** + * TYPEDEFS + **********************/ +struct _lv_img_t; + +typedef struct { + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/ + + uint32_t reserved :2; /*Reserved to be used later*/ + + uint32_t w:11; /*Width of the image map*/ + uint32_t h:11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y startt y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(void); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp); + +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf); + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.c new file mode 100644 index 0000000..0744ff1 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.c @@ -0,0 +1,264 @@ +/** + * @file lv_draw_label.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_label.h" +#include "lv_draw_rbasic.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LABEL_RECOLOR_PAR_LENGTH 6 + +/********************** + * TYPEDEFS + **********************/ +enum { + CMD_STATE_WAIT, + CMD_STATE_PAR, + CMD_STATE_IN, +}; +typedef uint8_t cmd_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint8_t hex_char_to_num(char hex); + +/********************** + * STATIC VARIABLES + **********************/ + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset) +{ + const lv_font_t * font = style->text.font; + lv_coord_t w; + if((flag & LV_TXT_FLAG_EXPAND) == 0) { + /*Normally use the label's width as width*/ + w = lv_area_get_width(coords); + } else { + /*If EXAPND is enabled then not limit the text's width to the object's width*/ + lv_point_t p; + lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); + w = p.x; + } + + lv_coord_t line_height = lv_font_get_height(font) + style->text.line_space; + + + /*Init variables for the first line*/ + lv_coord_t line_width = 0; + lv_point_t pos; + pos.x = coords->x1; + pos.y = coords->y1; + + lv_coord_t x_ofs = 0; + lv_coord_t y_ofs = 0; + if(offset != NULL) { + x_ofs = offset->x; + y_ofs = offset->y; + pos.y += y_ofs; + } + + uint32_t line_start = 0; + uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag); + + /*Go the first visible line*/ + while(pos.y + line_height < mask->y1) { + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); + pos.y += line_height; + + if(txt[line_start] == '\0') return; + } + + /*Align to middle*/ + if(flag & LV_TXT_FLAG_CENTER) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + + pos.x += (lv_area_get_width(coords) - line_width) / 2; + + } + /*Align to the right*/ + else if(flag & LV_TXT_FLAG_RIGHT) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t) style->text.opa * opa_scale) >> 8; + + cmd_state_t cmd_state = CMD_STATE_WAIT; + uint32_t i; + uint16_t par_start = 0; + lv_color_t recolor; + lv_coord_t letter_w; + + /*Real draw need a background color for higher bpp letter*/ +#if LV_VDB_SIZE == 0 + lv_rletter_set_background(style->body.main_color); +#endif + + + /*Write out all lines*/ + while(txt[line_start] != '\0') { + if(offset != NULL) { + pos.x += x_ofs; + } + /*Write all letter of a line*/ + cmd_state = CMD_STATE_WAIT; + i = line_start; + uint32_t letter; + while(i < line_end) { + letter = lv_txt_encoded_next(txt, &i); + + /*Handle the re-color command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) { + if(cmd_state == CMD_STATE_WAIT) { /*Start char*/ + par_start = i; + cmd_state = CMD_STATE_PAR; + continue; + } else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */ + cmd_state = CMD_STATE_WAIT; + } else if(cmd_state == CMD_STATE_IN) { /*Command end */ + cmd_state = CMD_STATE_WAIT; + continue; + } + } + + /*Skip the color parameter and wait the space after it*/ + if(cmd_state == CMD_STATE_PAR) { + if(letter == ' ') { + /*Get the parameter*/ + if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) { + char buf[LABEL_RECOLOR_PAR_LENGTH + 1]; + memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH); + buf[LABEL_RECOLOR_PAR_LENGTH] = '\0'; + int r, g, b; + r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]); + g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]); + b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]); + recolor = LV_COLOR_MAKE(r, g, b); + } else { + recolor.full = style->text.color.full; + } + cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + continue; + } + } + + lv_color_t color = style->text.color; + + if(cmd_state == CMD_STATE_IN) color = recolor; + + letter_fp(&pos, mask, font, letter, color, opa); + letter_w = lv_font_get_width(font, letter); + + if(letter_w > 0){ + pos.x += letter_w + style->text.letter_space; + } + } + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); + + pos.x = coords->x1; + /*Align to middle*/ + if(flag & LV_TXT_FLAG_CENTER) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + + pos.x += (lv_area_get_width(coords) - line_width) / 2; + + } + /*Align to the right*/ + else if(flag & LV_TXT_FLAG_RIGHT) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, + font, style->text.letter_space, flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + /*Go the next line position*/ + pos.y += line_height; + + if(pos.y > mask->y2) return; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert a hexadecimal characters to a number (0..15) + * @param hex Pointer to a hexadecimal character (0..9, A..F) + * @return the numerical value of `hex` or 0 on error + */ +static uint8_t hex_char_to_num(char hex) +{ + uint8_t result = 0; + + if(hex >= '0' && hex <= '9') { + result = hex - '0'; + } + else { + if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ + + switch(hex) { + case 'A': + result = 10; + break; + case 'B': + result = 11; + break; + case 'C': + result = 12; + break; + case 'D': + result = 13; + break; + case 'E': + result = 14; + break; + case 'F': + result = 15; + break; + default: + result = 0; + break; + } + } + + return result; +} diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.h new file mode 100644 index 0000000..8798573 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_label.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.c new file mode 100644 index 0000000..6e72ff4 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.c @@ -0,0 +1,607 @@ +/** + * @file lv_draw_line.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_draw.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#if LV_COMPILER_VLA_SUPPORTED == 0 +#define LINE_MAX_WIDTH 64 +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_point_t p1; + lv_point_t p2; + lv_point_t p_act; + lv_coord_t dx; + lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/ + lv_coord_t dy; + lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/ + lv_coord_t err; + lv_coord_t e2; + bool hor; /*Rather horizontal or vertical*/ +} line_draw_t; + +typedef struct { + lv_coord_t width; + lv_coord_t width_1; + lv_coord_t width_half; +} line_width_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2); +static bool line_next(line_draw_t * line); +static bool line_next_y(line_draw_t * line); +static bool line_next_x(line_draw_t * line); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale) +{ + + if(style->line.width == 0) return; + if(point1->x == point2->x && point1->y == point2->y) return; + + line_draw_t main_line; + lv_point_t p1; + lv_point_t p2; + + /*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/ + + if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) { + + /*Steps less in y then x -> rather horizontal*/ + if(point1->x < point2->x) { + p1.x = point1->x; + p1.y = point1->y; + p2.x = point2->x; + p2.y = point2->y; + } else { + p1.x = point2->x; + p1.y = point2->y; + p2.x = point1->x; + p2.y = point1->y; + } + } else { + /*Steps less in x then y -> rather vertical*/ + if(point1->y < point2->y) { + p1.x = point1->x; + p1.y = point1->y; + p2.x = point2->x; + p2.y = point2->y; + } else { + p1.x = point2->x; + p1.y = point2->y; + p2.x = point1->x; + p2.y = point1->y; + } + } + + line_init(&main_line, &p1, &p2); + + + /*Special case draw a horizontal line*/ + if(main_line.p1.y == main_line.p2.y) { + line_draw_hor(&main_line, mask, style, opa_scale); + } + /*Special case draw a vertical line*/ + else if(main_line.p1.x == main_line.p2.x) { + line_draw_ver(&main_line, mask, style, opa_scale); + } + /*Arbitrary skew line*/ + else { + bool dir_ori = false; +#if LV_ANTIALIAS + lv_point_t p_tmp; + + if(main_line.hor) { + if(main_line.p1.y < main_line.p2.y) { + dir_ori = true; + p_tmp.x = main_line.p2.x; + p_tmp.y = main_line.p2.y - 1; + line_init(&main_line, &p1, &p_tmp); + main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ + } + else if(main_line.p1.y > main_line.p2.y) { + dir_ori = false; + p_tmp.x = main_line.p2.x; + p_tmp.y = main_line.p2.y + 1; + line_init(&main_line, &p1, &p_tmp); + main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ + } + } + else { + if(main_line.p1.x < main_line.p2.x) { + dir_ori = true; + p_tmp.x = main_line.p2.x - 1; + p_tmp.y = main_line.p2.y; + line_init(&main_line, &p1, &p_tmp); + main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ + } + else if(main_line.p1.x > main_line.p2.x) { + dir_ori = false; + p_tmp.x = main_line.p2.x + 1; + p_tmp.y = main_line.p2.y; + line_init(&main_line, &p1, &p_tmp); + main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ + } + } +#endif + line_draw_skew(&main_line, dir_ori, mask, style, opa_scale); + } +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + + +static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t width = style->line.width - 1; + lv_coord_t width_half = width >> 1; + lv_coord_t width_1 = width & 0x1; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + lv_area_t act_area; + act_area.x1 = main_line->p1.x; + act_area.x2 = main_line->p2.x; + act_area.y1 = main_line->p1.y - width_half - width_1; + act_area.y2 = main_line->p2.y + width_half ; + + lv_area_t draw_area; + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + fill_fp(&draw_area, mask, style->line.color, opa); +} + +static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t width = style->line.width - 1; + lv_coord_t width_half = width >> 1; + lv_coord_t width_1 = width & 0x1; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + + lv_area_t act_area; + act_area.x1 = main_line->p1.x - width_half; + act_area.x2 = main_line->p2.x + width_half + width_1; + act_area.y1 = main_line->p1.y; + act_area.y2 = main_line->p2.y; + + lv_area_t draw_area; + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + fill_fp(&draw_area, mask, style->line.color, opa); +} + +static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8; + + lv_point_t vect_main, vect_norm; + vect_main.x = main_line->p2.x - main_line->p1.x; + vect_main.y = main_line->p2.y - main_line->p1.y; + + if(main_line->hor) { + if(main_line->p1.y < main_line->p2.y + dir_ori) { + vect_norm.x = - vect_main.y; + vect_norm.y = vect_main.x; + } else { + vect_norm.x = vect_main.y; + vect_norm.y = -vect_main.x; + } + } else { + if(main_line->p1.x < main_line->p2.x + dir_ori) { + vect_norm.x = vect_main.y; + vect_norm.y = - vect_main.x; + } else { + vect_norm.x = - vect_main.y; + vect_norm.y = vect_main.x; + } + } + + /* In case of a short but tick line the perpendicular ending is longer then the real line. + * it would break the calculations so make the normal vector larger*/ + vect_norm.x = vect_norm.x << 4; + vect_norm.y = vect_norm.y << 4; + + lv_coord_t width; + width = style->line.width; + + /* The pattern stores the points of the line ending. It has the good direction and length. + * The worth case is the 45° line where pattern can have 1.41 x `width` points*/ +#if LV_COMPILER_VLA_SUPPORTED + lv_point_t pattern[width * 2]; +#else + lv_point_t pattern[LINE_MAX_WIDTH]; +#endif + lv_coord_t i = 0; + + /*Create a perpendicular pattern (a small line)*/ + if(width != 0) { + line_draw_t pattern_line; + lv_point_t p0 = {0, 0}; + line_init(&pattern_line, &p0, &vect_norm); + + uint32_t width_sqr = width * width; + /* Run for a lot of times. Meanwhile the real width will be determined as well */ + for(i = 0; i < (lv_coord_t)sizeof(pattern); i ++) { + pattern[i].x = pattern_line.p_act.x; + pattern[i].y = pattern_line.p_act.y; + + /*Finish the pattern line if it's length equal to the desired width (Use Pythagoras theorem)*/ + uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y; + if(sqr >= width_sqr) { + width = i; +#if LV_ANTIALIAS + width--; +#endif + break; + } + + line_next(&pattern_line); + } + } + +#if LV_ANTIALIAS + lv_coord_t width_safe = width; + if(width == 0) width_safe = 1; + + lv_coord_t aa_last_corner; + aa_last_corner = 0; +#endif + + lv_coord_t x_center_ofs = 0; + lv_coord_t y_center_ofs = 0; + + if(width != 0) { + x_center_ofs = pattern[width - 1].x / 2; + y_center_ofs = pattern[width - 1].y / 2; + } + else { + if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y --; + if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x --; + } + + /* Make the coordinates relative to the center */ + for(i = 0; i < width; i++) { + pattern[i].x -= x_center_ofs; + pattern[i].y -= y_center_ofs; +#if LV_ANTIALIAS + if(i != 0) { + if(main_line->hor) { + if(pattern[i - 1].x != pattern[i].x) { + lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y; + if(main_line->sy < 0) { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, + -seg_w, mask, style->line.color, opa); + } else { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y, + -seg_w, mask, style->line.color, opa); + } + aa_last_corner = i; + } + } else { + if(pattern[i - 1].y != pattern[i].y) { + lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x; + if(main_line->sx < 0) { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p2.y + pattern[aa_last_corner].y + 1, + -seg_w, mask, style->line.color, opa); + } else { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1, + -seg_w, mask, style->line.color, opa); + } + aa_last_corner = i; + } + } + + } +#endif + } + + + +#if LV_ANTIALIAS + /*Add the last part of anti-aliasing for the perpendicular ending*/ + if(width != 0) { /*Due to rounding error with very thin lines it looks ugly*/ + if(main_line->hor) { + lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y; + if(main_line->sy < 0) { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w, + seg_w + main_line->sy, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w, + -(seg_w + main_line->sy), mask, style->line.color, opa); + + } else { + lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y, + seg_w + main_line->sy, mask, style->line.color, opa); + + lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y, + -(seg_w + main_line->sy), mask, style->line.color, opa); + } + } else { + lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x; + if(main_line->sx < 0) { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w + main_line->sx, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, main_line->p2.y + pattern[aa_last_corner].y + 1, + -(seg_w + main_line->sx), mask, style->line.color, opa); + + } else { + lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1, + seg_w + main_line->sx, mask, style->line.color, opa); + + lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1, + -(seg_w + main_line->sx), mask, style->line.color, opa); + } + + } + } +#endif + +#if LV_ANTIALIAS + + /*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/ + lv_coord_t aa_shift1; + lv_coord_t aa_shift2; + + if(main_line->hor == false) { + if(main_line->sx < 0) { + aa_shift1 = -1; + aa_shift2 = width == 0 ? 0 : aa_shift1; + } else { + aa_shift2 = 1; + aa_shift1 = width == 0 ? 0 : aa_shift2; + } + } else { + if(main_line->sy < 0) { + aa_shift1 = -1; + aa_shift2 = width == 0 ? 0 : aa_shift1; + } else { + aa_shift2 = 1; + aa_shift1 = width == 0 ? 0 : aa_shift2; + } + } + +#endif + + volatile lv_point_t prev_p; + prev_p.x = main_line->p1.x; + prev_p.y = main_line->p1.y; + lv_area_t draw_area; + bool first_run = true; + + if(main_line->hor) { + while(line_next_y(main_line)) { + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1; + draw_area.y2 = draw_area.y1; + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in y one pixel remains empty on every corner (don't do this on the first segment ) */ + if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { + px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, + -(main_line->p_act.x - prev_p.x), mask, style->line.color, opa); + lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2, + main_line->p_act.x - prev_p.x, mask, style->line.color, opa); +#endif + + first_run = false; + + prev_p.x = main_line->p_act.x; + prev_p.y = main_line->p_act.y; + } + + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x; + draw_area.y2 = draw_area.y1; + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in y one pixel remains empty on every corner */ + if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { + px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, + -(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa); + lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2, + main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa); +#endif + } + /*Rather a vertical line*/ + else { + + while(line_next_x(main_line)) { + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1; + draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1; + + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in x one pixel remains empty on every corner (don't do this on the first segment ) */ + if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { + px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); + } + + } + +#if LV_ANTIALIAS + lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, + -(main_line->p_act.y - prev_p.y), mask, style->line.color, opa); + lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y, + main_line->p_act.y - prev_p.y, mask, style->line.color, opa); +#endif + + first_run = false; + + prev_p.x = main_line->p_act.x; + prev_p.y = main_line->p_act.y; + } + + /*Draw the last part*/ + for(i = 0; i < width; i++) { + draw_area.x1 = prev_p.x + pattern[i].x; + draw_area.y1 = prev_p.y + pattern[i].y; + draw_area.x2 = draw_area.x1; + draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y; + + fill_fp(&draw_area, mask, style->line.color, opa); + + /* Fill the gaps + * When stepping in x one pixel remains empty on every corner */ + if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { + px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); + } + } + +#if LV_ANTIALIAS + lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, + -(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa); + lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y, + main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa); +#endif + } +} + + +static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2) +{ + line->p1.x = p1->x; + line->p1.y = p1->y; + line->p2.x = p2->x; + line->p2.y = p2->y; + + line->dx = LV_MATH_ABS(line->p2.x - line->p1.x); + line->sx = line->p1.x < line->p2.x ? 1 : -1; + line->dy = LV_MATH_ABS(line->p2.y - line->p1.y); + line->sy = line->p1.y < line->p2.y ? 1 : -1; + line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2; + line->e2 = 0; + line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/ + + line->p_act.x = line->p1.x; + line->p_act.y = line->p1.y; +} + +static bool line_next(line_draw_t * line) +{ + if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false; + line->e2 = line->err; + if(line->e2 > -line->dx) { + line->err -= line->dy; + line->p_act.x += line->sx; + } + if(line->e2 < line->dy) { + line->err += line->dx; + line->p_act.y += line->sy; + } + return true; +} + +/** + * Iterate until step one in y direction. + * @param line + * @return + */ +static bool line_next_y(line_draw_t * line) +{ + lv_coord_t last_y = line->p_act.y; + + do { + if(!line_next(line)) return false; + } while(last_y == line->p_act.y); + + return true; + +} + +/** + * Iterate until step one in x direction. + * @param line + * @return + */ +static bool line_next_x(line_draw_t * line) +{ + lv_coord_t last_x = line->p_act.x; + + do { + if(!line_next(line)) return false; + } while(last_x == line->p_act.x); + + return true; + +} + diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.h new file mode 100644 index 0000000..4269475 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_line.h @@ -0,0 +1,49 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c new file mode 100644 index 0000000..369adf5 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c @@ -0,0 +1,269 @@ +/** + * @file lv_draw_rbasic.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_rbasic.h" +#if USE_LV_REAL_DRAW != 0 + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_font.h" +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_color_t letter_bg_color; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Put a pixel to the display + * @param x x coordinate of the pixel + * @param y y coordinate of the pixel + * @param mask_p the pixel will be drawn on this area + * @param color color of the pixel + * @param opa opacity (ignored, only for compatibility with lv_vpx) + */ +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa) +{ + (void)opa; /*Opa is used only for compatibility with lv_vpx*/ + + lv_area_t area; + area.x1 = x; + area.y1 = y; + area.x2 = x; + area.y2 = y; + + lv_rfill(&area, mask_p, color, LV_OPA_COVER); +} + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa) +{ + + (void)opa; /*Opa is used only for compatibility with lv_vfill*/ + + lv_area_t masked_area; + bool union_ok = true; + + if(mask_p != NULL) { + union_ok = lv_area_intersect(&masked_area, cords_p, mask_p); + } else { + lv_area_t scr_area; + lv_area_set(&scr_area, 0, 0, LV_HOR_RES - 1, LV_VER_RES - 1); + union_ok = lv_area_intersect(&masked_area, cords_p, &scr_area); + } + + if(union_ok != false) { + lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color); + } +} + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa) +{ + (void)opa; /*Opa is used only for compatibility with lv_vletter*/ + + static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + static uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + + if(font_p == NULL) return; + + uint8_t letter_w = lv_font_get_width(font_p, letter); + uint8_t letter_h = lv_font_get_height(font_p); + uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/ + uint8_t * bpp_opa_table; + uint8_t mask_init; + uint8_t mask; + + switch(bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + mask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + mask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + mask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + mask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + return; /*Invalid bpp. Can't render the letter*/ + } + + const uint8_t * map_p = lv_font_get_bitmap(font_p, letter); + + if(map_p == NULL) return; + + /*If the letter is completely out of mask don't draw it */ + if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 || + pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return; + + lv_coord_t col, row; + uint8_t col_bit; + uint8_t col_byte_cnt; + uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(letter_w & 0x7) width_byte_scr++; + uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/ + if((letter_w * bpp) & 0x7) width_byte_bpp++; + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_p->x >= mask_p->x1 ? 0 : mask_p->x1 - pos_p->x; + lv_coord_t col_end = pos_p->x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_p->x + 1; + lv_coord_t row_start = pos_p->y >= mask_p->y1 ? 0 : mask_p->y1 - pos_p->y; + lv_coord_t row_end = pos_p->y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_p->y + 1; + + /*Move on the map too*/ + map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3); + + uint8_t letter_px; + for(row = row_start; row < row_end; row ++) { + col_byte_cnt = 0; + col_bit = (col_start * bpp) % 8; + mask = mask_init >> col_bit; + for(col = col_start; col < col_end; col ++) { + letter_px = (*map_p & mask) >> (8 - col_bit - bpp); + if(letter_px != 0) { + lv_rpx(pos_p->x + col, pos_p->y + row, mask_p, lv_color_mix(color, letter_bg_color, bpp == 8 ? letter_px : bpp_opa_table[letter_px]), LV_OPA_COVER); + } + + if(col_bit < 8 - bpp) { + col_bit += bpp; + mask = mask >> bpp; + } else { + col_bit = 0; + col_byte_cnt ++; + mask = mask_init; + map_p ++; + } + } + + map_p += (width_byte_bpp) - col_byte_cnt; + } +} + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color) +{ + letter_bg_color = color; +} + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) +{ + if(alpha_byte) return; /*Pixel level opacity i not supported in real map drawing*/ + + (void)opa; /*opa is used only for compatibility with lv_vmap*/ + lv_area_t masked_a; + bool union_ok; + + union_ok = lv_area_intersect(&masked_a, cords_p, mask_p); + + /*If there are common part of the mask and map then draw the map*/ + if(union_ok == false) return; + + /*Go to the first pixel*/ + lv_coord_t map_width = lv_area_get_width(cords_p); + map_p += (masked_a.y1 - cords_p->y1) * map_width * sizeof(lv_color_t); + map_p += (masked_a.x1 - cords_p->x1) * sizeof(lv_color_t); + + lv_coord_t row; + if(recolor_opa == LV_OPA_TRANSP && chroma_key == false) { + lv_coord_t mask_w = lv_area_get_width(&masked_a) - 1; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t *)map_p); + map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/ + } + } else { + lv_color_t chroma_key_color = LV_COLOR_TRANSP; + lv_coord_t col; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = masked_a.x1; col <= masked_a.x2; col++) { + lv_color_t * px_color = (lv_color_t *) &map_p[(uint32_t)(col - masked_a.x1) * sizeof(lv_color_t)]; + + if(chroma_key && chroma_key_color.full == px_color->full) continue; + + if(recolor_opa != LV_OPA_TRANSP) { + lv_color_t recolored_px = lv_color_mix(recolor, *px_color, recolor_opa); + + lv_rpx(col, row, mask_p, recolored_px, LV_OPA_COVER); + } else { + lv_rpx(col, row, mask_p, *px_color, LV_OPA_COVER); + } + + } + map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/ + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h new file mode 100644 index 0000000..b1d62f3 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rbasic..h + * + */ + +#ifndef LV_DRAW_RBASIC_H +#define LV_DRAW_RBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_REAL_DRAW != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color); + + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c new file mode 100644 index 0000000..5b4ef16 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.c @@ -0,0 +1,1435 @@ +/** + * @file lv_draw_rect.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "../lv_misc/lv_circ.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD 5 /*Circle segment greater then this value will be anti-aliased by a non-linear (cos) opacity mapping*/ + +#define SHADOW_OPA_EXTRA_PRECISION 8 /*Calculate with 2^x bigger shadow opacity values to avoid rounding errors*/ +#define SHADOW_BOTTOM_AA_EXTRA_RADIUS 3 /*Add extra radius with LV_SHADOW_BOTTOM to cover anti-aliased corners*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +#if USE_LV_SHADOW && LV_VDB_SIZE +static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); +static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map); +#endif + +static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h); + +#if LV_ANTIALIAS +static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return; + +#if USE_LV_SHADOW && LV_VDB_SIZE + if(style->body.shadow.width != 0) { + lv_draw_shadow(coords, mask, style, opa_scale); + } +#endif + if(style->body.empty == 0 && style->body.opa >= LV_OPA_MIN) { + lv_draw_rect_main_mid(coords, mask, style, opa_scale); + + if(style->body.radius != 0) { + lv_draw_rect_main_corner(coords, mask, style, opa_scale); + } + } + + if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE && style->body.border.opa >= LV_OPA_MIN) { + lv_draw_rect_border_straight(coords, mask, style, opa_scale); + + if(style->body.radius != 0) { + lv_draw_rect_border_corner(coords, mask, style, opa_scale); + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Draw the middle part (rectangular) of a rectangle + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param rects_p pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_color_t mcolor = style->body.main_color; + lv_color_t gcolor = style->body.grad_color; + uint8_t mix; + lv_coord_t height = lv_area_get_height(coords); + lv_coord_t width = lv_area_get_width(coords); + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + + radius = lv_draw_cont_radius_corr(radius, width, height); + + /*If the radius is too big then there is no body*/ + if(radius > height / 2) return; + + lv_area_t work_area; + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + + if(mcolor.full == gcolor.full) { + work_area.y1 = coords->y1 + radius; + work_area.y2 = coords->y2 - radius; + + if(style->body.radius != 0) { +#if LV_ANTIALIAS + work_area.y1 += 2; + work_area.y2 -= 2; +#else + work_area.y1 += 1; + work_area.y2 -= 1; +#endif + } + + fill_fp(&work_area, mask, mcolor, opa); + } else { + lv_coord_t row; + lv_coord_t row_start = coords->y1 + radius; + lv_coord_t row_end = coords->y2 - radius; + lv_color_t act_color; + + if(style->body.radius != 0) { +#if LV_ANTIALIAS + row_start += 2; + row_end -= 2; +#else + row_start += 1; + row_end -= 1; +#endif + } + if(row_start < 0) row_start = 0; + + for(row = row_start; row <= row_end; row ++) { + work_area.y1 = row; + work_area.y2 = row; + mix = (uint32_t)((uint32_t)(coords->y2 - work_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + + fill_fp(&work_area, mask, act_color, opa); + } + } +} +/** + * Draw the top and bottom parts (corners) of a rectangle + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param rects_p pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_color_t mcolor = style->body.main_color; + lv_color_t gcolor = style->body.grad_color; + lv_color_t act_color; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + uint8_t mix; + lv_coord_t height = lv_area_get_height(coords); + lv_coord_t width = lv_area_get_width(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + lv_point_t lt_origo; /*Left Top origo*/ + lv_point_t lb_origo; /*Left Bottom origo*/ + lv_point_t rt_origo; /*Right Top origo*/ + lv_point_t rb_origo; /*Left Bottom origo*/ + + lt_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + lb_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + rt_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + rb_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t edge_top_area; + lv_area_t mid_top_area; + lv_area_t mid_bot_area; + lv_area_t edge_bot_area; + + lv_point_t cir; + lv_coord_t cir_tmp; + lv_circ_init(&cir, &cir_tmp, radius); + + /*Init the areas*/ + lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir), + lb_origo.y + LV_CIRC_OCT4_Y(cir), + rb_origo.x + LV_CIRC_OCT1_X(cir), + rb_origo.y + LV_CIRC_OCT1_Y(cir)); + + lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir), + lb_origo.y + LV_CIRC_OCT3_Y(cir), + rb_origo.x + LV_CIRC_OCT2_X(cir), + rb_origo.y + LV_CIRC_OCT2_Y(cir)); + + lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir), + lt_origo.y + LV_CIRC_OCT5_Y(cir), + rt_origo.x + LV_CIRC_OCT8_X(cir), + rt_origo.y + LV_CIRC_OCT8_Y(cir)); + + lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir), + lt_origo.y + LV_CIRC_OCT6_Y(cir), + rt_origo.x + LV_CIRC_OCT7_X(cir), + rt_origo.y + LV_CIRC_OCT7_Y(cir)); +#if LV_ANTIALIAS + /*Store some internal states for anti-aliasing*/ + lv_coord_t out_y_seg_start = 0; + lv_coord_t out_y_seg_end = 0; + lv_coord_t out_x_last = radius; + + lv_color_t aa_color_hor_top; + lv_color_t aa_color_hor_bottom; + lv_color_t aa_color_ver; +#endif + + while(lv_circ_cont(&cir)) { +#if LV_ANTIALIAS != 0 + /*New step in y on the outter circle*/ + if(out_x_last != cir.x) { + out_y_seg_end = cir.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height; + aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix); + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + } + + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa); + + mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height; + aa_color_ver = lv_color_mix(mcolor, gcolor, mix); + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + + aa_color_ver = lv_color_mix(gcolor, mcolor, mix); + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + } + + out_x_last = cir.x; + out_y_seg_start = out_y_seg_end; + } +#endif + uint8_t edge_top_refr = 0; + uint8_t mid_top_refr = 0; + uint8_t mid_bot_refr = 0; + uint8_t edge_bot_refr = 0; + + /* If a new row coming draw the previous + * The y coordinate can remain the same so wait for a new*/ + if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y) mid_bot_refr = 1; + + if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) edge_bot_refr = 1; + + if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) mid_top_refr = 1; + + if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) edge_top_refr = 1; + + /*Draw the areas which are not disabled*/ + if(edge_top_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_top_area, mask, act_color, opa); + } + + if(mid_top_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_top_area, mask, act_color, opa); + } + + if(mid_bot_refr != 0) { + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_bot_area, mask, act_color, opa); + } + + if(edge_bot_refr != 0) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_bot_area, mask, act_color, opa); + } + + /*Save the current coordinates*/ + lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir), + lb_origo.y + LV_CIRC_OCT4_Y(cir), + rb_origo.x + LV_CIRC_OCT1_X(cir), + rb_origo.y + LV_CIRC_OCT1_Y(cir)); + + lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir), + lb_origo.y + LV_CIRC_OCT3_Y(cir), + rb_origo.x + LV_CIRC_OCT2_X(cir), + rb_origo.y + LV_CIRC_OCT2_Y(cir)); + + lv_area_set(&mid_top_area, lt_origo.x + LV_CIRC_OCT5_X(cir), + lt_origo.y + LV_CIRC_OCT5_Y(cir), + rt_origo.x + LV_CIRC_OCT8_X(cir), + rt_origo.y + LV_CIRC_OCT8_Y(cir)); + + lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir), + lt_origo.y + LV_CIRC_OCT6_Y(cir), + rt_origo.x + LV_CIRC_OCT7_X(cir), + rt_origo.y + LV_CIRC_OCT7_Y(cir)); + + lv_circ_next(&cir, &cir_tmp); + } + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_top_area, mask, act_color, opa); + + if(edge_top_area.y1 != mid_top_area.y1) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_top_area, mask, act_color, opa); + } + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&mid_bot_area, mask, act_color, opa); + + if(edge_bot_area.y1 != mid_bot_area.y1) { + + if(mcolor.full == gcolor.full) act_color = mcolor; + else { + mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height; + act_color = lv_color_mix(mcolor, gcolor, mix); + } + fill_fp(&edge_bot_area, mask, act_color, opa); + } + + +#if LV_ANTIALIAS + /*The first and the last line is not drawn*/ + edge_top_area.x1 = coords->x1 + radius + 2; + edge_top_area.x2 = coords->x2 - radius - 2; + edge_top_area.y1 = coords->y1; + edge_top_area.y2 = coords->y1; + fill_fp(&edge_top_area, mask, style->body.main_color, opa); + + edge_top_area.y1 = coords->y2; + edge_top_area.y2 = coords->y2; + fill_fp(&edge_top_area, mask, style->body.grad_color, opa); + + /*Last parts of the anti-alias*/ + out_y_seg_end = cir.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height; + aa_color_hor_bottom = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_top = lv_color_mix(mcolor, gcolor, mix); + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa); + + mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height; + aa_color_ver = lv_color_mix(mcolor, gcolor, mix); + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa); + + aa_color_ver = lv_color_mix(gcolor, mcolor, mix); + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa); + } + + /*In some cases the last pixel is not drawn*/ + if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) { + aa_p.x = out_x_last; + aa_p.y = out_x_last; + + mix = (uint32_t)((uint32_t)(out_x_last) * 255) / height; + aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix); + aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix); + + lv_opa_t aa_opa = opa >> 1; + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, aa_color_hor_bottom, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, aa_color_hor_bottom, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, aa_color_hor_top, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, aa_color_hor_top, aa_opa); + } + +#endif + + +} + +/** + * Draw the straight parts of a rectangle border + * @param coords the coordinates of the original rectangle + * @param mask_ the rectangle will be drawn only on this area + * @param rstyle pointer to a rectangle style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius; + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + uint16_t bwidth = style->body.border.width; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8; + lv_border_part_t part = style->body.border.part; + lv_color_t color = style->body.border.color; + lv_area_t work_area; + lv_coord_t length_corr = 0; + lv_coord_t corner_size = 0; + + /*the 0 px border width drawn as 1 px, so decrement the b_width*/ + bwidth--; + + radius = lv_draw_cont_radius_corr(radius, width, height); + + if(radius < bwidth) { + length_corr = bwidth - radius - LV_ANTIALIAS; + corner_size = bwidth; + } else { + corner_size = radius + LV_ANTIALIAS; + } + + /*If radius == 0 is a special case*/ + if(style->body.radius == 0) { + /*Left top corner*/ + if(part & LV_BORDER_TOP) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top corner*/ + if(part & LV_BORDER_RIGHT) { + work_area.x1 = coords->x2 - bwidth; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0); + work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0); + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom corner*/ + if(part & LV_BORDER_LEFT) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + bwidth; + work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0); + work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0); + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom corner*/ + if(part & LV_BORDER_BOTTOM) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + return; + } + + /* Modify the corner_size if corner is drawn */ + corner_size ++; + + /*Depending one which part's are drawn modify the area lengths */ + if(part & LV_BORDER_TOP) work_area.y1 = coords->y1 + corner_size; + else work_area.y1 = coords->y1 + radius; + + if(part & LV_BORDER_BOTTOM) work_area.y2 = coords->y2 - corner_size; + else work_area.y2 = coords->y2 - radius; + + /*Left border*/ + if(part & LV_BORDER_LEFT) { + work_area.x1 = coords->x1; + work_area.x2 = work_area.x1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right border*/ + if(part & LV_BORDER_RIGHT) { + work_area.x2 = coords->x2; + work_area.x1 = work_area.x2 - bwidth; + fill_fp(&work_area, mask, color, opa); + } + + work_area.x1 = coords->x1 + corner_size - length_corr; + work_area.x2 = coords->x2 - corner_size + length_corr; + + /*Upper border*/ + if(part & LV_BORDER_TOP) { + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Lower border*/ + if(part & LV_BORDER_BOTTOM) { + work_area.y2 = coords->y2; + work_area.y1 = work_area.y2 - bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Draw the a remaining rectangles if the radius is smaller then bwidth */ + if(length_corr != 0) { + /*Left top correction*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + radius + LV_ANTIALIAS; + work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top correction*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - radius - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS; + work_area.y2 = coords->y1 + bwidth; + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom correction*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + radius + LV_ANTIALIAS; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom correction*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - radius - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - bwidth; + work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + } + + /*If radius == 0 one px on the corners are not drawn by main drawer*/ + if(style->body.radius == 0) { + /*Left top corner*/ + if(part & (LV_BORDER_TOP | LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + LV_ANTIALIAS; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Right top corner*/ + if(part & (LV_BORDER_TOP | LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y1; + work_area.y2 = coords->y1 + LV_ANTIALIAS; + fill_fp(&work_area, mask, color, opa); + } + + /*Left bottom corner*/ + if(part & (LV_BORDER_BOTTOM | LV_BORDER_LEFT)) { + work_area.x1 = coords->x1; + work_area.x2 = coords->x1 + LV_ANTIALIAS; + work_area.y1 = coords->y2 - LV_ANTIALIAS; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + + /*Right bottom corner*/ + if(part & (LV_BORDER_BOTTOM | LV_BORDER_RIGHT)) { + work_area.x1 = coords->x2 - LV_ANTIALIAS; + work_area.x2 = coords->x2; + work_area.y1 = coords->y2 - LV_ANTIALIAS; + work_area.y2 = coords->y2; + fill_fp(&work_area, mask, color, opa); + } + } +} + + +/** + * Draw the corners of a rectangle border + * @param coords the coordinates of the original rectangle + * @param mask the rectangle will be drawn only on this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + uint16_t radius = style->body.radius ; + uint16_t bwidth = style->body.border.width; + lv_color_t color = style->body.border.color; + lv_border_part_t part = style->body.border.part; + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8; + /*0 px border width drawn as 1 px, so decrement the bwidth*/ + bwidth--; + +#if LV_ANTIALIAS + bwidth--; /*Because of anti-aliasing the border seems one pixel ticker*/ +#endif + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + lv_point_t lt_origo; /*Left Top origo*/ + lv_point_t lb_origo; /*Left Bottom origo*/ + lv_point_t rt_origo; /*Right Top origo*/ + lv_point_t rb_origo; /*Left Bottom origo*/ + + lt_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + lb_origo.x = coords->x1 + radius + LV_ANTIALIAS; + lb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + rt_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rt_origo.y = coords->y1 + radius + LV_ANTIALIAS; + + rb_origo.x = coords->x2 - radius - LV_ANTIALIAS; + rb_origo.y = coords->y2 - radius - LV_ANTIALIAS; + + lv_point_t cir_out; + lv_coord_t tmp_out; + lv_circ_init(&cir_out, &tmp_out, radius); + + lv_point_t cir_in; + lv_coord_t tmp_in; + lv_coord_t radius_in = radius - bwidth; + + if(radius_in < 0) { + radius_in = 0; + } + + lv_circ_init(&cir_in, &tmp_in, radius_in); + + lv_area_t circ_area; + lv_coord_t act_w1; + lv_coord_t act_w2; + +#if LV_ANTIALIAS + /*Store some internal states for anti-aliasing*/ + lv_coord_t out_y_seg_start = 0; + lv_coord_t out_y_seg_end = 0; + lv_coord_t out_x_last = radius; + + + lv_coord_t in_y_seg_start = 0; + lv_coord_t in_y_seg_end = 0; + lv_coord_t in_x_last = radius - bwidth; +#endif + + while(cir_out.y <= cir_out.x) { + + /*Calculate the actual width to avoid overwriting pixels*/ + if(cir_in.y < cir_in.x) { + act_w1 = cir_out.x - cir_in.x; + act_w2 = act_w1; + } else { + act_w1 = cir_out.x - cir_out.y; + act_w2 = act_w1 - 1; + } + +#if LV_ANTIALIAS != 0 + /*New step in y on the outter circle*/ + if(out_x_last != cir_out.x) { + out_y_seg_end = cir_out.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + out_x_last = cir_out.x; + out_y_seg_start = out_y_seg_end; + } + + /*New step in y on the inner circle*/ + if(in_x_last != cir_in.x) { + in_y_seg_end = cir_out.y; + lv_coord_t seg_size = in_y_seg_end - in_y_seg_start; + lv_point_t aa_p; + + aa_p.x = in_x_last; + aa_p.y = in_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa; + + if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/ + aa_opa = opa - antialias_get_opa_circ(seg_size, i, opa); + } else { + aa_opa = lv_draw_aa_get_opa(seg_size, i, opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + /*Be sure the pixels on the middle are not drawn twice*/ + if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) { + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + } + + in_x_last = cir_in.x; + in_y_seg_start = in_y_seg_end; + + } + +#endif + + + /*Draw the octets to the right bottom corner*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + circ_area.x1 = rb_origo.x + LV_CIRC_OCT1_X(cir_out) - act_w2; + circ_area.x2 = rb_origo.x + LV_CIRC_OCT1_X(cir_out); + circ_area.y1 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out); + circ_area.y2 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + + circ_area.x1 = rb_origo.x + LV_CIRC_OCT2_X(cir_out); + circ_area.x2 = rb_origo.x + LV_CIRC_OCT2_X(cir_out); + circ_area.y1 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out) - act_w1; + circ_area.y2 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the left bottom corner*/ + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + circ_area.x1 = lb_origo.x + LV_CIRC_OCT3_X(cir_out); + circ_area.x2 = lb_origo.x + LV_CIRC_OCT3_X(cir_out); + circ_area.y1 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out) - act_w2; + circ_area.y2 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + + circ_area.x1 = lb_origo.x + LV_CIRC_OCT4_X(cir_out); + circ_area.x2 = lb_origo.x + LV_CIRC_OCT4_X(cir_out) + act_w1; + circ_area.y1 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out); + circ_area.y2 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the left top corner*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + if(lb_origo.y + LV_CIRC_OCT4_Y(cir_out) > lt_origo.y + LV_CIRC_OCT5_Y(cir_out)) { + /*Don't draw if the lines are common in the middle*/ + circ_area.x1 = lt_origo.x + LV_CIRC_OCT5_X(cir_out); + circ_area.x2 = lt_origo.x + LV_CIRC_OCT5_X(cir_out) + act_w2; + circ_area.y1 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out); + circ_area.y2 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + + circ_area.x1 = lt_origo.x + LV_CIRC_OCT6_X(cir_out); + circ_area.x2 = lt_origo.x + LV_CIRC_OCT6_X(cir_out); + circ_area.y1 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out); + circ_area.y2 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out) + act_w1; + fill_fp(&circ_area, mask, color, opa); + } + + /*Draw the octets to the right top corner*/ + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + circ_area.x1 = rt_origo.x + LV_CIRC_OCT7_X(cir_out); + circ_area.x2 = rt_origo.x + LV_CIRC_OCT7_X(cir_out); + circ_area.y1 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out); + circ_area.y2 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out) + act_w2; + fill_fp(&circ_area, mask, color, opa); + + /*Don't draw if the lines are common in the middle*/ + if(rb_origo.y + LV_CIRC_OCT1_Y(cir_out) > rt_origo.y + LV_CIRC_OCT8_Y(cir_out)) { + circ_area.x1 = rt_origo.x + LV_CIRC_OCT8_X(cir_out) - act_w1; + circ_area.x2 = rt_origo.x + LV_CIRC_OCT8_X(cir_out); + circ_area.y1 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out); + circ_area.y2 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out); + fill_fp(&circ_area, mask, color, opa); + } + } + lv_circ_next(&cir_out, &tmp_out); + + /*The internal circle will be ready faster + * so check it! */ + if(cir_in.y < cir_in.x) { + lv_circ_next(&cir_in, &tmp_in); + } + } + + +#if LV_ANTIALIAS != 0 + + /*Last parts of the outer anti-alias*/ + out_y_seg_end = cir_out.y; + lv_coord_t seg_size = out_y_seg_end - out_y_seg_start; + lv_point_t aa_p; + + aa_p.x = out_x_last; + aa_p.y = out_y_seg_start; + + lv_coord_t i; + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa); + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + + /*In some cases the last pixel in the outer middle is not drawn*/ + if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) { + aa_p.x = out_x_last; + aa_p.y = out_x_last; + + lv_opa_t aa_opa = opa >> 1; + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, style->body.border.color, aa_opa); + } + } + + /*Last parts of the inner anti-alias*/ + in_y_seg_end = cir_in.y; + aa_p.x = in_x_last; + aa_p.y = in_y_seg_start; + seg_size = in_y_seg_end - in_y_seg_start; + + for(i = 0; i < seg_size; i++) { + lv_opa_t aa_opa = lv_draw_aa_get_opa(seg_size, i, opa); + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) { + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) { + px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) { + px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) { + px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa); + } + + if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) { + px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa); + } + } + } + +#endif + +} + +#if USE_LV_SHADOW && LV_VDB_SIZE + +/** + * Draw a shadow + * @param rect pointer to rectangle object + * @param mask pointer to a mask area (from the design functions) + * @param opa_scale scale down all opacities by the factor + */ +static void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + /* If mask is in the middle of cords do not draw shadow*/ + lv_coord_t radius = style->body.radius; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + radius = lv_draw_cont_radius_corr(radius, width, height); + lv_area_t area_tmp; + + /*Check horizontally without radius*/ + lv_area_copy(&area_tmp, coords); + area_tmp.x1 += radius; + area_tmp.x2 -= radius; + if(lv_area_is_in(mask, &area_tmp) != false) return; + + /*Check vertically without radius*/ + lv_area_copy(&area_tmp, coords); + area_tmp.y1 += radius; + area_tmp.y2 -= radius; + if(lv_area_is_in(mask, &area_tmp) != false) return; + + if(style->body.shadow.type == LV_SHADOW_FULL) { + lv_draw_shadow_full(coords, mask, style, opa_scale); + } else if(style->body.shadow.type == LV_SHADOW_BOTTOM) { + lv_draw_shadow_bottom(coords, mask, style, opa_scale); + } +} + +static void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + + /* KNOWN ISSUE + * The algorithm calculates the shadow only above the middle point of the radius (speaking about the left top corner). + * It causes an error because it doesn't consider how long the straight edge is which effects the value of bottom of the corner shadow. + * In addition the straight shadow is drawn from the middles point of the radius however + * the ends of the straight parts still should be effected by the corner shadow. + * It also causes an issue in opacity. A smaller radius means smaller average shadow opacity. + * The solution should be to start `line` from `- swidth` and handle if the straight part is short (or zero) and the value is taken from + * the other corner. `col` also should start from `- swidth` + */ + + + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width; + + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + + radius += LV_ANTIALIAS; + +#if LV_COMPILER_VLA_SUPPORTED + lv_coord_t curve_x[radius + swidth + 1]; /*Stores the 'x' coordinates of a quarter circle.*/ +#else +# if LV_HOR_RES > LV_VER_RES + lv_coord_t curve_x[LV_HOR_RES]; +# else + lv_coord_t curve_x[LV_VER_RES]; +# endif +#endif + memset(curve_x, 0, sizeof(curve_x)); + lv_point_t circ; + lv_coord_t circ_tmp; + lv_circ_init(&circ, &circ_tmp, radius); + while(lv_circ_cont(&circ)) { + curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ); + curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ); + lv_circ_next(&circ, &circ_tmp); + } + int16_t line; + + int16_t filter_width = 2 * swidth + 1; +#if LV_COMPILER_VLA_SUPPORTED + uint32_t line_1d_blur[filter_width]; +#else +# if LV_HOR_RES > LV_VER_RES + uint32_t line_1d_blur[LV_HOR_RES]; +# else + uint32_t line_1d_blur[LV_VER_RES]; +# endif +#endif + /*1D Blur horizontally*/ + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + for(line = 0; line < filter_width; line++) { + line_1d_blur[line] = (uint32_t)((uint32_t)(filter_width - line) * (opa * 2) << SHADOW_OPA_EXTRA_PRECISION) / (filter_width * filter_width); + } + + uint16_t col; +#if LV_COMPILER_VLA_SUPPORTED + lv_opa_t line_2d_blur[radius + swidth + 1]; +#else +# if LV_HOR_RES > LV_VER_RES + lv_opa_t line_2d_blur[LV_HOR_RES]; +# else + lv_opa_t line_2d_blur[LV_VER_RES]; +# endif +#endif + + lv_point_t point_rt; + lv_point_t point_rb; + lv_point_t point_lt; + lv_point_t point_lb; + lv_point_t ofs_rb; + lv_point_t ofs_rt; + lv_point_t ofs_lb; + lv_point_t ofs_lt; + ofs_rb.x = coords->x2 - radius - LV_ANTIALIAS; + ofs_rb.y = coords->y2 - radius - LV_ANTIALIAS; + + ofs_rt.x = coords->x2 - radius - LV_ANTIALIAS; + ofs_rt.y = coords->y1 + radius + LV_ANTIALIAS; + + ofs_lb.x = coords->x1 + radius + LV_ANTIALIAS; + ofs_lb.y = coords->y2 - radius - LV_ANTIALIAS; + + ofs_lt.x = coords->x1 + radius + LV_ANTIALIAS; + ofs_lt.y = coords->y1 + radius + LV_ANTIALIAS; + bool line_ready; + for(line = 0; line <= radius + swidth; line++) { /*Check all rows and make the 1D blur to 2D*/ + line_ready = false; + for(col = 0; col <= radius + swidth; col++) { /*Check all pixels in a 1D blur line (from the origo to last shadow pixel (radius + swidth))*/ + + /*Sum the opacities from the lines above and below this 'row'*/ + int16_t line_rel; + uint32_t px_opa_sum = 0; + for(line_rel = -swidth; line_rel <= swidth; line_rel ++) { + /*Get the relative x position of the 'line_rel' to 'line'*/ + int16_t col_rel; + if(line + line_rel < 0) { /*Below the radius, here is the blur of the edge */ + col_rel = radius - curve_x[line] - col; + } else if(line + line_rel > radius) { /*Above the radius, here won't be more 1D blur*/ + break; + } else { /*Blur from the curve*/ + col_rel = curve_x[line + line_rel] - curve_x[line] - col; + } + + /*Add the value of the 1D blur on 'col_rel' position*/ + if(col_rel < -swidth) { /*Outside of the blurred area. */ + if(line_rel == -swidth) line_ready = true; /*If no data even on the very first line then it wont't be anything else in this line*/ + break; /*Break anyway because only smaller 'col_rel' values will come */ + } else if(col_rel > swidth) px_opa_sum += line_1d_blur[0]; /*Inside the not blurred area*/ + else px_opa_sum += line_1d_blur[swidth - col_rel]; /*On the 1D blur (+ swidth to align to the center)*/ + } + + line_2d_blur[col] = px_opa_sum >> SHADOW_OPA_EXTRA_PRECISION; + if(line_ready) { + col++; /*To make this line to the last one ( drawing will go to '< col')*/ + break; + } + + } + + /*Flush the line*/ + point_rt.x = curve_x[line] + ofs_rt.x + 1; + point_rt.y = ofs_rt.y - line; + + point_rb.x = curve_x[line] + ofs_rb.x + 1; + point_rb.y = ofs_rb.y + line; + + point_lt.x = ofs_lt.x - curve_x[line] - 1; + point_lt.y = ofs_lt.y - line; + + point_lb.x = ofs_lb.x - curve_x[line] - 1; + point_lb.y = ofs_lb.y + line; + + uint16_t d; + for(d = 1; d < col; d++) { + + if(point_lt.x < ofs_lt.x && point_lt.y < ofs_lt.y) { + px_fp(point_lt.x, point_lt.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_lb.x < ofs_lb.x && point_lb.y > ofs_lb.y) { + px_fp(point_lb.x, point_lb.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_rt.x > ofs_rt.x && point_rt.y < ofs_rt.y) { + px_fp(point_rt.x, point_rt.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + if(point_rb.x > ofs_rb.x && point_rb.y > ofs_rb.y) { + px_fp(point_rb.x, point_rb.y, mask, style->body.shadow.color, line_2d_blur[d]); + } + + point_rb.x++; + point_lb.x--; + + point_rt.x++; + point_lt.x--; + } + + /* Put the first line to the edges too. + * It is not correct because blur should be done below the corner too + * but is is simple, fast and gives a good enough result*/ + if(line == 0) lv_draw_shadow_full_straight(coords, mask, style, line_2d_blur); + } +} + + +static void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +{ + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + radius += LV_ANTIALIAS * SHADOW_BOTTOM_AA_EXTRA_RADIUS; + swidth += LV_ANTIALIAS; +#if LV_COMPILER_VLA_SUPPORTED + lv_coord_t curve_x[radius + 1]; /*Stores the 'x' coordinates of a quarter circle.*/ +#else +# if LV_HOR_RES > LV_VER_RES + lv_coord_t curve_x[LV_HOR_RES]; +# else + lv_coord_t curve_x[LV_VER_RES]; +# endif +#endif + lv_point_t circ; + lv_coord_t circ_tmp; + lv_circ_init(&circ, &circ_tmp, radius); + while(lv_circ_cont(&circ)) { + curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ); + curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ); + lv_circ_next(&circ, &circ_tmp); + } + + int16_t col; +#if LV_COMPILER_VLA_SUPPORTED + lv_opa_t line_1d_blur[swidth]; +#else +# if LV_HOR_RES > LV_VER_RES + lv_opa_t line_1d_blur[LV_HOR_RES]; +# else + lv_opa_t line_1d_blur[LV_VER_RES]; +# endif +#endif + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8; + for(col = 0; col < swidth; col++) { + line_1d_blur[col] = (uint32_t)((uint32_t)(swidth - col) * opa / 2) / (swidth); + } + + lv_point_t point_l; + lv_point_t point_r; + lv_area_t area_mid; + lv_point_t ofs_l; + lv_point_t ofs_r; + + ofs_l.x = coords->x1 + radius; + ofs_l.y = coords->y2 - radius + 1 - LV_ANTIALIAS; + + ofs_r.x = coords->x2 - radius; + ofs_r.y = coords->y2 - radius + 1 - LV_ANTIALIAS; + + for(col = 0; col <= radius; col++) { + point_l.x = ofs_l.x - col ; + point_l.y = ofs_l.y + curve_x[col]; + + point_r.x = ofs_r.x + col; + point_r.y = ofs_r.y + curve_x[col]; + + lv_opa_t px_opa; + int16_t diff = col == 0 ? 0 : curve_x[col - 1] - curve_x[col]; + uint16_t d; + for(d = 0; d < swidth; d++) { + /*When stepping a pixel in y calculate the average with the pixel from the prev. column to make a blur */ + if(diff == 0) { + px_opa = line_1d_blur[d]; + } else { + px_opa = (uint16_t)((uint16_t)line_1d_blur[d] + line_1d_blur[d - diff]) >> 1; + } + px_fp(point_l.x, point_l.y, mask, style->body.shadow.color, px_opa); + point_l.y ++; + + /*Don't overdraw the pixel on the middle*/ + if(point_r.x > ofs_l.x) { + px_fp(point_r.x, point_r.y, mask, style->body.shadow.color, px_opa); + } + point_r.y ++; + } + + } + + area_mid.x1 = ofs_l.x + 1; + area_mid.y1 = ofs_l.y + radius; + area_mid.x2 = ofs_r.x - 1; + area_mid.y2 = area_mid.y1; + + uint16_t d; + for(d = 0; d < swidth; d++) { + fill_fp(&area_mid, mask, style->body.shadow.color, line_1d_blur[d]); + area_mid.y1 ++; + area_mid.y2 ++; + } +} + +static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map) +{ + lv_coord_t radius = style->body.radius; + lv_coord_t swidth = style->body.shadow.width;// + LV_ANTIALIAS; + lv_coord_t width = lv_area_get_width(coords); + lv_coord_t height = lv_area_get_height(coords); + + radius = lv_draw_cont_radius_corr(radius, width, height); + radius += LV_ANTIALIAS; + + lv_area_t right_area; + right_area.x1 = coords->x2 + 1 - LV_ANTIALIAS; + right_area.y1 = coords->y1 + radius + LV_ANTIALIAS; + right_area.x2 = right_area.x1; + right_area.y2 = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t left_area; + left_area.x1 = coords->x1 - 1 + LV_ANTIALIAS; + left_area.y1 = coords->y1 + radius + LV_ANTIALIAS; + left_area.x2 = left_area.x1; + left_area.y2 = coords->y2 - radius - LV_ANTIALIAS; + + lv_area_t top_area; + top_area.x1 = coords->x1 + radius + LV_ANTIALIAS; + top_area.y1 = coords->y1 - 1 + LV_ANTIALIAS; + top_area.x2 = coords->x2 - radius - LV_ANTIALIAS; + top_area.y2 = top_area.y1; + + lv_area_t bottom_area; + bottom_area.x1 = coords->x1 + radius + LV_ANTIALIAS; + bottom_area.y1 = coords->y2 + 1 - LV_ANTIALIAS; + bottom_area.x2 = coords->x2 - radius - LV_ANTIALIAS; + bottom_area.y2 = bottom_area.y1; + + lv_opa_t opa_act; + int16_t d; + for(d = 1 /*+ LV_ANTIALIAS*/; d <= swidth/* - LV_ANTIALIAS*/; d++) { + opa_act = map[d]; + + fill_fp(&right_area, mask, style->body.shadow.color, opa_act); + right_area.x1++; + right_area.x2++; + + fill_fp(&left_area, mask, style->body.shadow.color, opa_act); + left_area.x1--; + left_area.x2--; + + fill_fp(&top_area, mask, style->body.shadow.color, opa_act); + top_area.y1--; + top_area.y2--; + + fill_fp(&bottom_area, mask, style->body.shadow.color, opa_act); + bottom_area.y1++; + bottom_area.y2++; + } +} + +#endif + + +static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h) +{ + if(r >= (w >> 1)) { + r = (w >> 1); + if(r != 0) r--; + } + if(r >= (h >> 1)) { + r = (h >> 1); + if(r != 0) r--; + } + + if(r > 0) r -= LV_ANTIALIAS; + + return r; +} + +#if LV_ANTIALIAS + +/** + * Approximate the opacity for anti-aliasing. + * Used the first segment of a circle which is the longest and have the most non-linearity (cos) + * @param seg length of the line segment + * @param px_id index of pixel on the line segment + * @param line_opa opacity of the lien (it will be the max opacity) + * @return the desired opacity of the pixel + */ +static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa) +{ + static const lv_opa_t opa_map[8] = {250, 242, 221, 196, 163, 122, 74, 18}; + + if(seg == 0) return LV_OPA_TRANSP; + else if(seg == 1) return LV_OPA_80; + else { + + uint8_t id = (uint32_t)((uint32_t)px_id * (sizeof(opa_map) - 1)) / (seg - 1); + return (uint32_t)((uint32_t) opa_map[id] * opa) >> 8; + + } + +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h new file mode 100644 index 0000000..933590c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_rect.h @@ -0,0 +1,48 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c new file mode 100644 index 0000000..84c9d3f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.c @@ -0,0 +1,168 @@ +/** + * @file lv_draw_triangle.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_triangle.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static void point_swap(lv_point_t * p1, lv_point_t * p2); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color) +{ + lv_point_t tri[3]; + + memcpy(tri, points, sizeof(tri)); + + /*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/ + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]); + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + + /*Return is the triangle is degenerated*/ + if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return; + if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return; + if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return; + + if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return; + if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return; + + /*Draw the triangle*/ + lv_point_t edge1; + lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x); + lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1; + lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y); + lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1; + lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + lv_coord_t err_tmp1; + + lv_point_t edge2; + lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x); + lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1; + lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y); + lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1; + lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2; + lv_coord_t err_tmp2; + + lv_coord_t y1_tmp; + lv_coord_t y2_tmp; + + edge1.x = tri[0].x; + edge1.y = tri[0].y; + edge2.x = tri[0].x; + edge2.y = tri[0].y; + lv_area_t act_area; + lv_area_t draw_area; + + while(1) { + act_area.x1 = edge1.x; + act_area.x2 = edge2.x ; + act_area.y1 = edge1.y; + act_area.y2 = edge2.y ; + + + draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); + draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); + draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); + draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); + draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/ + fill_fp(&draw_area, mask, color, LV_OPA_50); + + /*Calc. the next point of edge1*/ + y1_tmp = edge1.y; + do { + if(edge1.x == tri[1].x && edge1.y == tri[1].y) { + + dx1 = LV_MATH_ABS(tri[1].x - tri[2].x); + sx1 = tri[1].x < tri[2].x ? 1 : -1; + dy1 = LV_MATH_ABS(tri[1].y - tri[2].y); + sy1 = tri[1].y < tri[2].y ? 1 : -1; + err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + } else if(edge1.x == tri[2].x && edge1.y == tri[2].y) return; + err_tmp1 = err1; + if(err_tmp1 > -dx1) { + err1 -= dy1; + edge1.x += sx1; + } + if(err_tmp1 < dy1) { + err1 += dx1; + edge1.y += sy1; + } + } while(edge1.y == y1_tmp); + + /*Calc. the next point of edge2*/ + y2_tmp = edge2.y; + do { + if(edge2.x == tri[2].x && edge2.y == tri[2].y) return; + err_tmp2 = err2; + if(err_tmp2 > -dx2) { + err2 -= dy2; + edge2.x += sx2; + } + if(err_tmp2 < dy2) { + err2 += dx2; + edge2.y += sy2; + } + } while(edge2.y == y2_tmp); + } +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + + +#if USE_LV_TRIANGLE != 0 +/** + * Swap two points + * p1 pointer to the first point + * p2 pointer to the second point + */ +static void point_swap(lv_point_t * p1, lv_point_t * p2) +{ + lv_point_t tmp; + tmp.x = p1->x; + tmp.y = p1->y; + + p1->x = p2->x; + p1->y = p2->y; + + p2->x = tmp.x; + p2->y = tmp.y; + +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h new file mode 100644 index 0000000..c3c6208 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c new file mode 100644 index 0000000..ebe5f57 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c @@ -0,0 +1,691 @@ +/** + * @file lv_vdraw.c + * + */ + +#include "lv_draw_vbasic.h" + +#include +#include + +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_log.h" + +#if LV_VDB_SIZE != 0 + +#include +#include "../lv_core/lv_vdb.h" +#include "lv_draw.h" + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ +#define VFILL_HW_ACC_SIZE_LIMIT 50 /*Always fill < 50 px with 'sw_color_fill' because of the hw. init overhead*/ + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); +static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa); + +#if LV_COLOR_SCREEN_TRANSP +static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Put a pixel in the Virtual Display Buffer + * @param x pixel x coordinate + * @param y pixel y coordinate + * @param mask_p fill only on this mask (truncated to VDB area) + * @param color pixel color + * @param opa opacity of the area (0..255) + */ +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa) +{ + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Pixel out of the mask*/ + if(x < mask_p->x1 || x > mask_p->x2 || + y < mask_p->y1 || y > mask_p->y2) { + return; + } + + uint32_t vdb_width = lv_area_get_width(&vdb_p->area); + + /*Make the coordinates relative to VDB*/ + x -= vdb_p->area.x1; + y -= vdb_p->area.y1; + + lv_disp_t * disp = lv_disp_get_active(); + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, x, y, color, opa); + } else { + lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x; +#if LV_COLOR_SCREEN_TRANSP == 0 + if(opa == LV_OPA_COVER) { + *vdb_px_p = color; + } else { + *vdb_px_p = lv_color_mix(color, *vdb_px_p, opa); + } +#else + *vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).alpha, color, opa); +#endif + } +} + + +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask (truncated to VDB area) + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa) +{ + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_area_t res_a; + bool union_ok; + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Get the union of cord and mask*/ + /* The mask is already truncated to the vdb size + * in 'lv_refr_area_with_vdb' function */ + union_ok = lv_area_intersect(&res_a, cords_p, mask_p); + + /*If there are common part of the three area then draw to the vdb*/ + if(union_ok == false) return; + + lv_area_t vdb_rel_a; /*Stores relative coordinates on vdb*/ + vdb_rel_a.x1 = res_a.x1 - vdb_p->area.x1; + vdb_rel_a.y1 = res_a.y1 - vdb_p->area.y1; + vdb_rel_a.x2 = res_a.x2 - vdb_p->area.x1; + vdb_rel_a.y2 = res_a.y2 - vdb_p->area.y1; + + lv_color_t * vdb_buf_tmp = vdb_p->buf; + uint32_t vdb_width = lv_area_get_width(&vdb_p->area); + /*Move the vdb_tmp to the first row*/ + vdb_buf_tmp += vdb_width * vdb_rel_a.y1; + + +#if USE_LV_GPU + static LV_ATTRIBUTE_MEM_ALIGN lv_color_t color_array_tmp[LV_HOR_RES]; /*Used by 'lv_disp_mem_blend'*/ + static lv_coord_t last_width = -1; + + lv_coord_t w = lv_area_get_width(&vdb_rel_a); + /*Don't use hw. acc. for every small fill (because of the init overhead)*/ + if(w < VFILL_HW_ACC_SIZE_LIMIT) { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + /*Not opaque fill*/ + else if(opa == LV_OPA_COVER) { + /*Use hw fill if present*/ + if(lv_disp_is_mem_fill_supported()) { + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_fill(&vdb_buf_tmp[vdb_rel_a.x1], w, color); + vdb_buf_tmp += vdb_width; + } + } + /*Use hw blend if present and the area is not too small*/ + else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT && + lv_disp_is_mem_blend_supported()) { + /*Fill a one line sized buffer with a color and blend this later*/ + if(color_array_tmp[0].full != color.full || last_width != w) { + uint16_t i; + for(i = 0; i < w; i++) { + color_array_tmp[i].full = color.full; + } + last_width = w; + } + + /*Blend the filled line to every line VDB line-by-line*/ + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa); + vdb_buf_tmp += vdb_width; + } + + } + /*Else use sw fill if no better option*/ + else { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + + } + /*Fill with opacity*/ + else { + /*Use hw blend if present*/ + if(lv_disp_is_mem_blend_supported()) { + if(color_array_tmp[0].full != color.full || last_width != w) { + uint16_t i; + for(i = 0; i < w; i++) { + color_array_tmp[i].full = color.full; + } + + last_width = w; + } + lv_coord_t row; + for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) { + lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa); + vdb_buf_tmp += vdb_width; + } + + } + /*Use sw fill with opa if no better option*/ + else { + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); + } + + } +#else + sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa); +#endif +} + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area (truncated to VDB area) + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa) +{ + const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255 + }; + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + if(font_p == NULL) { + LV_LOG_WARN("Font: character's bitmap not found"); + return; + } + + lv_coord_t pos_x = pos_p->x; + lv_coord_t pos_y = pos_p->y; + uint8_t letter_w = lv_font_get_real_width(font_p, letter); + uint8_t letter_h = lv_font_get_height(font_p); + uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/ + const uint8_t * bpp_opa_table; + uint8_t mask_init; + uint8_t mask; + + if(lv_font_is_monospace(font_p, letter)) { + pos_x += (lv_font_get_width(font_p, letter) - letter_w) / 2; + } + + + switch(bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + mask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + mask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + mask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + mask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + return; /*Invalid bpp. Can't render the letter*/ + } + + const uint8_t * map_p = lv_font_get_bitmap(font_p, letter); + + if(map_p == NULL) return; + + /*If the letter is completely out of mask don't draw it */ + if(pos_x + letter_w < mask_p->x1 || pos_x > mask_p->x2 || + pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return; + + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area); + lv_color_t * vdb_buf_tmp = vdb_p->buf; + lv_coord_t col, row; + uint8_t col_bit; + uint8_t col_byte_cnt; + uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(letter_w & 0x7) width_byte_scr++; + uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/ + if((letter_w * bpp) & 0x7) width_byte_bpp++; + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x; + lv_coord_t col_end = pos_x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_x + 1; + lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y; + lv_coord_t row_end = pos_y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_y + 1; + + /*Set a pointer on VDB to the first pixel of the letter*/ + vdb_buf_tmp += ((pos_y - vdb_p->area.y1) * vdb_width) + + pos_x - vdb_p->area.x1; + + /*If the letter is partially out of mask the move there on VDB*/ + vdb_buf_tmp += (row_start * vdb_width) + col_start; + + /*Move on the map too*/ + map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3); + + lv_disp_t * disp = lv_disp_get_active(); + + uint8_t letter_px; + lv_opa_t px_opa; + for(row = row_start; row < row_end; row ++) { + col_byte_cnt = 0; + col_bit = (col_start * bpp) % 8; + mask = mask_init >> col_bit; + for(col = col_start; col < col_end; col ++) { + letter_px = (*map_p & mask) >> (8 - col_bit - bpp); + if(letter_px != 0) { + if(opa == LV_OPA_COVER) { + px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px]; + } else { + px_opa = bpp == 8 ? + (uint16_t)((uint16_t)letter_px * opa) >> 8 : + (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; + } + + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, + (col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->area.y1, + color, px_opa); + } else { +#if LV_COLOR_SCREEN_TRANSP == 0 + *vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa); +#else + *vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa); +#endif + } + } + + vdb_buf_tmp++; + + if(col_bit < 8 - bpp) { + col_bit += bpp; + mask = mask >> bpp; + } else { + col_bit = 0; + col_byte_cnt ++; + mask = mask_init; + map_p ++; + } + } + + map_p += (width_byte_bpp) - col_byte_cnt; + vdb_buf_tmp += vdb_width - (col_end - col_start); /*Next row in VDB*/ + } +} + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa) +{ + + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + lv_area_t masked_a; + bool union_ok; + lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + + /*Get the union of map size and mask*/ + /* The mask is already truncated to the vdb size + * in 'lv_refr_area_with_vdb' function */ + union_ok = lv_area_intersect(&masked_a, cords_p, mask_p); + + /*If there are common part of the three area then draw to the vdb*/ + if(union_ok == false) return; + + /*The pixel size in byte is different if an alpha byte is added too*/ + uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t); + + /*If the map starts OUT of the masked area then calc. the first pixel*/ + lv_coord_t map_width = lv_area_get_width(cords_p); + if(cords_p->y1 < masked_a.y1) { + map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1)) * px_size_byte; + } + if(cords_p->x1 < masked_a.x1) { + map_p += (masked_a.x1 - cords_p->x1) * px_size_byte; + } + + /*Stores coordinates relative to the current VDB*/ + masked_a.x1 = masked_a.x1 - vdb_p->area.x1; + masked_a.y1 = masked_a.y1 - vdb_p->area.y1; + masked_a.x2 = masked_a.x2 - vdb_p->area.x1; + masked_a.y2 = masked_a.y2 - vdb_p->area.y1; + + lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area); + lv_color_t * vdb_buf_tmp = vdb_p->buf; + vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/ + vdb_buf_tmp += (uint32_t) masked_a.x1; /*Move to the first col*/ + + lv_coord_t row; + lv_coord_t map_useful_w = lv_area_get_width(&masked_a); + + lv_disp_t * disp = lv_disp_get_active(); + + /*The simplest case just copy the pixels into the VDB*/ + if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) { + + /*Use the custom VDB write function is exists*/ + if(disp->driver.vdb_wr) { + lv_coord_t col; + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = 0; col < map_useful_w; col++) { + lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]); + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa); + } + map_p += map_width * px_size_byte; /*Next row on the map*/ + } + } + /*Normal native VDB*/ + else { + for(row = masked_a.y1; row <= masked_a.y2; row++) { +#if USE_LV_GPU + if(lv_disp_is_mem_blend_supported() == false) { + sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); + } else { + lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); + } +#else + sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa); +#endif + map_p += map_width * px_size_byte; /*Next row on the map*/ + vdb_buf_tmp += vdb_width; /*Next row on the VDB*/ + } + } + } + + /*In the other cases every pixel need to be checked one-by-one*/ + else { + lv_color_t chroma_key_color = LV_COLOR_TRANSP; + lv_coord_t col; + lv_color_t last_img_px = LV_COLOR_BLACK; + lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa); + for(row = masked_a.y1; row <= masked_a.y2; row++) { + for(col = 0; col < map_useful_w; col++) { + lv_opa_t opa_result = opa; + uint8_t * px_color_p = (uint8_t *) &map_p[(uint32_t)col * px_size_byte]; + lv_color_t px_color; + + /*Calculate with the pixel level alpha*/ + if(alpha_byte) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + px_color.full = px_color_p[0]; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + px_color.full = px_color_p[0] + (px_color_p[1] << 8); +#elif LV_COLOR_DEPTH == 32 + px_color = *((lv_color_t *)px_color_p); +#endif + lv_opa_t px_opa = *(px_color_p + LV_IMG_PX_SIZE_ALPHA_BYTE - 1); + if(px_opa == LV_OPA_TRANSP) continue; + else if(px_opa != LV_OPA_COVER) opa_result = (uint32_t)((uint32_t)px_opa * opa_result) >> 8; + } else { + px_color = *((lv_color_t *)px_color_p); + } + + /*Handle chroma key*/ + if(chroma_key && px_color.full == chroma_key_color.full) continue; + + /*Re-color the pixel if required*/ + if(recolor_opa != LV_OPA_TRANSP) { + if(last_img_px.full != px_color.full) { /*Minor acceleration: calculate only for new colors (save the last)*/ + last_img_px = px_color; + recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa); + } + /*Handle custom VDB write is present*/ + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, recolored_px, opa_result); + } + /*Normal native VDB write*/ + else { + if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full; + else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result); + } + } else { + /*Handle custom VDB write is present*/ + if(disp->driver.vdb_wr) { + disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa_result); + } + /*Normal native VDB write*/ + else { + if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color; + else { +#if LV_COLOR_SCREEN_TRANSP == 0 + vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result); +#else + vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].alpha, px_color, opa_result); +#endif + } + } + } + } + + map_p += map_width * px_size_byte; /*Next row on the map*/ + vdb_buf_tmp += vdb_width; /*Next row on the VDB*/ + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Blend pixels to destination memory using opacity + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa) +{ + if(opa == LV_OPA_COVER) { + memcpy(dest, src, length * sizeof(lv_color_t)); + } else { + uint32_t col; + for(col = 0; col < length; col++) { + dest[col] = lv_color_mix(src[col], dest[col], opa); + } + } +} + +/** + * + * @param mem_area coordinates of 'mem' memory area + * @param mem a memory address. Considered to a rectangular window according to 'mem_area' + * @param fill_area coordinates of an area to fill. Relative to 'mem_area'. + * @param color fill color + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa) +{ + /*Set all row in vdb to the given color*/ + lv_coord_t row; + lv_coord_t col; + lv_coord_t mem_width = lv_area_get_width(mem_area); + + lv_disp_t * disp = lv_disp_get_active(); + if(disp->driver.vdb_wr) { + for(col = fill_area->x1; col <= fill_area->x2; col++) { + for(row = fill_area->y1; row <= fill_area->y2; row++) { + disp->driver.vdb_wr((uint8_t *)mem, mem_width, col, row, color, opa); + } + } + } else { + mem += fill_area->y1 * mem_width; /*Go to the first row*/ + + /*Run simpler function without opacity*/ + if(opa == LV_OPA_COVER) { + + /*Fill the first row with 'color'*/ + for(col = fill_area->x1; col <= fill_area->x2; col++) { + mem[col] = color; + } + + /*Copy the first row to all other rows*/ + lv_color_t * mem_first = &mem[fill_area->x1]; + lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t); + mem += mem_width; + + for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) { + memcpy(&mem[fill_area->x1], mem_first, copy_size); + mem += mem_width; + } + } + /*Calculate with alpha too*/ + else { + +#if LV_COLOR_SCREEN_TRANSP == 0 + lv_color_t bg_tmp = LV_COLOR_BLACK; + lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa); +#endif + for(row = fill_area->y1; row <= fill_area->y2; row++) { + for(col = fill_area->x1; col <= fill_area->x2; col++) { +#if LV_COLOR_SCREEN_TRANSP == 0 + /*If the bg color changed recalculate the result color*/ + if(mem[col].full != bg_tmp.full) { + bg_tmp = mem[col]; + opa_tmp = lv_color_mix(color, bg_tmp, opa); + } + + mem[col] = opa_tmp; + +#else + mem[col] = color_mix_2_alpha(mem[col], mem[col].alpha, color, opa); +#endif + } + mem += mem_width; + } + } + } +} + +#if LV_COLOR_SCREEN_TRANSP + +/** + * Mix two colors. Both color can have alpha value. It requires ARGB888 colors. + * @param bg_color background color + * @param bg_opa alpha of the background color + * @param fg_color foreground color + * @param fg_opa alpha of the foreground color + * @return the mixed color. the alpha channel (color.alpha) contains the result alpha + */ +static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa) +{ + /* Pick the foreground if it's fully opaque or the Background is fully transparent*/ + if(fg_opa == LV_OPA_COVER && bg_opa <= LV_OPA_MIN) { + fg_color.alpha = fg_opa; + return fg_color; + } + /*Transparent foreground: use the Background*/ + else if(fg_opa <= LV_OPA_MIN) { + return bg_color; + } + /*Opaque background: use simple mix*/ + else if(bg_opa >= LV_OPA_MAX) { + return lv_color_mix(fg_color, bg_color, fg_opa); + } + /*Both colors have alpha. Expensive calculation need to be applied*/ + else { + /*Save the parameters and the result. If they will be asked again don't compute again*/ + static lv_opa_t fg_opa_save = 0; + static lv_opa_t bg_opa_save = 0; + static lv_color_t c = {{0}}; + + if(fg_opa != fg_opa_save || bg_opa != bg_opa_save) { + fg_opa_save = fg_opa; + bg_opa_save = bg_opa; + /*Info: https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/ + lv_opa_t alpha_res = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8); + if(alpha_res == 0) { + while(1); + } + lv_opa_t ratio = (uint16_t)((uint16_t) fg_opa * 255) / alpha_res; + c = lv_color_mix(fg_color, bg_color, ratio); + c.alpha = alpha_res; + } + return c; + + } +} +#endif /*LV_COLOR_SCREEN_TRANSP*/ + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h new file mode 100644 index 0000000..88838b7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h @@ -0,0 +1,89 @@ +/** + * @file lv_draw_vbasic.h + * + */ + +#ifndef LV_DRAW_VBASIC_H +#define LV_DRAW_VBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +#endif /*LV_VDB_SIZE != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c new file mode 100644 index 0000000..c97eda6 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_120 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols-huge.ttf 120 px Font in U+f002 () .. U+f007 () range with all bpp + * Sparse font with only these characters:  +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_120_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_120 == 8 + {.w_px = 103, .glyph_index = 0}, /*Unicode: U+f002 ()*/ + {.w_px = 103, .glyph_index = 12360}, /*Unicode: U+f003 ()*/ + {.w_px = 103, .glyph_index = 24720}, /*Unicode: U+f005 ()*/ + {.w_px = 103, .glyph_index = 37080}, /*Unicode: U+f007 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_120 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 120, /*Font height in pixels*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x36E00), /*Bitmap of glyphs*/ + .glyph_dsc = hekate_symbol_120_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 4, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_120 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_100*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c new file mode 100644 index 0000000..426bde8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_20 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols.ttf 20 px Font in U+f000 () .. U+f2ee (ï‹®) range with all bpp + * Sparse font with only these characters: ï€ï€ˆï€‹ï€Œï€ï€‘ï€ïˆï‹ïŒïï‘ï’ï“ï”ï§ï¨ï±ï´ï·ï¸ï¹ï»ï‚“ï‰ï‰‚ +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_20_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_20 == 4 + {.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 (ï€)*/ + {.w_px = 16, .glyph_index = 60}, /*Unicode: U+f008 ()*/ + {.w_px = 20, .glyph_index = 220}, /*Unicode: U+f00b ()*/ + {.w_px = 22, .glyph_index = 420}, /*Unicode: U+f00c ()*/ + {.w_px = 16, .glyph_index = 640}, /*Unicode: U+f00d (ï€)*/ + {.w_px = 18, .glyph_index = 800}, /*Unicode: U+f011 ()*/ + {.w_px = 18, .glyph_index = 980}, /*Unicode: U+f013 ()*/ + {.w_px = 16, .glyph_index = 1160}, /*Unicode: U+f014 ()*/ + {.w_px = 23, .glyph_index = 1320}, /*Unicode: U+f015 ()*/ + {.w_px = 18, .glyph_index = 1560}, /*Unicode: U+f019 ()*/ + {.w_px = 23, .glyph_index = 1740}, /*Unicode: U+f01c ()*/ + {.w_px = 18, .glyph_index = 1980}, /*Unicode: U+f021 ()*/ + {.w_px = 18, .glyph_index = 2160}, /*Unicode: U+f026 ()*/ + {.w_px = 18, .glyph_index = 2340}, /*Unicode: U+f027 ()*/ + {.w_px = 13, .glyph_index = 2520}, /*Unicode: U+f028 ()*/ + {.w_px = 13, .glyph_index = 2660}, /*Unicode: U+f03e ()*/ + {.w_px = 16, .glyph_index = 2800}, /*Unicode: U+f040 (ï€)*/ + {.w_px = 13, .glyph_index = 2960}, /*Unicode: U+f048 (ïˆ)*/ + {.w_px = 13, .glyph_index = 3100}, /*Unicode: U+f04b (ï‹)*/ + {.w_px = 13, .glyph_index = 3240}, /*Unicode: U+f04c (ïŒ)*/ + {.w_px = 9, .glyph_index = 3380}, /*Unicode: U+f04d (ï)*/ + {.w_px = 23, .glyph_index = 3480}, /*Unicode: U+f051 (ï‘)*/ + {.w_px = 21, .glyph_index = 3720}, /*Unicode: U+f052 (ï’)*/ + {.w_px = 11, .glyph_index = 3940}, /*Unicode: U+f053 (ï“)*/ + {.w_px = 11, .glyph_index = 4060}, /*Unicode: U+f054 (ï”)*/ + {.w_px = 18, .glyph_index = 4180}, /*Unicode: U+f067 (ï§)*/ + {.w_px = 18, .glyph_index = 4360}, /*Unicode: U+f068 (ï¨)*/ + {.w_px = 20, .glyph_index = 4540}, /*Unicode: U+f071 (ï±)*/ + {.w_px = 20, .glyph_index = 4740}, /*Unicode: U+f074 (ï´)*/ + {.w_px = 18, .glyph_index = 4940}, /*Unicode: U+f077 (ï·)*/ + {.w_px = 18, .glyph_index = 5120}, /*Unicode: U+f078 (ï¸)*/ + {.w_px = 18, .glyph_index = 5300}, /*Unicode: U+f079 (ï¹)*/ + {.w_px = 20, .glyph_index = 5480}, /*Unicode: U+f07b (ï»)*/ + {.w_px = 18, .glyph_index = 5680}, /*Unicode: U+f093 (ï‚“)*/ + {.w_px = 25, .glyph_index = 5860}, /*Unicode: U+f095 (ï‚•)*/ + {.w_px = 18, .glyph_index = 6120}, /*Unicode: U+f0c4 ()*/ + {.w_px = 16, .glyph_index = 6300}, /*Unicode: U+f0c5 ()*/ + {.w_px = 17, .glyph_index = 6460}, /*Unicode: U+f0c7 ()*/ + {.w_px = 8, .glyph_index = 6640}, /*Unicode: U+f0e7 ()*/ + {.w_px = 12, .glyph_index = 6720}, /*Unicode: U+f0f3 ()*/ + {.w_px = 23, .glyph_index = 6840}, /*Unicode: U+f11c (ï„œ)*/ + {.w_px = 18, .glyph_index = 7080}, /*Unicode: U+f124 ()*/ + {.w_px = 13, .glyph_index = 7260}, /*Unicode: U+f15b (ï…›)*/ + {.w_px = 20, .glyph_index = 7400}, /*Unicode: U+f1eb ()*/ + {.w_px = 26, .glyph_index = 7600}, /*Unicode: U+f240 ()*/ + {.w_px = 26, .glyph_index = 7860}, /*Unicode: U+f241 (ï‰)*/ + {.w_px = 26, .glyph_index = 8120}, /*Unicode: U+f242 ()*/ + {.w_px = 26, .glyph_index = 8380}, /*Unicode: U+f243 ()*/ + {.w_px = 26, .glyph_index = 8640}, /*Unicode: U+f244 ()*/ + {.w_px = 20, .glyph_index = 8900}, /*Unicode: U+f293 ()*/ + +#elif USE_HEKATE_SYMBOL_20 == 8 + {.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 (ï€)*/ + {.w_px = 16, .glyph_index = 100}, /*Unicode: U+f008 ()*/ + {.w_px = 20, .glyph_index = 420}, /*Unicode: U+f00b ()*/ + {.w_px = 22, .glyph_index = 820}, /*Unicode: U+f00c ()*/ + {.w_px = 16, .glyph_index = 1260}, /*Unicode: U+f00d (ï€)*/ + {.w_px = 18, .glyph_index = 1580}, /*Unicode: U+f011 ()*/ + {.w_px = 18, .glyph_index = 1940}, /*Unicode: U+f013 ()*/ + {.w_px = 16, .glyph_index = 2300}, /*Unicode: U+f014 ()*/ + {.w_px = 23, .glyph_index = 2620}, /*Unicode: U+f015 ()*/ + {.w_px = 18, .glyph_index = 3080}, /*Unicode: U+f019 ()*/ + {.w_px = 23, .glyph_index = 3440}, /*Unicode: U+f01c ()*/ + {.w_px = 18, .glyph_index = 3900}, /*Unicode: U+f021 ()*/ + {.w_px = 18, .glyph_index = 4260}, /*Unicode: U+f026 ()*/ + {.w_px = 18, .glyph_index = 4620}, /*Unicode: U+f027 ()*/ + {.w_px = 13, .glyph_index = 4980}, /*Unicode: U+f028 ()*/ + {.w_px = 13, .glyph_index = 5240}, /*Unicode: U+f03e ()*/ + {.w_px = 16, .glyph_index = 5500}, /*Unicode: U+f040 (ï€)*/ + {.w_px = 13, .glyph_index = 5820}, /*Unicode: U+f048 (ïˆ)*/ + {.w_px = 13, .glyph_index = 6080}, /*Unicode: U+f04b (ï‹)*/ + {.w_px = 13, .glyph_index = 6340}, /*Unicode: U+f04c (ïŒ)*/ + {.w_px = 9, .glyph_index = 6600}, /*Unicode: U+f04d (ï)*/ + {.w_px = 23, .glyph_index = 6780}, /*Unicode: U+f051 (ï‘)*/ + {.w_px = 21, .glyph_index = 7240}, /*Unicode: U+f052 (ï’)*/ + {.w_px = 11, .glyph_index = 7660}, /*Unicode: U+f053 (ï“)*/ + {.w_px = 11, .glyph_index = 7880}, /*Unicode: U+f054 (ï”)*/ + {.w_px = 18, .glyph_index = 8100}, /*Unicode: U+f067 (ï§)*/ + {.w_px = 18, .glyph_index = 8460}, /*Unicode: U+f068 (ï¨)*/ + {.w_px = 20, .glyph_index = 8820}, /*Unicode: U+f071 (ï±)*/ + {.w_px = 20, .glyph_index = 9220}, /*Unicode: U+f074 (ï´)*/ + {.w_px = 18, .glyph_index = 9620}, /*Unicode: U+f077 (ï·)*/ + {.w_px = 18, .glyph_index = 9980}, /*Unicode: U+f078 (ï¸)*/ + {.w_px = 18, .glyph_index = 10340}, /*Unicode: U+f079 (ï¹)*/ + {.w_px = 20, .glyph_index = 10700}, /*Unicode: U+f07b (ï»)*/ + {.w_px = 18, .glyph_index = 11100}, /*Unicode: U+f093 (ï‚“)*/ + {.w_px = 25, .glyph_index = 11460}, /*Unicode: U+f095 (ï‚•)*/ + {.w_px = 18, .glyph_index = 11960}, /*Unicode: U+f0c4 ()*/ + {.w_px = 16, .glyph_index = 12320}, /*Unicode: U+f0c5 ()*/ + {.w_px = 17, .glyph_index = 12640}, /*Unicode: U+f0c7 ()*/ + {.w_px = 8, .glyph_index = 12980}, /*Unicode: U+f0e7 ()*/ + {.w_px = 12, .glyph_index = 13140}, /*Unicode: U+f0f3 ()*/ + {.w_px = 23, .glyph_index = 13380}, /*Unicode: U+f11c (ï„œ)*/ + {.w_px = 18, .glyph_index = 13840}, /*Unicode: U+f124 ()*/ + {.w_px = 13, .glyph_index = 14200}, /*Unicode: U+f15b (ï…›)*/ + {.w_px = 20, .glyph_index = 14460}, /*Unicode: U+f1eb ()*/ + {.w_px = 26, .glyph_index = 14860}, /*Unicode: U+f240 ()*/ + {.w_px = 26, .glyph_index = 15380}, /*Unicode: U+f241 (ï‰)*/ + {.w_px = 26, .glyph_index = 15900}, /*Unicode: U+f242 ()*/ + {.w_px = 26, .glyph_index = 16420}, /*Unicode: U+f243 ()*/ + {.w_px = 26, .glyph_index = 16940}, /*Unicode: U+f244 ()*/ + {.w_px = 20, .glyph_index = 17460}, /*Unicode: U+f293 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_20 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = hekate_symbol_20_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0xFC00), + .glyph_dsc = hekate_symbol_20_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 50, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_20 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_HEKATE_SYMBOL_20 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_20*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c new file mode 100644 index 0000000..4e0da47 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_HEKATE_SYMBOL_30 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * hekate-symbols.ttf 30 px Font in U+f000 () .. U+f2ee (ï‹®) range with all bpp + * Sparse font with only these characters: ï€ï€ˆï€‹ï€Œï€ï€‘ï€ïˆï‹ïŒïï‘ï’ï“ï”ï§ï¨ï±ï´ï·ï¸ï¹ï»ï‚“ï‰ï‰‚ +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t hekate_symbol_30_glyph_dsc[] = +{ +#if USE_HEKATE_SYMBOL_30 == 4 + {.w_px = 7, .glyph_index = 0}, /*Unicode: U+f001 (ï€)*/ + {.w_px = 25, .glyph_index = 120}, /*Unicode: U+f008 ()*/ + {.w_px = 27, .glyph_index = 510}, /*Unicode: U+f00b ()*/ + {.w_px = 31, .glyph_index = 930}, /*Unicode: U+f00c ()*/ + {.w_px = 22, .glyph_index = 1410}, /*Unicode: U+f00d (ï€)*/ + {.w_px = 25, .glyph_index = 1740}, /*Unicode: U+f011 ()*/ + {.w_px = 25, .glyph_index = 2130}, /*Unicode: U+f013 ()*/ + {.w_px = 23, .glyph_index = 2520}, /*Unicode: U+f014 ()*/ + {.w_px = 34, .glyph_index = 2880}, /*Unicode: U+f015 ()*/ + {.w_px = 25, .glyph_index = 3390}, /*Unicode: U+f019 ()*/ + {.w_px = 32, .glyph_index = 3780}, /*Unicode: U+f01c ()*/ + {.w_px = 25, .glyph_index = 4260}, /*Unicode: U+f021 ()*/ + {.w_px = 25, .glyph_index = 4650}, /*Unicode: U+f026 ()*/ + {.w_px = 25, .glyph_index = 5040}, /*Unicode: U+f027 ()*/ + {.w_px = 20, .glyph_index = 5430}, /*Unicode: U+f028 ()*/ + {.w_px = 20, .glyph_index = 5730}, /*Unicode: U+f03e ()*/ + {.w_px = 25, .glyph_index = 6030}, /*Unicode: U+f040 (ï€)*/ + {.w_px = 20, .glyph_index = 6420}, /*Unicode: U+f048 (ïˆ)*/ + {.w_px = 20, .glyph_index = 6720}, /*Unicode: U+f04b (ï‹)*/ + {.w_px = 20, .glyph_index = 7020}, /*Unicode: U+f04c (ïŒ)*/ + {.w_px = 13, .glyph_index = 7320}, /*Unicode: U+f04d (ï)*/ + {.w_px = 32, .glyph_index = 7530}, /*Unicode: U+f051 (ï‘)*/ + {.w_px = 30, .glyph_index = 8010}, /*Unicode: U+f052 (ï’)*/ + {.w_px = 16, .glyph_index = 8460}, /*Unicode: U+f053 (ï“)*/ + {.w_px = 16, .glyph_index = 8700}, /*Unicode: U+f054 (ï”)*/ + {.w_px = 25, .glyph_index = 8940}, /*Unicode: U+f067 (ï§)*/ + {.w_px = 25, .glyph_index = 9330}, /*Unicode: U+f068 (ï¨)*/ + {.w_px = 27, .glyph_index = 9720}, /*Unicode: U+f071 (ï±)*/ + {.w_px = 29, .glyph_index = 10140}, /*Unicode: U+f074 (ï´)*/ + {.w_px = 26, .glyph_index = 10590}, /*Unicode: U+f077 (ï·)*/ + {.w_px = 26, .glyph_index = 10980}, /*Unicode: U+f078 (ï¸)*/ + {.w_px = 25, .glyph_index = 11370}, /*Unicode: U+f079 (ï¹)*/ + {.w_px = 29, .glyph_index = 11760}, /*Unicode: U+f07b (ï»)*/ + {.w_px = 25, .glyph_index = 12210}, /*Unicode: U+f093 (ï‚“)*/ + {.w_px = 37, .glyph_index = 12600}, /*Unicode: U+f095 (ï‚•)*/ + {.w_px = 25, .glyph_index = 13170}, /*Unicode: U+f0c4 ()*/ + {.w_px = 23, .glyph_index = 13560}, /*Unicode: U+f0c5 ()*/ + {.w_px = 24, .glyph_index = 13920}, /*Unicode: U+f0c7 ()*/ + {.w_px = 13, .glyph_index = 14280}, /*Unicode: U+f0e7 ()*/ + {.w_px = 18, .glyph_index = 14490}, /*Unicode: U+f0f3 ()*/ + {.w_px = 33, .glyph_index = 14760}, /*Unicode: U+f11c (ï„œ)*/ + {.w_px = 25, .glyph_index = 15270}, /*Unicode: U+f124 ()*/ + {.w_px = 20, .glyph_index = 15660}, /*Unicode: U+f15b (ï…›)*/ + {.w_px = 29, .glyph_index = 15960}, /*Unicode: U+f1eb ()*/ + {.w_px = 38, .glyph_index = 16410}, /*Unicode: U+f240 ()*/ + {.w_px = 38, .glyph_index = 16980}, /*Unicode: U+f241 (ï‰)*/ + {.w_px = 38, .glyph_index = 17550}, /*Unicode: U+f242 ()*/ + {.w_px = 38, .glyph_index = 18120}, /*Unicode: U+f243 ()*/ + {.w_px = 38, .glyph_index = 18690}, /*Unicode: U+f244 ()*/ + {.w_px = 29, .glyph_index = 19260}, /*Unicode: U+f293 ()*/ + +#elif USE_HEKATE_SYMBOL_30 == 8 + {.w_px = 7, .glyph_index = 0}, /*Unicode: U+f001 (ï€)*/ + {.w_px = 25, .glyph_index = 210}, /*Unicode: U+f008 ()*/ + {.w_px = 27, .glyph_index = 960}, /*Unicode: U+f00b ()*/ + {.w_px = 31, .glyph_index = 1770}, /*Unicode: U+f00c ()*/ + {.w_px = 22, .glyph_index = 2700}, /*Unicode: U+f00d (ï€)*/ + {.w_px = 25, .glyph_index = 3360}, /*Unicode: U+f011 ()*/ + {.w_px = 25, .glyph_index = 4110}, /*Unicode: U+f013 ()*/ + {.w_px = 23, .glyph_index = 4860}, /*Unicode: U+f014 ()*/ + {.w_px = 34, .glyph_index = 5550}, /*Unicode: U+f015 ()*/ + {.w_px = 25, .glyph_index = 6570}, /*Unicode: U+f019 ()*/ + {.w_px = 32, .glyph_index = 7320}, /*Unicode: U+f01c ()*/ + {.w_px = 25, .glyph_index = 8280}, /*Unicode: U+f021 ()*/ + {.w_px = 25, .glyph_index = 9030}, /*Unicode: U+f026 ()*/ + {.w_px = 25, .glyph_index = 9780}, /*Unicode: U+f027 ()*/ + {.w_px = 20, .glyph_index = 10530}, /*Unicode: U+f028 ()*/ + {.w_px = 20, .glyph_index = 11130}, /*Unicode: U+f03e ()*/ + {.w_px = 25, .glyph_index = 11730}, /*Unicode: U+f040 (ï€)*/ + {.w_px = 20, .glyph_index = 12480}, /*Unicode: U+f048 (ïˆ)*/ + {.w_px = 20, .glyph_index = 13080}, /*Unicode: U+f04b (ï‹)*/ + {.w_px = 20, .glyph_index = 13680}, /*Unicode: U+f04c (ïŒ)*/ + {.w_px = 13, .glyph_index = 14280}, /*Unicode: U+f04d (ï)*/ + {.w_px = 32, .glyph_index = 14670}, /*Unicode: U+f051 (ï‘)*/ + {.w_px = 30, .glyph_index = 15630}, /*Unicode: U+f052 (ï’)*/ + {.w_px = 16, .glyph_index = 16530}, /*Unicode: U+f053 (ï“)*/ + {.w_px = 16, .glyph_index = 17010}, /*Unicode: U+f054 (ï”)*/ + {.w_px = 25, .glyph_index = 17490}, /*Unicode: U+f067 (ï§)*/ + {.w_px = 25, .glyph_index = 18240}, /*Unicode: U+f068 (ï¨)*/ + {.w_px = 27, .glyph_index = 18990}, /*Unicode: U+f071 (ï±)*/ + {.w_px = 29, .glyph_index = 19800}, /*Unicode: U+f074 (ï´)*/ + {.w_px = 26, .glyph_index = 20670}, /*Unicode: U+f077 (ï·)*/ + {.w_px = 26, .glyph_index = 21450}, /*Unicode: U+f078 (ï¸)*/ + {.w_px = 25, .glyph_index = 22230}, /*Unicode: U+f079 (ï¹)*/ + {.w_px = 29, .glyph_index = 22980}, /*Unicode: U+f07b (ï»)*/ + {.w_px = 25, .glyph_index = 23850}, /*Unicode: U+f093 (ï‚“)*/ + {.w_px = 37, .glyph_index = 24600}, /*Unicode: U+f095 (ï‚•)*/ + {.w_px = 25, .glyph_index = 25710}, /*Unicode: U+f0c4 ()*/ + {.w_px = 23, .glyph_index = 26460}, /*Unicode: U+f0c5 ()*/ + {.w_px = 24, .glyph_index = 27150}, /*Unicode: U+f0c7 ()*/ + {.w_px = 13, .glyph_index = 27870}, /*Unicode: U+f0e7 ()*/ + {.w_px = 18, .glyph_index = 28260}, /*Unicode: U+f0f3 ()*/ + {.w_px = 33, .glyph_index = 28800}, /*Unicode: U+f11c (ï„œ)*/ + {.w_px = 25, .glyph_index = 29790}, /*Unicode: U+f124 ()*/ + {.w_px = 20, .glyph_index = 30540}, /*Unicode: U+f15b (ï…›)*/ + {.w_px = 29, .glyph_index = 31140}, /*Unicode: U+f1eb ()*/ + {.w_px = 38, .glyph_index = 32010}, /*Unicode: U+f240 ()*/ + {.w_px = 38, .glyph_index = 33150}, /*Unicode: U+f241 (ï‰)*/ + {.w_px = 38, .glyph_index = 34290}, /*Unicode: U+f242 ()*/ + {.w_px = 38, .glyph_index = 35430}, /*Unicode: U+f243 ()*/ + {.w_px = 38, .glyph_index = 36570}, /*Unicode: U+f244 ()*/ + {.w_px = 29, .glyph_index = 37710}, /*Unicode: U+f293 ()*/ + +#endif +}; + +lv_font_t hekate_symbol_30 = +{ + .unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/ + .unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/ + .h_px = 30, /*Font height in pixels*/ + //.glyph_bitmap = hekate_symbol_30_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x14200), + .glyph_dsc = hekate_symbol_30_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 50, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*List of unicode characters*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_HEKATE_SYMBOL_30 == 4 + .bpp = 4, /*Bit per pixel*/ + #elif USE_HEKATE_SYMBOL_30 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_HEKATE_SYMBOL_30*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/interui_20.c b/ariane/src/bdk/libs/lvgl/lv_fonts/interui_20.c new file mode 100644 index 0000000..5f50c6c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/interui_20.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_INTERUI_20 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * Inter-UI-Regular-stretched.ttf 20 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t interui_20_glyph_dsc[] = +{ +#if USE_INTERUI_20 == 4 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 60}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 100}, /*Unicode: U+0022 (")*/ + {.w_px = 8, .glyph_index = 160}, /*Unicode: U+0023 (#)*/ + {.w_px = 9, .glyph_index = 240}, /*Unicode: U+0024 ($)*/ + {.w_px = 14, .glyph_index = 340}, /*Unicode: U+0025 (%)*/ + {.w_px = 12, .glyph_index = 480}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 600}, /*Unicode: U+0027 (')*/ + {.w_px = 5, .glyph_index = 640}, /*Unicode: U+0028 (()*/ + {.w_px = 5, .glyph_index = 700}, /*Unicode: U+0029 ())*/ + {.w_px = 7, .glyph_index = 760}, /*Unicode: U+002a (*)*/ + {.w_px = 10, .glyph_index = 840}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 940}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 980}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 1040}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1080}, /*Unicode: U+002f (/)*/ + {.w_px = 10, .glyph_index = 1160}, /*Unicode: U+0030 (0)*/ + {.w_px = 5, .glyph_index = 1260}, /*Unicode: U+0031 (1)*/ + {.w_px = 9, .glyph_index = 1320}, /*Unicode: U+0032 (2)*/ + {.w_px = 10, .glyph_index = 1420}, /*Unicode: U+0033 (3)*/ + {.w_px = 9, .glyph_index = 1520}, /*Unicode: U+0034 (4)*/ + {.w_px = 9, .glyph_index = 1620}, /*Unicode: U+0035 (5)*/ + {.w_px = 10, .glyph_index = 1720}, /*Unicode: U+0036 (6)*/ + {.w_px = 8, .glyph_index = 1820}, /*Unicode: U+0037 (7)*/ + {.w_px = 10, .glyph_index = 1900}, /*Unicode: U+0038 (8)*/ + {.w_px = 10, .glyph_index = 2000}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 2100}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 2140}, /*Unicode: U+003b (;)*/ + {.w_px = 12, .glyph_index = 2180}, /*Unicode: U+003c (<)*/ + {.w_px = 10, .glyph_index = 2300}, /*Unicode: U+003d (=)*/ + {.w_px = 12, .glyph_index = 2400}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 2520}, /*Unicode: U+003f (?)*/ + {.w_px = 14, .glyph_index = 2600}, /*Unicode: U+0040 (@)*/ + {.w_px = 12, .glyph_index = 2740}, /*Unicode: U+0041 (A)*/ + {.w_px = 10, .glyph_index = 2860}, /*Unicode: U+0042 (B)*/ + {.w_px = 11, .glyph_index = 2960}, /*Unicode: U+0043 (C)*/ + {.w_px = 12, .glyph_index = 3080}, /*Unicode: U+0044 (D)*/ + {.w_px = 9, .glyph_index = 3200}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+0046 (F)*/ + {.w_px = 12, .glyph_index = 3380}, /*Unicode: U+0047 (G)*/ + {.w_px = 10, .glyph_index = 3500}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 3600}, /*Unicode: U+0049 (I)*/ + {.w_px = 7, .glyph_index = 3640}, /*Unicode: U+004a (J)*/ + {.w_px = 10, .glyph_index = 3720}, /*Unicode: U+004b (K)*/ + {.w_px = 7, .glyph_index = 3820}, /*Unicode: U+004c (L)*/ + {.w_px = 15, .glyph_index = 3900}, /*Unicode: U+004d (M)*/ + {.w_px = 12, .glyph_index = 4060}, /*Unicode: U+004e (N)*/ + {.w_px = 14, .glyph_index = 4180}, /*Unicode: U+004f (O)*/ + {.w_px = 9, .glyph_index = 4320}, /*Unicode: U+0050 (P)*/ + {.w_px = 14, .glyph_index = 4420}, /*Unicode: U+0051 (Q)*/ + {.w_px = 9, .glyph_index = 4560}, /*Unicode: U+0052 (R)*/ + {.w_px = 9, .glyph_index = 4660}, /*Unicode: U+0053 (S)*/ + {.w_px = 9, .glyph_index = 4760}, /*Unicode: U+0054 (T)*/ + {.w_px = 12, .glyph_index = 4860}, /*Unicode: U+0055 (U)*/ + {.w_px = 12, .glyph_index = 4980}, /*Unicode: U+0056 (V)*/ + {.w_px = 18, .glyph_index = 5100}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 5280}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 5380}, /*Unicode: U+0059 (Y)*/ + {.w_px = 10, .glyph_index = 5480}, /*Unicode: U+005a (Z)*/ + {.w_px = 5, .glyph_index = 5580}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 5640}, /*Unicode: U+005c (\)*/ + {.w_px = 5, .glyph_index = 5720}, /*Unicode: U+005d (])*/ + {.w_px = 9, .glyph_index = 5780}, /*Unicode: U+005e (^)*/ + {.w_px = 8, .glyph_index = 5880}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 5960}, /*Unicode: U+0060 (`)*/ + {.w_px = 9, .glyph_index = 6000}, /*Unicode: U+0061 (a)*/ + {.w_px = 10, .glyph_index = 6100}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 6200}, /*Unicode: U+0063 (c)*/ + {.w_px = 10, .glyph_index = 6280}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 6380}, /*Unicode: U+0065 (e)*/ + {.w_px = 4, .glyph_index = 6480}, /*Unicode: U+0066 (f)*/ + {.w_px = 9, .glyph_index = 6520}, /*Unicode: U+0067 (g)*/ + {.w_px = 9, .glyph_index = 6620}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 6720}, /*Unicode: U+0069 (i)*/ + {.w_px = 5, .glyph_index = 6760}, /*Unicode: U+006a (j)*/ + {.w_px = 8, .glyph_index = 6820}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 6900}, /*Unicode: U+006c (l)*/ + {.w_px = 13, .glyph_index = 6940}, /*Unicode: U+006d (m)*/ + {.w_px = 9, .glyph_index = 7080}, /*Unicode: U+006e (n)*/ + {.w_px = 10, .glyph_index = 7180}, /*Unicode: U+006f (o)*/ + {.w_px = 10, .glyph_index = 7280}, /*Unicode: U+0070 (p)*/ + {.w_px = 10, .glyph_index = 7380}, /*Unicode: U+0071 (q)*/ + {.w_px = 5, .glyph_index = 7480}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 7540}, /*Unicode: U+0073 (s)*/ + {.w_px = 5, .glyph_index = 7620}, /*Unicode: U+0074 (t)*/ + {.w_px = 9, .glyph_index = 7680}, /*Unicode: U+0075 (u)*/ + {.w_px = 8, .glyph_index = 7780}, /*Unicode: U+0076 (v)*/ + {.w_px = 14, .glyph_index = 7860}, /*Unicode: U+0077 (w)*/ + {.w_px = 8, .glyph_index = 8000}, /*Unicode: U+0078 (x)*/ + {.w_px = 8, .glyph_index = 8080}, /*Unicode: U+0079 (y)*/ + {.w_px = 7, .glyph_index = 8160}, /*Unicode: U+007a (z)*/ + {.w_px = 4, .glyph_index = 8240}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 8280}, /*Unicode: U+007c (|)*/ + {.w_px = 4, .glyph_index = 8320}, /*Unicode: U+007d (})*/ + {.w_px = 6, .glyph_index = 8360}, /*Unicode: U+007e (~)*/ + +#elif USE_INTERUI_20 == 8 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 180}, /*Unicode: U+0022 (")*/ + {.w_px = 8, .glyph_index = 280}, /*Unicode: U+0023 (#)*/ + {.w_px = 9, .glyph_index = 440}, /*Unicode: U+0024 ($)*/ + {.w_px = 14, .glyph_index = 620}, /*Unicode: U+0025 (%)*/ + {.w_px = 12, .glyph_index = 900}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 1140}, /*Unicode: U+0027 (')*/ + {.w_px = 5, .glyph_index = 1200}, /*Unicode: U+0028 (()*/ + {.w_px = 5, .glyph_index = 1300}, /*Unicode: U+0029 ())*/ + {.w_px = 7, .glyph_index = 1400}, /*Unicode: U+002a (*)*/ + {.w_px = 10, .glyph_index = 1540}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 1740}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 1800}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 1900}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1960}, /*Unicode: U+002f (/)*/ + {.w_px = 10, .glyph_index = 2120}, /*Unicode: U+0030 (0)*/ + {.w_px = 5, .glyph_index = 2320}, /*Unicode: U+0031 (1)*/ + {.w_px = 9, .glyph_index = 2420}, /*Unicode: U+0032 (2)*/ + {.w_px = 10, .glyph_index = 2600}, /*Unicode: U+0033 (3)*/ + {.w_px = 9, .glyph_index = 2800}, /*Unicode: U+0034 (4)*/ + {.w_px = 9, .glyph_index = 2980}, /*Unicode: U+0035 (5)*/ + {.w_px = 10, .glyph_index = 3160}, /*Unicode: U+0036 (6)*/ + {.w_px = 8, .glyph_index = 3360}, /*Unicode: U+0037 (7)*/ + {.w_px = 10, .glyph_index = 3520}, /*Unicode: U+0038 (8)*/ + {.w_px = 10, .glyph_index = 3720}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 3920}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 3980}, /*Unicode: U+003b (;)*/ + {.w_px = 12, .glyph_index = 4040}, /*Unicode: U+003c (<)*/ + {.w_px = 10, .glyph_index = 4280}, /*Unicode: U+003d (=)*/ + {.w_px = 12, .glyph_index = 4480}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 4720}, /*Unicode: U+003f (?)*/ + {.w_px = 14, .glyph_index = 4880}, /*Unicode: U+0040 (@)*/ + {.w_px = 12, .glyph_index = 5160}, /*Unicode: U+0041 (A)*/ + {.w_px = 10, .glyph_index = 5400}, /*Unicode: U+0042 (B)*/ + {.w_px = 11, .glyph_index = 5600}, /*Unicode: U+0043 (C)*/ + {.w_px = 12, .glyph_index = 5820}, /*Unicode: U+0044 (D)*/ + {.w_px = 9, .glyph_index = 6060}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 6240}, /*Unicode: U+0046 (F)*/ + {.w_px = 12, .glyph_index = 6400}, /*Unicode: U+0047 (G)*/ + {.w_px = 10, .glyph_index = 6640}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 6840}, /*Unicode: U+0049 (I)*/ + {.w_px = 7, .glyph_index = 6900}, /*Unicode: U+004a (J)*/ + {.w_px = 10, .glyph_index = 7040}, /*Unicode: U+004b (K)*/ + {.w_px = 7, .glyph_index = 7240}, /*Unicode: U+004c (L)*/ + {.w_px = 15, .glyph_index = 7380}, /*Unicode: U+004d (M)*/ + {.w_px = 12, .glyph_index = 7680}, /*Unicode: U+004e (N)*/ + {.w_px = 14, .glyph_index = 7920}, /*Unicode: U+004f (O)*/ + {.w_px = 9, .glyph_index = 8200}, /*Unicode: U+0050 (P)*/ + {.w_px = 14, .glyph_index = 8380}, /*Unicode: U+0051 (Q)*/ + {.w_px = 9, .glyph_index = 8660}, /*Unicode: U+0052 (R)*/ + {.w_px = 9, .glyph_index = 8840}, /*Unicode: U+0053 (S)*/ + {.w_px = 9, .glyph_index = 9020}, /*Unicode: U+0054 (T)*/ + {.w_px = 12, .glyph_index = 9200}, /*Unicode: U+0055 (U)*/ + {.w_px = 12, .glyph_index = 9440}, /*Unicode: U+0056 (V)*/ + {.w_px = 18, .glyph_index = 9680}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 10040}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 10240}, /*Unicode: U+0059 (Y)*/ + {.w_px = 10, .glyph_index = 10440}, /*Unicode: U+005a (Z)*/ + {.w_px = 5, .glyph_index = 10640}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 10740}, /*Unicode: U+005c (\)*/ + {.w_px = 5, .glyph_index = 10900}, /*Unicode: U+005d (])*/ + {.w_px = 9, .glyph_index = 11000}, /*Unicode: U+005e (^)*/ + {.w_px = 8, .glyph_index = 11180}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 11340}, /*Unicode: U+0060 (`)*/ + {.w_px = 9, .glyph_index = 11420}, /*Unicode: U+0061 (a)*/ + {.w_px = 10, .glyph_index = 11600}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 11800}, /*Unicode: U+0063 (c)*/ + {.w_px = 10, .glyph_index = 11960}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 12160}, /*Unicode: U+0065 (e)*/ + {.w_px = 4, .glyph_index = 12340}, /*Unicode: U+0066 (f)*/ + {.w_px = 9, .glyph_index = 12420}, /*Unicode: U+0067 (g)*/ + {.w_px = 9, .glyph_index = 12600}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 12780}, /*Unicode: U+0069 (i)*/ + {.w_px = 5, .glyph_index = 12840}, /*Unicode: U+006a (j)*/ + {.w_px = 8, .glyph_index = 12940}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 13100}, /*Unicode: U+006c (l)*/ + {.w_px = 13, .glyph_index = 13180}, /*Unicode: U+006d (m)*/ + {.w_px = 9, .glyph_index = 13440}, /*Unicode: U+006e (n)*/ + {.w_px = 10, .glyph_index = 13620}, /*Unicode: U+006f (o)*/ + {.w_px = 10, .glyph_index = 13820}, /*Unicode: U+0070 (p)*/ + {.w_px = 10, .glyph_index = 14020}, /*Unicode: U+0071 (q)*/ + {.w_px = 5, .glyph_index = 14220}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 14320}, /*Unicode: U+0073 (s)*/ + {.w_px = 5, .glyph_index = 14480}, /*Unicode: U+0074 (t)*/ + {.w_px = 9, .glyph_index = 14580}, /*Unicode: U+0075 (u)*/ + {.w_px = 8, .glyph_index = 14760}, /*Unicode: U+0076 (v)*/ + {.w_px = 14, .glyph_index = 14920}, /*Unicode: U+0077 (w)*/ + {.w_px = 8, .glyph_index = 15200}, /*Unicode: U+0078 (x)*/ + {.w_px = 8, .glyph_index = 15360}, /*Unicode: U+0079 (y)*/ + {.w_px = 7, .glyph_index = 15520}, /*Unicode: U+007a (z)*/ + {.w_px = 4, .glyph_index = 15660}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 15740}, /*Unicode: U+007c (|)*/ + {.w_px = 4, .glyph_index = 15800}, /*Unicode: U+007d (})*/ + {.w_px = 6, .glyph_index = 15880}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t interui_20 = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = interui_20_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x3A00), + .glyph_dsc = interui_20_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_INTERUI_20 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_INTERUI_20 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_INTERUI_20*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/interui_30.c b/ariane/src/bdk/libs/lvgl/lv_fonts/interui_30.c new file mode 100644 index 0000000..238bcb1 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/interui_30.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_INTERUI_30 != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * Inter-UI-Regular-stretched.ttf 30 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t interui_30_glyph_dsc[] = +{ +#if USE_INTERUI_30 == 4 + {.w_px = 8, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 6, .glyph_index = 180}, /*Unicode: U+0022 (")*/ + {.w_px = 13, .glyph_index = 270}, /*Unicode: U+0023 (#)*/ + {.w_px = 12, .glyph_index = 480}, /*Unicode: U+0024 ($)*/ + {.w_px = 18, .glyph_index = 660}, /*Unicode: U+0025 (%)*/ + {.w_px = 16, .glyph_index = 930}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 1170}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 1230}, /*Unicode: U+0028 (()*/ + {.w_px = 7, .glyph_index = 1320}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 1440}, /*Unicode: U+002a (*)*/ + {.w_px = 16, .glyph_index = 1590}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 1830}, /*Unicode: U+002c (,)*/ + {.w_px = 8, .glyph_index = 1890}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 2010}, /*Unicode: U+002e (.)*/ + {.w_px = 11, .glyph_index = 2070}, /*Unicode: U+002f (/)*/ + {.w_px = 13, .glyph_index = 2250}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 2460}, /*Unicode: U+0031 (1)*/ + {.w_px = 13, .glyph_index = 2580}, /*Unicode: U+0032 (2)*/ + {.w_px = 14, .glyph_index = 2790}, /*Unicode: U+0033 (3)*/ + {.w_px = 13, .glyph_index = 3000}, /*Unicode: U+0034 (4)*/ + {.w_px = 14, .glyph_index = 3210}, /*Unicode: U+0035 (5)*/ + {.w_px = 13, .glyph_index = 3420}, /*Unicode: U+0036 (6)*/ + {.w_px = 13, .glyph_index = 3630}, /*Unicode: U+0037 (7)*/ + {.w_px = 13, .glyph_index = 3840}, /*Unicode: U+0038 (8)*/ + {.w_px = 13, .glyph_index = 4050}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 4260}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 4320}, /*Unicode: U+003b (;)*/ + {.w_px = 18, .glyph_index = 4380}, /*Unicode: U+003c (<)*/ + {.w_px = 16, .glyph_index = 4650}, /*Unicode: U+003d (=)*/ + {.w_px = 18, .glyph_index = 4890}, /*Unicode: U+003e (>)*/ + {.w_px = 12, .glyph_index = 5160}, /*Unicode: U+003f (?)*/ + {.w_px = 18, .glyph_index = 5340}, /*Unicode: U+0040 (@)*/ + {.w_px = 17, .glyph_index = 5610}, /*Unicode: U+0041 (A)*/ + {.w_px = 13, .glyph_index = 5880}, /*Unicode: U+0042 (B)*/ + {.w_px = 15, .glyph_index = 6090}, /*Unicode: U+0043 (C)*/ + {.w_px = 17, .glyph_index = 6330}, /*Unicode: U+0044 (D)*/ + {.w_px = 12, .glyph_index = 6600}, /*Unicode: U+0045 (E)*/ + {.w_px = 11, .glyph_index = 6780}, /*Unicode: U+0046 (F)*/ + {.w_px = 17, .glyph_index = 6960}, /*Unicode: U+0047 (G)*/ + {.w_px = 14, .glyph_index = 7230}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 7440}, /*Unicode: U+0049 (I)*/ + {.w_px = 11, .glyph_index = 7500}, /*Unicode: U+004a (J)*/ + {.w_px = 14, .glyph_index = 7680}, /*Unicode: U+004b (K)*/ + {.w_px = 9, .glyph_index = 7890}, /*Unicode: U+004c (L)*/ + {.w_px = 23, .glyph_index = 8040}, /*Unicode: U+004d (M)*/ + {.w_px = 16, .glyph_index = 8400}, /*Unicode: U+004e (N)*/ + {.w_px = 19, .glyph_index = 8640}, /*Unicode: U+004f (O)*/ + {.w_px = 11, .glyph_index = 8940}, /*Unicode: U+0050 (P)*/ + {.w_px = 19, .glyph_index = 9120}, /*Unicode: U+0051 (Q)*/ + {.w_px = 13, .glyph_index = 9420}, /*Unicode: U+0052 (R)*/ + {.w_px = 12, .glyph_index = 9630}, /*Unicode: U+0053 (S)*/ + {.w_px = 14, .glyph_index = 9810}, /*Unicode: U+0054 (T)*/ + {.w_px = 16, .glyph_index = 10020}, /*Unicode: U+0055 (U)*/ + {.w_px = 18, .glyph_index = 10260}, /*Unicode: U+0056 (V)*/ + {.w_px = 27, .glyph_index = 10530}, /*Unicode: U+0057 (W)*/ + {.w_px = 15, .glyph_index = 10950}, /*Unicode: U+0058 (X)*/ + {.w_px = 15, .glyph_index = 11190}, /*Unicode: U+0059 (Y)*/ + {.w_px = 15, .glyph_index = 11430}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 11670}, /*Unicode: U+005b ([)*/ + {.w_px = 11, .glyph_index = 11760}, /*Unicode: U+005c (\)*/ + {.w_px = 7, .glyph_index = 11940}, /*Unicode: U+005d (])*/ + {.w_px = 13, .glyph_index = 12060}, /*Unicode: U+005e (^)*/ + {.w_px = 12, .glyph_index = 12270}, /*Unicode: U+005f (_)*/ + {.w_px = 6, .glyph_index = 12450}, /*Unicode: U+0060 (`)*/ + {.w_px = 12, .glyph_index = 12540}, /*Unicode: U+0061 (a)*/ + {.w_px = 13, .glyph_index = 12720}, /*Unicode: U+0062 (b)*/ + {.w_px = 11, .glyph_index = 12930}, /*Unicode: U+0063 (c)*/ + {.w_px = 13, .glyph_index = 13110}, /*Unicode: U+0064 (d)*/ + {.w_px = 12, .glyph_index = 13320}, /*Unicode: U+0065 (e)*/ + {.w_px = 6, .glyph_index = 13500}, /*Unicode: U+0066 (f)*/ + {.w_px = 12, .glyph_index = 13590}, /*Unicode: U+0067 (g)*/ + {.w_px = 11, .glyph_index = 13770}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 13950}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 14010}, /*Unicode: U+006a (j)*/ + {.w_px = 12, .glyph_index = 14130}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 14310}, /*Unicode: U+006c (l)*/ + {.w_px = 19, .glyph_index = 14370}, /*Unicode: U+006d (m)*/ + {.w_px = 11, .glyph_index = 14670}, /*Unicode: U+006e (n)*/ + {.w_px = 14, .glyph_index = 14850}, /*Unicode: U+006f (o)*/ + {.w_px = 13, .glyph_index = 15060}, /*Unicode: U+0070 (p)*/ + {.w_px = 13, .glyph_index = 15270}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 15480}, /*Unicode: U+0072 (r)*/ + {.w_px = 11, .glyph_index = 15600}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 15780}, /*Unicode: U+0074 (t)*/ + {.w_px = 11, .glyph_index = 15900}, /*Unicode: U+0075 (u)*/ + {.w_px = 12, .glyph_index = 16080}, /*Unicode: U+0076 (v)*/ + {.w_px = 21, .glyph_index = 16260}, /*Unicode: U+0077 (w)*/ + {.w_px = 13, .glyph_index = 16590}, /*Unicode: U+0078 (x)*/ + {.w_px = 13, .glyph_index = 16800}, /*Unicode: U+0079 (y)*/ + {.w_px = 10, .glyph_index = 17010}, /*Unicode: U+007a (z)*/ + {.w_px = 6, .glyph_index = 17160}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 17250}, /*Unicode: U+007c (|)*/ + {.w_px = 5, .glyph_index = 17310}, /*Unicode: U+007d (})*/ + {.w_px = 8, .glyph_index = 17400}, /*Unicode: U+007e (~)*/ + +#elif USE_INTERUI_30 == 8 + {.w_px = 8, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 3, .glyph_index = 240}, /*Unicode: U+0021 (!)*/ + {.w_px = 6, .glyph_index = 330}, /*Unicode: U+0022 (")*/ + {.w_px = 13, .glyph_index = 510}, /*Unicode: U+0023 (#)*/ + {.w_px = 12, .glyph_index = 900}, /*Unicode: U+0024 ($)*/ + {.w_px = 18, .glyph_index = 1260}, /*Unicode: U+0025 (%)*/ + {.w_px = 16, .glyph_index = 1800}, /*Unicode: U+0026 (&)*/ + {.w_px = 3, .glyph_index = 2280}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 2370}, /*Unicode: U+0028 (()*/ + {.w_px = 7, .glyph_index = 2550}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 2760}, /*Unicode: U+002a (*)*/ + {.w_px = 16, .glyph_index = 3030}, /*Unicode: U+002b (+)*/ + {.w_px = 3, .glyph_index = 3510}, /*Unicode: U+002c (,)*/ + {.w_px = 8, .glyph_index = 3600}, /*Unicode: U+002d (-)*/ + {.w_px = 3, .glyph_index = 3840}, /*Unicode: U+002e (.)*/ + {.w_px = 11, .glyph_index = 3930}, /*Unicode: U+002f (/)*/ + {.w_px = 13, .glyph_index = 4260}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 4650}, /*Unicode: U+0031 (1)*/ + {.w_px = 13, .glyph_index = 4860}, /*Unicode: U+0032 (2)*/ + {.w_px = 14, .glyph_index = 5250}, /*Unicode: U+0033 (3)*/ + {.w_px = 13, .glyph_index = 5670}, /*Unicode: U+0034 (4)*/ + {.w_px = 14, .glyph_index = 6060}, /*Unicode: U+0035 (5)*/ + {.w_px = 13, .glyph_index = 6480}, /*Unicode: U+0036 (6)*/ + {.w_px = 13, .glyph_index = 6870}, /*Unicode: U+0037 (7)*/ + {.w_px = 13, .glyph_index = 7260}, /*Unicode: U+0038 (8)*/ + {.w_px = 13, .glyph_index = 7650}, /*Unicode: U+0039 (9)*/ + {.w_px = 3, .glyph_index = 8040}, /*Unicode: U+003a (:)*/ + {.w_px = 3, .glyph_index = 8130}, /*Unicode: U+003b (;)*/ + {.w_px = 18, .glyph_index = 8220}, /*Unicode: U+003c (<)*/ + {.w_px = 16, .glyph_index = 8760}, /*Unicode: U+003d (=)*/ + {.w_px = 18, .glyph_index = 9240}, /*Unicode: U+003e (>)*/ + {.w_px = 12, .glyph_index = 9780}, /*Unicode: U+003f (?)*/ + {.w_px = 18, .glyph_index = 10140}, /*Unicode: U+0040 (@)*/ + {.w_px = 17, .glyph_index = 10680}, /*Unicode: U+0041 (A)*/ + {.w_px = 13, .glyph_index = 11190}, /*Unicode: U+0042 (B)*/ + {.w_px = 15, .glyph_index = 11580}, /*Unicode: U+0043 (C)*/ + {.w_px = 17, .glyph_index = 12030}, /*Unicode: U+0044 (D)*/ + {.w_px = 12, .glyph_index = 12540}, /*Unicode: U+0045 (E)*/ + {.w_px = 11, .glyph_index = 12900}, /*Unicode: U+0046 (F)*/ + {.w_px = 17, .glyph_index = 13230}, /*Unicode: U+0047 (G)*/ + {.w_px = 14, .glyph_index = 13740}, /*Unicode: U+0048 (H)*/ + {.w_px = 3, .glyph_index = 14160}, /*Unicode: U+0049 (I)*/ + {.w_px = 11, .glyph_index = 14250}, /*Unicode: U+004a (J)*/ + {.w_px = 14, .glyph_index = 14580}, /*Unicode: U+004b (K)*/ + {.w_px = 9, .glyph_index = 15000}, /*Unicode: U+004c (L)*/ + {.w_px = 23, .glyph_index = 15270}, /*Unicode: U+004d (M)*/ + {.w_px = 16, .glyph_index = 15960}, /*Unicode: U+004e (N)*/ + {.w_px = 19, .glyph_index = 16440}, /*Unicode: U+004f (O)*/ + {.w_px = 11, .glyph_index = 17010}, /*Unicode: U+0050 (P)*/ + {.w_px = 19, .glyph_index = 17340}, /*Unicode: U+0051 (Q)*/ + {.w_px = 13, .glyph_index = 17910}, /*Unicode: U+0052 (R)*/ + {.w_px = 12, .glyph_index = 18300}, /*Unicode: U+0053 (S)*/ + {.w_px = 14, .glyph_index = 18660}, /*Unicode: U+0054 (T)*/ + {.w_px = 16, .glyph_index = 19080}, /*Unicode: U+0055 (U)*/ + {.w_px = 18, .glyph_index = 19560}, /*Unicode: U+0056 (V)*/ + {.w_px = 27, .glyph_index = 20100}, /*Unicode: U+0057 (W)*/ + {.w_px = 15, .glyph_index = 20910}, /*Unicode: U+0058 (X)*/ + {.w_px = 15, .glyph_index = 21360}, /*Unicode: U+0059 (Y)*/ + {.w_px = 15, .glyph_index = 21810}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 22260}, /*Unicode: U+005b ([)*/ + {.w_px = 11, .glyph_index = 22440}, /*Unicode: U+005c (\)*/ + {.w_px = 7, .glyph_index = 22770}, /*Unicode: U+005d (])*/ + {.w_px = 13, .glyph_index = 22980}, /*Unicode: U+005e (^)*/ + {.w_px = 12, .glyph_index = 23370}, /*Unicode: U+005f (_)*/ + {.w_px = 6, .glyph_index = 23730}, /*Unicode: U+0060 (`)*/ + {.w_px = 12, .glyph_index = 23910}, /*Unicode: U+0061 (a)*/ + {.w_px = 13, .glyph_index = 24270}, /*Unicode: U+0062 (b)*/ + {.w_px = 11, .glyph_index = 24660}, /*Unicode: U+0063 (c)*/ + {.w_px = 13, .glyph_index = 24990}, /*Unicode: U+0064 (d)*/ + {.w_px = 12, .glyph_index = 25380}, /*Unicode: U+0065 (e)*/ + {.w_px = 6, .glyph_index = 25740}, /*Unicode: U+0066 (f)*/ + {.w_px = 12, .glyph_index = 25920}, /*Unicode: U+0067 (g)*/ + {.w_px = 11, .glyph_index = 26280}, /*Unicode: U+0068 (h)*/ + {.w_px = 3, .glyph_index = 26610}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 26700}, /*Unicode: U+006a (j)*/ + {.w_px = 12, .glyph_index = 26910}, /*Unicode: U+006b (k)*/ + {.w_px = 4, .glyph_index = 27270}, /*Unicode: U+006c (l)*/ + {.w_px = 19, .glyph_index = 27390}, /*Unicode: U+006d (m)*/ + {.w_px = 11, .glyph_index = 27960}, /*Unicode: U+006e (n)*/ + {.w_px = 14, .glyph_index = 28290}, /*Unicode: U+006f (o)*/ + {.w_px = 13, .glyph_index = 28710}, /*Unicode: U+0070 (p)*/ + {.w_px = 13, .glyph_index = 29100}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 29490}, /*Unicode: U+0072 (r)*/ + {.w_px = 11, .glyph_index = 29700}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 30030}, /*Unicode: U+0074 (t)*/ + {.w_px = 11, .glyph_index = 30270}, /*Unicode: U+0075 (u)*/ + {.w_px = 12, .glyph_index = 30600}, /*Unicode: U+0076 (v)*/ + {.w_px = 21, .glyph_index = 30960}, /*Unicode: U+0077 (w)*/ + {.w_px = 13, .glyph_index = 31590}, /*Unicode: U+0078 (x)*/ + {.w_px = 13, .glyph_index = 31980}, /*Unicode: U+0079 (y)*/ + {.w_px = 10, .glyph_index = 32370}, /*Unicode: U+007a (z)*/ + {.w_px = 6, .glyph_index = 32670}, /*Unicode: U+007b ({)*/ + {.w_px = 3, .glyph_index = 32850}, /*Unicode: U+007c (|)*/ + {.w_px = 5, .glyph_index = 32940}, /*Unicode: U+007d (})*/ + {.w_px = 8, .glyph_index = 33090}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t interui_30 = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 30, /*Font height in pixels*/ + //.glyph_bitmap = interui_30_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x7900), + .glyph_dsc = interui_30_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_INTERUI_30 == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_INTERUI_30 == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 0, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_INTERUI_30*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c new file mode 100644 index 0000000..16cbaea --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_font_built_in.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_font_builtin.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void) +{ + /*InterUI 20*/ +#if USE_INTERUI_20 != 0 + lv_font_add(&interui_20, NULL); +#endif + + /*SYMBOL 20*/ +#if USE_HEKATE_SYMBOL_20 != 0 +#if USE_INTERUI_20 != 0 + lv_font_add(&hekate_symbol_20, &interui_20); +#else + lv_font_add(&hekate_symbol_20, NULL); +#endif +#endif + + /*InterUI 30*/ +#if USE_INTERUI_30 != 0 + lv_font_add(&interui_30, NULL); +#endif + + /*SYMBOL 30*/ +#if USE_HEKATE_SYMBOL_30 != 0 +#if USE_INTERUI_30 != 0 + lv_font_add(&hekate_symbol_30, &interui_30); +#else + lv_font_add(&hekate_symbol_30, NULL); +#endif +#endif + + /*MONO 12*/ +#if USE_UBUNTU_MONO != 0 + lv_font_add(&ubuntu_mono, NULL); +#if USE_INTERUI_20 != 0 + lv_font_add(&hekate_symbol_20, &ubuntu_mono); +#endif +#endif + + /*Symbol 120*/ +#if USE_HEKATE_SYMBOL_120 != 0 + lv_font_add(&hekate_symbol_120, NULL); +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h new file mode 100644 index 0000000..519471f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_font_builtin.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_font_builtin.h + * + */ + +#ifndef LV_FONT_BUILTIN_H +#define LV_FONT_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void); + +/********************** + * MACROS + **********************/ + +/********************** + * FONT DECLARATIONS + **********************/ + +/*20 px */ +#if USE_INTERUI_20 +LV_FONT_DECLARE(interui_20); +#endif + +#if USE_HEKATE_SYMBOL_20 +LV_FONT_DECLARE(hekate_symbol_20); +#endif + +/*30 px */ +#if USE_INTERUI_30 +LV_FONT_DECLARE(interui_30); +#endif + +#if USE_HEKATE_SYMBOL_30 +LV_FONT_DECLARE(hekate_symbol_30); +#endif + +#if USE_UBUNTU_MONO +LV_FONT_DECLARE(ubuntu_mono); +#endif + +#if USE_HEKATE_SYMBOL_120 +LV_FONT_DECLARE(hekate_symbol_120); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FONT_BUILTIN_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk new file mode 100644 index 0000000..d288f8a --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/lv_fonts.mk @@ -0,0 +1,14 @@ +CSRCS += lv_font_builtin.c +CSRCS += hekate_symbol_10.c +CSRCS += hekate_symbol_20.c +CSRCS += hekate_symbol_30.c +CSRCS += hekate_symbol_40.c +CSRCS += interui_12.c +CSRCS += interui_20.c +CSRCS += interui_30.c +CSRCS += interui_40.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts +VPATH += :$(LVGL_DIR)/lvgl/lv_fonts + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts" diff --git a/ariane/src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c b/ariane/src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c new file mode 100644 index 0000000..4c988fc --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_fonts/ubuntu_mono.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../lv_misc/lv_font.h" + +#include + +#if USE_UBUNTU_MONO != 0 /*Can be enabled in lv_conf.h*/ + +/*********************************************************************************** + * UbuntuMono-B.ttf 20 px Font in U+0020 ( ) .. U+007e (~) range with all bpp +***********************************************************************************/ + +/*Store the glyph descriptions*/ +static const lv_font_glyph_dsc_t ubuntu_mono_glyph_dsc[] = +{ +#if USE_UBUNTU_MONO == 4 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 2, .glyph_index = 60}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 80}, /*Unicode: U+0022 (")*/ + {.w_px = 10, .glyph_index = 140}, /*Unicode: U+0023 (#)*/ + {.w_px = 8, .glyph_index = 240}, /*Unicode: U+0024 ($)*/ + {.w_px = 10, .glyph_index = 320}, /*Unicode: U+0025 (%)*/ + {.w_px = 10, .glyph_index = 420}, /*Unicode: U+0026 (&)*/ + {.w_px = 2, .glyph_index = 520}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 540}, /*Unicode: U+0028 (()*/ + {.w_px = 6, .glyph_index = 600}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 660}, /*Unicode: U+002a (*)*/ + {.w_px = 8, .glyph_index = 760}, /*Unicode: U+002b (+)*/ + {.w_px = 4, .glyph_index = 840}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 880}, /*Unicode: U+002d (-)*/ + {.w_px = 4, .glyph_index = 940}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 980}, /*Unicode: U+002f (/)*/ + {.w_px = 8, .glyph_index = 1060}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 1140}, /*Unicode: U+0031 (1)*/ + {.w_px = 8, .glyph_index = 1220}, /*Unicode: U+0032 (2)*/ + {.w_px = 8, .glyph_index = 1300}, /*Unicode: U+0033 (3)*/ + {.w_px = 8, .glyph_index = 1380}, /*Unicode: U+0034 (4)*/ + {.w_px = 8, .glyph_index = 1460}, /*Unicode: U+0035 (5)*/ + {.w_px = 8, .glyph_index = 1540}, /*Unicode: U+0036 (6)*/ + {.w_px = 7, .glyph_index = 1620}, /*Unicode: U+0037 (7)*/ + {.w_px = 8, .glyph_index = 1700}, /*Unicode: U+0038 (8)*/ + {.w_px = 8, .glyph_index = 1780}, /*Unicode: U+0039 (9)*/ + {.w_px = 4, .glyph_index = 1860}, /*Unicode: U+003a (:)*/ + {.w_px = 4, .glyph_index = 1900}, /*Unicode: U+003b (;)*/ + {.w_px = 9, .glyph_index = 1940}, /*Unicode: U+003c (<)*/ + {.w_px = 8, .glyph_index = 2040}, /*Unicode: U+003d (=)*/ + {.w_px = 8, .glyph_index = 2120}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 2200}, /*Unicode: U+003f (?)*/ + {.w_px = 9, .glyph_index = 2280}, /*Unicode: U+0040 (@)*/ + {.w_px = 10, .glyph_index = 2380}, /*Unicode: U+0041 (A)*/ + {.w_px = 8, .glyph_index = 2480}, /*Unicode: U+0042 (B)*/ + {.w_px = 8, .glyph_index = 2560}, /*Unicode: U+0043 (C)*/ + {.w_px = 8, .glyph_index = 2640}, /*Unicode: U+0044 (D)*/ + {.w_px = 8, .glyph_index = 2720}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 2800}, /*Unicode: U+0046 (F)*/ + {.w_px = 8, .glyph_index = 2880}, /*Unicode: U+0047 (G)*/ + {.w_px = 8, .glyph_index = 2960}, /*Unicode: U+0048 (H)*/ + {.w_px = 8, .glyph_index = 3040}, /*Unicode: U+0049 (I)*/ + {.w_px = 8, .glyph_index = 3120}, /*Unicode: U+004a (J)*/ + {.w_px = 9, .glyph_index = 3200}, /*Unicode: U+004b (K)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+004c (L)*/ + {.w_px = 9, .glyph_index = 3380}, /*Unicode: U+004d (M)*/ + {.w_px = 8, .glyph_index = 3480}, /*Unicode: U+004e (N)*/ + {.w_px = 8, .glyph_index = 3560}, /*Unicode: U+004f (O)*/ + {.w_px = 8, .glyph_index = 3640}, /*Unicode: U+0050 (P)*/ + {.w_px = 8, .glyph_index = 3720}, /*Unicode: U+0051 (Q)*/ + {.w_px = 8, .glyph_index = 3800}, /*Unicode: U+0052 (R)*/ + {.w_px = 8, .glyph_index = 3880}, /*Unicode: U+0053 (S)*/ + {.w_px = 8, .glyph_index = 3960}, /*Unicode: U+0054 (T)*/ + {.w_px = 8, .glyph_index = 4040}, /*Unicode: U+0055 (U)*/ + {.w_px = 9, .glyph_index = 4120}, /*Unicode: U+0056 (V)*/ + {.w_px = 9, .glyph_index = 4220}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 4320}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 4420}, /*Unicode: U+0059 (Y)*/ + {.w_px = 8, .glyph_index = 4520}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 4600}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 4660}, /*Unicode: U+005c (\)*/ + {.w_px = 6, .glyph_index = 4740}, /*Unicode: U+005d (])*/ + {.w_px = 10, .glyph_index = 4800}, /*Unicode: U+005e (^)*/ + {.w_px = 10, .glyph_index = 4900}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 5000}, /*Unicode: U+0060 (`)*/ + {.w_px = 8, .glyph_index = 5040}, /*Unicode: U+0061 (a)*/ + {.w_px = 8, .glyph_index = 5120}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 5200}, /*Unicode: U+0063 (c)*/ + {.w_px = 8, .glyph_index = 5280}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 5360}, /*Unicode: U+0065 (e)*/ + {.w_px = 9, .glyph_index = 5460}, /*Unicode: U+0066 (f)*/ + {.w_px = 8, .glyph_index = 5560}, /*Unicode: U+0067 (g)*/ + {.w_px = 8, .glyph_index = 5640}, /*Unicode: U+0068 (h)*/ + {.w_px = 9, .glyph_index = 5720}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 5820}, /*Unicode: U+006a (j)*/ + {.w_px = 9, .glyph_index = 5900}, /*Unicode: U+006b (k)*/ + {.w_px = 8, .glyph_index = 6000}, /*Unicode: U+006c (l)*/ + {.w_px = 8, .glyph_index = 6080}, /*Unicode: U+006d (m)*/ + {.w_px = 8, .glyph_index = 6160}, /*Unicode: U+006e (n)*/ + {.w_px = 8, .glyph_index = 6240}, /*Unicode: U+006f (o)*/ + {.w_px = 8, .glyph_index = 6320}, /*Unicode: U+0070 (p)*/ + {.w_px = 8, .glyph_index = 6400}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 6480}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 6560}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 6640}, /*Unicode: U+0074 (t)*/ + {.w_px = 8, .glyph_index = 6720}, /*Unicode: U+0075 (u)*/ + {.w_px = 9, .glyph_index = 6800}, /*Unicode: U+0076 (v)*/ + {.w_px = 10, .glyph_index = 6900}, /*Unicode: U+0077 (w)*/ + {.w_px = 10, .glyph_index = 7000}, /*Unicode: U+0078 (x)*/ + {.w_px = 9, .glyph_index = 7100}, /*Unicode: U+0079 (y)*/ + {.w_px = 8, .glyph_index = 7200}, /*Unicode: U+007a (z)*/ + {.w_px = 7, .glyph_index = 7280}, /*Unicode: U+007b ({)*/ + {.w_px = 2, .glyph_index = 7360}, /*Unicode: U+007c (|)*/ + {.w_px = 8, .glyph_index = 7380}, /*Unicode: U+007d (})*/ + {.w_px = 9, .glyph_index = 7460}, /*Unicode: U+007e (~)*/ + +#elif USE_UBUNTU_MONO == 8 + {.w_px = 6, .glyph_index = 0}, /*Unicode: U+0020 ( )*/ + {.w_px = 2, .glyph_index = 120}, /*Unicode: U+0021 (!)*/ + {.w_px = 5, .glyph_index = 160}, /*Unicode: U+0022 (")*/ + {.w_px = 10, .glyph_index = 260}, /*Unicode: U+0023 (#)*/ + {.w_px = 8, .glyph_index = 460}, /*Unicode: U+0024 ($)*/ + {.w_px = 10, .glyph_index = 620}, /*Unicode: U+0025 (%)*/ + {.w_px = 10, .glyph_index = 820}, /*Unicode: U+0026 (&)*/ + {.w_px = 2, .glyph_index = 1020}, /*Unicode: U+0027 (')*/ + {.w_px = 6, .glyph_index = 1060}, /*Unicode: U+0028 (()*/ + {.w_px = 6, .glyph_index = 1180}, /*Unicode: U+0029 ())*/ + {.w_px = 9, .glyph_index = 1300}, /*Unicode: U+002a (*)*/ + {.w_px = 8, .glyph_index = 1480}, /*Unicode: U+002b (+)*/ + {.w_px = 4, .glyph_index = 1640}, /*Unicode: U+002c (,)*/ + {.w_px = 5, .glyph_index = 1720}, /*Unicode: U+002d (-)*/ + {.w_px = 4, .glyph_index = 1820}, /*Unicode: U+002e (.)*/ + {.w_px = 8, .glyph_index = 1900}, /*Unicode: U+002f (/)*/ + {.w_px = 8, .glyph_index = 2060}, /*Unicode: U+0030 (0)*/ + {.w_px = 7, .glyph_index = 2220}, /*Unicode: U+0031 (1)*/ + {.w_px = 8, .glyph_index = 2360}, /*Unicode: U+0032 (2)*/ + {.w_px = 8, .glyph_index = 2520}, /*Unicode: U+0033 (3)*/ + {.w_px = 8, .glyph_index = 2680}, /*Unicode: U+0034 (4)*/ + {.w_px = 8, .glyph_index = 2840}, /*Unicode: U+0035 (5)*/ + {.w_px = 8, .glyph_index = 3000}, /*Unicode: U+0036 (6)*/ + {.w_px = 7, .glyph_index = 3160}, /*Unicode: U+0037 (7)*/ + {.w_px = 8, .glyph_index = 3300}, /*Unicode: U+0038 (8)*/ + {.w_px = 8, .glyph_index = 3460}, /*Unicode: U+0039 (9)*/ + {.w_px = 4, .glyph_index = 3620}, /*Unicode: U+003a (:)*/ + {.w_px = 4, .glyph_index = 3700}, /*Unicode: U+003b (;)*/ + {.w_px = 9, .glyph_index = 3780}, /*Unicode: U+003c (<)*/ + {.w_px = 8, .glyph_index = 3960}, /*Unicode: U+003d (=)*/ + {.w_px = 8, .glyph_index = 4120}, /*Unicode: U+003e (>)*/ + {.w_px = 8, .glyph_index = 4280}, /*Unicode: U+003f (?)*/ + {.w_px = 9, .glyph_index = 4440}, /*Unicode: U+0040 (@)*/ + {.w_px = 10, .glyph_index = 4620}, /*Unicode: U+0041 (A)*/ + {.w_px = 8, .glyph_index = 4820}, /*Unicode: U+0042 (B)*/ + {.w_px = 8, .glyph_index = 4980}, /*Unicode: U+0043 (C)*/ + {.w_px = 8, .glyph_index = 5140}, /*Unicode: U+0044 (D)*/ + {.w_px = 8, .glyph_index = 5300}, /*Unicode: U+0045 (E)*/ + {.w_px = 8, .glyph_index = 5460}, /*Unicode: U+0046 (F)*/ + {.w_px = 8, .glyph_index = 5620}, /*Unicode: U+0047 (G)*/ + {.w_px = 8, .glyph_index = 5780}, /*Unicode: U+0048 (H)*/ + {.w_px = 8, .glyph_index = 5940}, /*Unicode: U+0049 (I)*/ + {.w_px = 8, .glyph_index = 6100}, /*Unicode: U+004a (J)*/ + {.w_px = 9, .glyph_index = 6260}, /*Unicode: U+004b (K)*/ + {.w_px = 8, .glyph_index = 6440}, /*Unicode: U+004c (L)*/ + {.w_px = 9, .glyph_index = 6600}, /*Unicode: U+004d (M)*/ + {.w_px = 8, .glyph_index = 6780}, /*Unicode: U+004e (N)*/ + {.w_px = 8, .glyph_index = 6940}, /*Unicode: U+004f (O)*/ + {.w_px = 8, .glyph_index = 7100}, /*Unicode: U+0050 (P)*/ + {.w_px = 8, .glyph_index = 7260}, /*Unicode: U+0051 (Q)*/ + {.w_px = 8, .glyph_index = 7420}, /*Unicode: U+0052 (R)*/ + {.w_px = 8, .glyph_index = 7580}, /*Unicode: U+0053 (S)*/ + {.w_px = 8, .glyph_index = 7740}, /*Unicode: U+0054 (T)*/ + {.w_px = 8, .glyph_index = 7900}, /*Unicode: U+0055 (U)*/ + {.w_px = 9, .glyph_index = 8060}, /*Unicode: U+0056 (V)*/ + {.w_px = 9, .glyph_index = 8240}, /*Unicode: U+0057 (W)*/ + {.w_px = 10, .glyph_index = 8420}, /*Unicode: U+0058 (X)*/ + {.w_px = 10, .glyph_index = 8620}, /*Unicode: U+0059 (Y)*/ + {.w_px = 8, .glyph_index = 8820}, /*Unicode: U+005a (Z)*/ + {.w_px = 6, .glyph_index = 8980}, /*Unicode: U+005b ([)*/ + {.w_px = 8, .glyph_index = 9100}, /*Unicode: U+005c (\)*/ + {.w_px = 6, .glyph_index = 9260}, /*Unicode: U+005d (])*/ + {.w_px = 10, .glyph_index = 9380}, /*Unicode: U+005e (^)*/ + {.w_px = 10, .glyph_index = 9580}, /*Unicode: U+005f (_)*/ + {.w_px = 4, .glyph_index = 9780}, /*Unicode: U+0060 (`)*/ + {.w_px = 8, .glyph_index = 9860}, /*Unicode: U+0061 (a)*/ + {.w_px = 8, .glyph_index = 10020}, /*Unicode: U+0062 (b)*/ + {.w_px = 8, .glyph_index = 10180}, /*Unicode: U+0063 (c)*/ + {.w_px = 8, .glyph_index = 10340}, /*Unicode: U+0064 (d)*/ + {.w_px = 9, .glyph_index = 10500}, /*Unicode: U+0065 (e)*/ + {.w_px = 9, .glyph_index = 10680}, /*Unicode: U+0066 (f)*/ + {.w_px = 8, .glyph_index = 10860}, /*Unicode: U+0067 (g)*/ + {.w_px = 8, .glyph_index = 11020}, /*Unicode: U+0068 (h)*/ + {.w_px = 9, .glyph_index = 11180}, /*Unicode: U+0069 (i)*/ + {.w_px = 7, .glyph_index = 11360}, /*Unicode: U+006a (j)*/ + {.w_px = 9, .glyph_index = 11500}, /*Unicode: U+006b (k)*/ + {.w_px = 8, .glyph_index = 11680}, /*Unicode: U+006c (l)*/ + {.w_px = 8, .glyph_index = 11840}, /*Unicode: U+006d (m)*/ + {.w_px = 8, .glyph_index = 12000}, /*Unicode: U+006e (n)*/ + {.w_px = 8, .glyph_index = 12160}, /*Unicode: U+006f (o)*/ + {.w_px = 8, .glyph_index = 12320}, /*Unicode: U+0070 (p)*/ + {.w_px = 8, .glyph_index = 12480}, /*Unicode: U+0071 (q)*/ + {.w_px = 7, .glyph_index = 12640}, /*Unicode: U+0072 (r)*/ + {.w_px = 8, .glyph_index = 12780}, /*Unicode: U+0073 (s)*/ + {.w_px = 8, .glyph_index = 12940}, /*Unicode: U+0074 (t)*/ + {.w_px = 8, .glyph_index = 13100}, /*Unicode: U+0075 (u)*/ + {.w_px = 9, .glyph_index = 13260}, /*Unicode: U+0076 (v)*/ + {.w_px = 10, .glyph_index = 13440}, /*Unicode: U+0077 (w)*/ + {.w_px = 10, .glyph_index = 13640}, /*Unicode: U+0078 (x)*/ + {.w_px = 9, .glyph_index = 13840}, /*Unicode: U+0079 (y)*/ + {.w_px = 8, .glyph_index = 14020}, /*Unicode: U+007a (z)*/ + {.w_px = 7, .glyph_index = 14180}, /*Unicode: U+007b ({)*/ + {.w_px = 2, .glyph_index = 14320}, /*Unicode: U+007c (|)*/ + {.w_px = 8, .glyph_index = 14360}, /*Unicode: U+007d (})*/ + {.w_px = 9, .glyph_index = 14520}, /*Unicode: U+007e (~)*/ + +#endif +}; + +lv_font_t ubuntu_mono = +{ + .unicode_first = 32, /*First Unicode letter in this font*/ + .unicode_last = 126, /*Last Unicode letter in this font*/ + .h_px = 20, /*Font height in pixels*/ + //.glyph_bitmap = ubuntu_mono_glyph_bitmap, /*Bitmap of glyphs*/ + .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR), + .glyph_dsc = ubuntu_mono_glyph_dsc, /*Description of glyphs*/ + .glyph_cnt = 95, /*Number of glyphs in the font*/ + .unicode_list = NULL, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ + .get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/ + .get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/ +#if USE_UBUNTU_MONO == 4 + .bpp = 4, /*Bit per pixel*/ +#elif USE_UBUNTU_MONO == 8 + .bpp = 8, /*Bit per pixel*/ +#endif + .monospace = 10, /*Fix width (0: if not used)*/ + .next_page = NULL, /*Pointer to a font extension*/ +}; + +#endif /*USE_UBUNTU_MONO*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.h b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.h new file mode 100644 index 0000000..5ab28f2 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.h @@ -0,0 +1,40 @@ +/** + * @file hal.h + * + */ + +#ifndef HAL_H +#define HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.mk b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.mk new file mode 100644 index 0000000..83f4bf1 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal.mk @@ -0,0 +1,8 @@ +CSRCS += lv_hal_disp.c +CSRCS += lv_hal_indev.c +CSRCS += lv_hal_tick.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal +VPATH += :$(LVGL_DIR)/lvgl/lv_hal + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal" diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c new file mode 100644 index 0000000..3be8b92 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.c @@ -0,0 +1,242 @@ + +/** + * @file hal_disp.c + * + * @description HAL layer for display driver + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_disp_t * active; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t * driver) +{ + driver->disp_fill = NULL; + driver->disp_map = NULL; + driver->disp_flush = NULL; + +#if USE_LV_GPU + driver->mem_blend = NULL; + driver->mem_fill = NULL; +#endif + +#if LV_VDB_SIZE + driver->vdb_wr = NULL; +#endif +} + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) +{ + lv_disp_t * node; + + node = lv_mem_alloc(sizeof(lv_disp_t)); + lv_mem_assert(node); + if(node == NULL) return NULL; + + memcpy(&node->driver, driver, sizeof(lv_disp_drv_t)); + node->next = NULL; + + /* Set first display as active by default */ + if(LV_GC_ROOT(_lv_disp_list) == NULL) { + LV_GC_ROOT(_lv_disp_list) = node; + active = node; + lv_obj_invalidate(lv_scr_act()); + } else { + ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next = node; + } + + return node; +} + + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp) +{ + active = disp; + lv_obj_invalidate(lv_scr_act()); +} + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void) +{ + return active; +} + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp) +{ + if(disp == NULL) { + return LV_GC_ROOT(_lv_disp_list); + } else { + if(((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next == NULL) return NULL; + else return ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next; + } +} + +/** + * Write the content of the internal buffer (VDB) to the display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + if(active == NULL) return; + if(active->driver.disp_fill != NULL) active->driver.disp_fill(x1, y1, x2, y2, color); +} + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p) +{ + if(active == NULL) return; + if(active->driver.disp_flush != NULL) { + + LV_LOG_TRACE("disp flush started"); + active->driver.disp_flush(x1, y1, x2, y2, color_p); + LV_LOG_TRACE("disp flush ready"); + + } else { + LV_LOG_WARN("disp flush function registered"); + } +} + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map) +{ + if(active == NULL) return; + if(active->driver.disp_map != NULL) active->driver.disp_map(x1, y1, x2, y2, color_map); +} + +#if USE_LV_GPU + +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa) +{ + if(active == NULL) return; + if(active->driver.mem_blend != NULL) active->driver.mem_blend(dest, src, length, opa); +} + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color) +{ + if(active == NULL) return; + if(active->driver.mem_fill != NULL) active->driver.mem_fill(dest, length, color); +} + +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void) +{ + if(active == NULL) return false; + if(active->driver.mem_blend) return true; + else return false; +} + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void) +{ + if(active == NULL) return false; + if(active->driver.mem_fill) return true; + else return false; +} + +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h new file mode 100644 index 0000000..95b7ab5 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_disp.h @@ -0,0 +1,173 @@ +/** + * @file hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef HAL_DISP_H +#define HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_hal.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Display Driver structure to be registered by HAL + */ +typedef struct _disp_drv_t { + /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ + void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Fill an area with a color on the display*/ + void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + + /*Write pixel map (e.g. image) to the display*/ + void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Optional interface functions to use GPU*/ +#if USE_LV_GPU + /*Blend two memories using opacity (GPU only)*/ + void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + + /*Fill a memory with a color (GPU only)*/ + void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); +#endif + +#if LV_VDB_SIZE + /*Optional: Set a pixel in a buffer according to the requirements of the display*/ + void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#endif +} lv_disp_drv_t; + +typedef struct _disp_t { + lv_disp_drv_t driver; + struct _disp_t *next; +} lv_disp_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t *driver); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp); + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void); + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map); + +#if USE_LV_GPU +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void); + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void); +#endif +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c new file mode 100644 index 0000000..6083c3f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.c @@ -0,0 +1,135 @@ +/** + * @file hal_indev.c + * + * @description Input device HAL interface + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t * driver) +{ + driver->read = NULL; + driver->type = LV_INDEV_TYPE_NONE; + driver->user_data = NULL; +} + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver) +{ + lv_indev_t * node; + + node = lv_mem_alloc(sizeof(lv_indev_t)); + if(!node) return NULL; + + memset(node, 0, sizeof(lv_indev_t)); + memcpy(&node->driver, driver, sizeof(lv_indev_drv_t)); + + node->next = NULL; + node->proc.reset_query = 1; + node->cursor = NULL; + node->group = NULL; + node->btn_points = NULL; + + if(LV_GC_ROOT(_lv_indev_list) == NULL) { + LV_GC_ROOT(_lv_indev_list) = node; + } else { + lv_indev_t * last = LV_GC_ROOT(_lv_indev_list); + while(last->next) + last = last->next; + + last->next = node; + } + + return node; +} + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Give the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev) +{ + + if(indev == NULL) { + return LV_GC_ROOT(_lv_indev_list); + } else { + if(indev->next == NULL) return NULL; + else return indev->next; + } +} + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data) +{ + bool cont = false; + + memset(data, 0, sizeof(lv_indev_data_t)); + data->state = LV_INDEV_STATE_REL; + + if(indev->driver.read) { + data->user_data = indev->driver.user_data; + + LV_LOG_TRACE("idnev read started"); + cont = indev->driver.read(data); + LV_LOG_TRACE("idnev read finished"); + } else { + LV_LOG_WARN("indev function registered"); + } + + return cont; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h new file mode 100644 index 0000000..2355baa --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_indev.h @@ -0,0 +1,166 @@ +/** + * @file hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef HAL_INDEV_H +#define HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_hal.h" +#include +#include "../lv_misc/lv_area.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Possible input device types*/ +enum { + LV_INDEV_TYPE_NONE, /*Show uninitialized state*/ + LV_INDEV_TYPE_POINTER, /*Touch pad, mouse, external button*/ + LV_INDEV_TYPE_KEYPAD, /*Keypad or keyboard*/ + LV_INDEV_TYPE_BUTTON, /*External (hardware button) which is assinged to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/ +}; +typedef uint8_t lv_hal_indev_type_t; + +/*States for input devices*/ +enum { + LV_INDEV_STATE_REL = 0, + LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; + +/*Data type when an input device is read */ +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +/*Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct { + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ +} lv_indev_drv_t; + +struct _lv_obj_t; + +/*Run time data of input devices*/ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; + union { + struct { /*Pointer and button data*/ + lv_point_t act_point; + lv_point_t last_point; + lv_point_t vect; + lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/ + struct _lv_obj_t * act_obj; + struct _lv_obj_t * last_obj; + + /*Flags*/ + uint8_t drag_range_out :1; + uint8_t drag_in_prog :1; + uint8_t wait_unil_release :1; + }; + struct { /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + }; + }; + + uint32_t pr_timestamp; /*Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/ + + /*Flags*/ + uint8_t long_pr_sent :1; + uint8_t reset_query :1; + uint8_t disabled :1; +} lv_indev_proc_t; + +struct _lv_indev_t; + +typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t); + +struct _lv_obj_t; +struct _lv_group_t; + +/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/ +typedef struct _lv_indev_t { + lv_indev_drv_t driver; + lv_indev_proc_t proc; + lv_indev_feedback_t feedback; + uint32_t last_activity_time; + union { + struct _lv_obj_t *cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/ + struct _lv_group_t *group; /*Keypad destination group*/ + const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed here by the buttons*/ + + }; + struct _lv_indev_t *next; +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t *driver); + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev); + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c new file mode 100644 index 0000000..0310092 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.c @@ -0,0 +1,100 @@ +/** + * @file systick.c + * Provide access to the system tick with 1 millisecond resolution + */ + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_hal_tick.h" +#include + +#if LV_TICK_CUSTOM == 1 +#include LV_TICK_CUSTOM_INCLUDE +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static uint32_t sys_time = 0; +static volatile uint8_t tick_irq_flag; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period) +{ + tick_irq_flag = 0; + sys_time += tick_period; +} + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void) +{ +#if LV_TICK_CUSTOM == 0 + uint32_t result; + do { + tick_irq_flag = 1; + result = sys_time; + } while(!tick_irq_flag); /*'lv_tick_inc()' clears this flag which can be in an interrupt. Continue until make a non interrupted cycle */ + + return result; +#else + return LV_TICK_CUSTOM_SYS_TIME_EXPR; +#endif +} + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick) +{ + uint32_t act_time = lv_tick_get(); + + /*If there is no overflow in sys_time simple subtract*/ + if(act_time >= prev_tick) { + prev_tick = act_time - prev_tick; + } else { + prev_tick = UINT32_MAX - prev_tick + 1; + prev_tick += act_time; + } + + return prev_tick; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h new file mode 100644 index 0000000..af3d8ea --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_hal/lv_hal_tick.h @@ -0,0 +1,65 @@ +/** + * @file lv_hal_tick.h + * Provide access to the system tick with 1 millisecond resolution + */ + +#ifndef LV_HAL_TICK_H +#define LV_HAL_TICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period); + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void); + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_HAL_TICK_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.c new file mode 100644 index 0000000..578c556 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.c @@ -0,0 +1,445 @@ +/** + * @file anim.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_anim.h" + +#if USE_LV_ANIMATION +#include +#include +#include "../lv_hal/lv_hal_tick.h" +#include "lv_task.h" +#include "lv_math.h" +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ +#define LV_ANIM_RESOLUTION 1024 +#define LV_ANIM_RES_SHIFT 10 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void anim_task(void * param); +static bool anim_ready_handler(lv_anim_t * a); + +/********************** + * STATIC VARIABLES + **********************/ +static uint32_t last_task_run; +static bool anim_list_changed; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t)); + last_task_run = lv_tick_get(); + lv_task_create(anim_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL); +} + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p) +{ + LV_LOG_TRACE("animation create started") + /* Do not let two animations for the same 'var' with the same 'fp'*/ + if(anim_p->fp != NULL) lv_anim_del(anim_p->var, anim_p->fp); /*fp == NULL would delete all animations of var*/ + + /*Add the new animation to the animation linked list*/ + lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll)); + lv_mem_assert(new_anim); + if(new_anim == NULL) return; + + /*Initialize the animation descriptor*/ + anim_p->playback_now = 0; + memcpy(new_anim, anim_p, sizeof(lv_anim_t)); + + /*Set the start value*/ + if(new_anim->fp != NULL) new_anim->fp(new_anim->var, new_anim->start); + + /* Creating an animation changed the linked list. + * It's important if it happens in a ready callback. (see `anim_task`)*/ + anim_list_changed = true; + + LV_LOG_TRACE("animation created") +} + +/** + * Delete an animation for a variable with a given animator function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to delete all animations of 'var' + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp) +{ + lv_anim_t * a; + lv_anim_t * a_next; + bool del = false; + a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + while(a != NULL) { + /*'a' might be deleted, so get the next object while 'a' is valid*/ + a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + + if(a->var == var && (a->fp == fp || fp == NULL)) { + lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + lv_mem_free(a); + anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in the linked list*/ + del = true; + } + + a = a_next; + } + + return del; +} + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void) +{ + uint16_t cnt = 0; + lv_anim_t * a; + LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++; + + return cnt++; +} + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end) +{ + int32_t d = LV_MATH_ABS((int32_t) start - end); + uint32_t time = (int32_t)((int32_t)(d * 1000) / speed); + + if(time > UINT16_MAX) time = UINT16_MAX; + + if(time == 0) { + time++; + } + + return time; +} + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint16_t step; + if(a->time == a->act_time) step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/ + else step = (a->act_time * LV_ANIM_RESOLUTION) / a->time; + + /* Get the new value which will be proportional to `step` + * and the `start` and `end` values*/ + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> LV_ANIM_RES_SHIFT; + new_value += a->start; + + return new_value; +} + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 1, 1, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 1023, 1023, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 100, 924, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 600, 1300, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a) +{ + /*Calculate the current step*/ + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t diff = (a->end - a->start); + + /*3 bounces has 5 parts: 3 down and 2 up. One part is t / 5 long*/ + + if(t < 408){ + /*Go down*/ + t = (t * 2500) >> 10; /*[0..1024] range*/ + } + else if(t >= 408 && t < 614) { + /*First bounce back*/ + t -= 408; + t = t * 5; /*to [0..1024] range*/ + t = 1024 - t; + diff = diff / 6; + } + else if(t >= 614 && t < 819) { + /*Fall back*/ + t -= 614; + t = t * 5; /*to [0..1024] range*/ + diff = diff / 6; + } + else if(t >= 819 && t < 921) { + /*Second bounce back*/ + t -= 819; + t = t * 10; /*to [0..1024] range*/ + t = 1024 - t; + diff = diff / 16; + } + else if(t >= 921 && t <= 1024) { + /*Fall back*/ + t -= 921; + t = t * 10; /*to [0..1024] range*/ + diff = diff / 16; + } + + if(t > 1024) t = 1024; + + int32_t step = lv_bezier3(t, 1024, 1024, 800, 0); + + int32_t new_value; + + new_value = (int32_t) step * diff; + new_value = new_value >> 10; + new_value = a->end - new_value; + + + return new_value; +} + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t * a) +{ + if(a->act_time >= a->time) return a->end; + else return a->start; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Periodically handle the animations. + * @param param unused + */ +static void anim_task(void * param) +{ + (void)param; + + lv_anim_t * a; + LL_READ(LV_GC_ROOT(_lv_anim_ll), a) { + a->has_run = 0; + } + + uint32_t elaps = lv_tick_elaps(last_task_run); + a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + + while(a != NULL) { + /*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete happened in `anim_ready_handler` + * which could make this linked list reading corrupt because the list is changed meanwhile + */ + anim_list_changed = false; + + if(!a->has_run) { + a->has_run = 1; /*The list readying might be reseted so need to know which anim has run already*/ + a->act_time += elaps; + if(a->act_time >= 0) { + if(a->act_time > a->time) a->act_time = a->time; + + int32_t new_value; + new_value = a->path(a); + + if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/ + + /*If the time is elapsed the animation is ready*/ + if(a->act_time >= a->time) { + anim_ready_handler(a); + } + } + } + + /* If the linked list changed due to anim. delete then it's not safe to continue + * the reading of the list from here -> start from the head*/ + if(anim_list_changed) a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + else a = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + } + + last_task_run = lv_tick_get(); +} + +/** + * Called when an animation is ready to do the necessary thinks + * e.g. repeat, play back, delete etc. + * @param a pointer to an animation descriptor + * @return true: animation delete occurred nnd the `LV_GC_ROOT(_lv_anim_ll)` has changed + * */ +static bool anim_ready_handler(lv_anim_t * a) +{ + + /*Delete the animation if + * - no repeat and no play back (simple one shot animation) + * - no repeat, play back is enabled and play back is ready */ + if((a->repeat == 0 && a->playback == 0) || + (a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) { + void (*cb)(void *) = a->end_cb; + void * p = a->var; + lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + lv_mem_free(a); + anim_list_changed = true; + + /* Call the callback function at the end*/ + /* Check if an animation is deleted in the cb function + * if yes then the caller function has to know this*/ + if(cb != NULL) cb(p); + } + /*If the animation is not deleted then restart it*/ + else { + a->act_time = - a->repeat_pause; /*Restart the animation*/ + /*Swap the start and end values in play back mode*/ + if(a->playback != 0) { + /*If now turning back use the 'playback_pause*/ + if(a->playback_now == 0) a->act_time = - a->playback_pause; + + /*Toggle the play back state*/ + a->playback_now = a->playback_now == 0 ? 1 : 0; + /*Swap the start and end values*/ + int32_t tmp; + tmp = a->start; + a->start = a->end; + a->end = tmp; + } + } + + return anim_list_changed; +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.h new file mode 100644 index 0000000..6625ae2 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_anim.h @@ -0,0 +1,176 @@ +/** + * @file anim.h + * + */ + +#ifndef ANIM_H +#define ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ANIMATION + +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_t; + +typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*); + +typedef void (*lv_anim_fp_t)(void *, int32_t); +typedef void (*lv_anim_cb_t)(void *); + +typedef struct _lv_anim_t +{ + void * var; /*Variable to animate*/ + lv_anim_fp_t fp; /*Animator function*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready*/ + lv_anim_path_t path; /*An array with the steps of animations*/ + int32_t start; /*Start value*/ + int32_t end; /*End value*/ + uint16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ + /*Animation system use these - user shouldn't set*/ + uint8_t playback_now :1; /*Play back is in progress*/ + uint32_t has_run :1; /*Indicates the animation has run it this round*/ +} lv_anim_t; + +/*Example initialization +lv_anim_t a; +a.var = obj; +a.start = lv_obj_get_height(obj); +a.end = new_height; +a.fp = (lv_anim_fp_t)lv_obj_set_height; +a.path = lv_anim_path_linear; +a.end_cb = NULL; +a.act_time = 0; +a.time = 200; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +lv_anim_create(&a); + */ +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void); + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p); + +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp); + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void); + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t *a); + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t *a); + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t *a); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ANIMATION == 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_H*/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.c new file mode 100644 index 0000000..f340690 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.c @@ -0,0 +1,200 @@ +/** + * @file lv_area.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_area.h" +#include "lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2) +{ + area_p->x1 = x1; + area_p->y1 = y1; + area_p->x2 = x2; + area_p->y2 = y2; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w) +{ + area_p->x2 = area_p->x1 + w - 1; +} + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h) +{ + area_p->y2 = area_p->y1 + h - 1; +} + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y) +{ + lv_coord_t w = lv_area_get_width(area_p); + lv_coord_t h = lv_area_get_height(area_p); + area_p->x1 = x; + area_p->y1 = y; + lv_area_set_width(area_p, w); + lv_area_set_height(area_p, h); +} + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p) +{ + uint32_t size; + + size = (uint32_t)(area_p->x2 - area_p->x1 + 1) * + (area_p->y2 - area_p->y1 + 1); + + return size; +} + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + /* Get the smaller area from 'a1_p' and 'a2_p' */ + res_p->x1 = LV_MATH_MAX(a1_p->x1, a2_p->x1); + res_p->y1 = LV_MATH_MAX(a1_p->y1, a2_p->y1); + res_p->x2 = LV_MATH_MIN(a1_p->x2, a2_p->x2); + res_p->y2 = LV_MATH_MIN(a1_p->y2, a2_p->y2); + + /*If x1 or y1 greater then x2 or y2 then the areas union is empty*/ + bool union_ok = true; + if((res_p->x1 > res_p->x2) || + (res_p->y1 > res_p->y2)) { + union_ok = false; + } + + return union_ok; +} +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + a_res_p->x1 = LV_MATH_MIN(a1_p->x1, a2_p->x1); + a_res_p->y1 = LV_MATH_MIN(a1_p->y1, a2_p->y1); + a_res_p->x2 = LV_MATH_MAX(a1_p->x2, a2_p->x2); + a_res_p->y2 = LV_MATH_MAX(a1_p->y2, a2_p->y2); +} + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p) +{ + bool is_on = false; + + if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) && + ((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) { + is_on = true; + } + + return is_on; +} + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p) +{ + if((a1_p->x1 <= a2_p->x2) && + (a1_p->x2 >= a2_p->x1) && + (a1_p->y1 <= a2_p->y2) && + (a1_p->y2 >= a2_p->y1)) { + return true; + } else { + return false; + } + +} + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be in 'aholder_p' + * @param aholder pointer to an area which could involve 'ain_p' + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p) +{ + bool is_in = false; + + if(ain_p->x1 >= aholder_p->x1 && + ain_p->y1 >= aholder_p->y1 && + ain_p->x2 <= aholder_p->x2 && + ain_p->y2 <= aholder_p->y2) { + is_in = true; + } + + return is_in; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.h new file mode 100644 index 0000000..63ea059 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_area.h @@ -0,0 +1,168 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */ +#define LV_COORD_MIN (-16384) + +/********************** + * TYPEDEFS + **********************/ +typedef int16_t lv_coord_t; + +typedef struct +{ + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct +{ + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2); + +/** + * Copy an area + * @param dest pointer to the destination area + * @param src pointer to the source area + */ +inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) +{ + memcpy(dest, src, sizeof(lv_area_t)); +} + +/** + * Get the width of an area + * @param area_p pointer to an area + * @return the width of the area (if x1 == x2 -> width = 1) + */ +static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p) +{ + return area_p->x2 - area_p->x1 + 1; +} + +/** + * Get the height of an area + * @param area_p pointer to an area + * @return the height of the area (if y1 == y2 -> height = 1) + */ +static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p) +{ + return area_p->y2 - area_p->y1 + 1; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w); + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p); + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored her + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be on aholder_p + * @param aholder pointer to an area which could involve ain_p + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.c new file mode 100644 index 0000000..d89d833 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.c @@ -0,0 +1,79 @@ +/** + * @file lv_circ.c + * Circle drawing algorithm (with Bresenham) + * Only a 1/8 circle is calculated. Use CIRC_OCT1_X, CIRC_OCT1_Y macros to get + * the other octets. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_circ.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius) +{ + c->x = radius; + c->y = 0; + *tmp = 1 - radius; +} + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c) +{ + return c->y <= c->x ? true : false; +} + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp) +{ + c->y++; + + if(*tmp <= 0) { + (*tmp) += 2 * c->y + 1; // Change in decision criterion for y -> y+1 + } else { + c->x--; + (*tmp) += 2 * (c->y - c->x) + 1; // Change for y -> y+1, x -> x-1 + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.h new file mode 100644 index 0000000..bc1c1dd --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_circ.h @@ -0,0 +1,80 @@ +/** + * @file lv_circ.h + * + */ + +#ifndef LV_CIRC_H +#define LV_CIRC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_area.h" +#include + +/********************* + * DEFINES + *********************/ +#define LV_CIRC_OCT1_X(p) (p.x) +#define LV_CIRC_OCT1_Y(p) (p.y) +#define LV_CIRC_OCT2_X(p) (p.y) +#define LV_CIRC_OCT2_Y(p) (p.x) +#define LV_CIRC_OCT3_X(p) (-p.y) +#define LV_CIRC_OCT3_Y(p) (p.x) +#define LV_CIRC_OCT4_X(p) (-p.x) +#define LV_CIRC_OCT4_Y(p) (p.y) +#define LV_CIRC_OCT5_X(p) (-p.x) +#define LV_CIRC_OCT5_Y(p) (-p.y) +#define LV_CIRC_OCT6_X(p) (-p.y) +#define LV_CIRC_OCT6_Y(p) (-p.x) +#define LV_CIRC_OCT7_X(p) (p.y) +#define LV_CIRC_OCT7_Y(p) (-p.x) +#define LV_CIRC_OCT8_X(p) (p.x) +#define LV_CIRC_OCT8_Y(p) (-p.y) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c); + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.c new file mode 100644 index 0000000..8c12193 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_color.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_color.h" + +/********************* + * DEFINES + *********************/ + +#define HUE_DEGREE 512 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val) +{ + uint8_t r, g, b; + + uint32_t h = (hue * 360 * HUE_DEGREE -1) / 360; + uint32_t s = sat * 255 / 100; + uint32_t v = val * 255 / 100; + uint32_t p = (256 * v - s * v) / 256; + uint32_t region = h / (60 * 512); + + if(sat == 0) + return LV_COLOR_MAKE(v, v, v); + + if (region & 1) + { + uint32_t q = (256 * 60 * HUE_DEGREE * v - h * s * v + 60 * HUE_DEGREE * s * v * region) / + (256 * 60 * HUE_DEGREE); + + switch (region) + { + case 1: + r = q; + g = v; + b = p; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 5: + default: + r = v; + g = p; + b = q; + break; + } + } + else + { + uint32_t t = (256 * 60 * HUE_DEGREE * v + h * s * v - 60 * HUE_DEGREE * s * v * (region + 1)) / + (256 * 60 * HUE_DEGREE); + + switch (region) + { + case 0: + r = v; + g = t; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 4: + default: + r = t; + g = p; + b = v; + break; + } + } + + return LV_COLOR_MAKE(r, g, b); +} + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b) +{ + lv_color_hsv_t hsv; + uint8_t rgbMin, rgbMax; + + rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b); + rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b); + + hsv.v = rgbMax; + if(hsv.v == 0) { + hsv.h = 0; + hsv.s = 0; + return hsv; + } + + hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v; + if(hsv.s == 0) { + hsv.h = 0; + return hsv; + } + + if(rgbMax == r) + hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin); + else if(rgbMax == g) + hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin); + else + hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin); + + return hsv; +} diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.h new file mode 100644 index 0000000..3459b63 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_color.h @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +/*Error checking*/ +#if LV_COLOR_DEPTH == 24 +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#endif + +#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0 +#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h" +#endif + +#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0 +#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h" +#endif + + +#include + +/********************* + * DEFINES + *********************/ +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80) +#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00) + +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; + +#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ + +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_SIZE 16 +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_SIZE 32 +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef union +{ + uint8_t blue :1; + uint8_t green :1; + uint8_t red :1; + uint8_t full :1; +} lv_color1_t; + +typedef union +{ + struct + { + uint8_t blue :2; + uint8_t green :3; + uint8_t red :3; + }; + uint8_t full; +} lv_color8_t; + +typedef union +{ + struct + { +#if LV_COLOR_16_SWAP == 0 + uint16_t blue :5; + uint16_t green :6; + uint16_t red :5; +#else + uint16_t green_h :3; + uint16_t red :5; + uint16_t blue :5; + uint16_t green_l :3; +#endif + }; + uint16_t full; +} lv_color16_t; + +typedef union +{ + struct + { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +#if LV_COLOR_DEPTH == 1 +typedef uint8_t lv_color_int_t; +typedef lv_color1_t lv_color_t; +#elif LV_COLOR_DEPTH == 8 +typedef uint8_t lv_color_int_t; +typedef lv_color8_t lv_color_t; +#elif LV_COLOR_DEPTH == 16 +typedef uint16_t lv_color_int_t; +typedef lv_color16_t lv_color_t; +#elif LV_COLOR_DEPTH == 32 +typedef uint32_t lv_color_int_t; +typedef lv_color32_t lv_color_t; +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +typedef uint8_t lv_opa_t; + +typedef struct +{ + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*In color conversations: + * - When converting to bigger color type the LSB weight of 1 LSB is calculated + * E.g. 16 bit Red has 5 bits + * 8 bit Red has 2 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 2 bits + * 16 bit Red has 5 bits + * ---------------------- + * Shift right with 5 - 3 = 2 + */ + +static inline uint8_t lv_color_to1(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + return color.full; +#elif LV_COLOR_DEPTH == 8 + if((color.red & 0x4) || + (color.green & 0x4) || + (color.blue & 0x2)) { + return 1; + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + if((color.red & 0x10) || + (color.green & 0x20) || + (color.blue & 0x10)) { + return 1; +# else + if((color.red & 0x10) || + (color.green_h & 0x20) || + (color.blue & 0x10)) { + return 1; +# endif + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((color.red & 0x80) || + (color.green & 0x80) || + (color.blue & 0x80)) { + return 1; + } else { + return 0; + } +#endif +} + +static inline uint8_t lv_color_to8(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFF; +#elif LV_COLOR_DEPTH == 8 + return color.full; +#elif LV_COLOR_DEPTH == 16 + +# if LV_COLOR_16_SWAP == 0 + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green >> 3; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# else + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green_h; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + ret.red = color.red >> 5; /* 8 - 3 = 5*/ + ret.green = color.green >> 5; /* 8 - 3 = 5*/ + ret.blue = color.blue >> 6; /* 8 - 2 = 6*/ + return ret.full; +#endif +} + +static inline uint16_t lv_color_to16(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ +# else + ret.red = color.red * 4; + uint8_t g_tmp = color.green * 9; + ret.green_h = (g_tmp & 0x1F) >> 3; + ret.green_l = g_tmp & 0x07; + ret.blue = color.blue * 10; +# endif + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red >> 3; /* 8 - 5 = 3*/ + ret.green = color.green >> 2; /* 8 - 6 = 2*/ + ret.blue = color.blue >> 3; /* 8 - 5 = 3*/ +# else + ret.red = color.red >> 3; + ret.green_h = (color.green & 0xE0) >> 5; + ret.green_l = (color.green & 0x1C) >> 2; + ret.blue = color.blue >> 3; +# endif + return ret.full; +#endif +} + +static inline uint32_t lv_color_to32(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + ret.alpha = 0xFF; + return ret.full; +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# else + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +static inline lv_color_t lv_color_mix(const lv_color_t c1, const lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 && LV_COLOR_DEPTH != 32 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + ret.red = (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP + /*If swapped Green is in 2 parts*/ + uint16_t g_1 = (c1.green_h << 3) + c1.green_l; + uint16_t g_2 = (c2.green_h << 3) + c2.green_l; + uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8; + ret.green_h = g_out >> 3; + ret.green_l = g_out & 0x7; +# else + ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8; +# endif + ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8; +#else +# if LV_COLOR_DEPTH == 32 + uint32_t rb = (((c1.full & 0x00FF00FF) * mix) + ((c2.full & 0x00FF00FF) * (255 - mix))) >> 8; + uint32_t g = (((((c1.full & 0x0000FF00) >> 8) * mix) + (((c2.full & 0x0000FF00) >> 8) * (255 - mix))) >> 8) << 8; + ret.full = 0xFF000000 | (0x00FF00FF & rb) | (0x0000FF00 & g); +# else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +# endif +#endif + + return ret; +} + +/** + * Get the brightness of a color + * @param color a color + * @return the brightness [0..255] + */ +static inline uint8_t lv_color_brightness(lv_color_t color) +{ + lv_color32_t c32; + c32.full = lv_color_to32(color); + uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green; + return (uint16_t) bright >> 3; +} + +/* The most simple macro to create a color from R,G and B values + * The order of bit field is different on Big-endian and Little-endian machines*/ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}}) +# else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}}) +# endif +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ +#endif +#else +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}}) +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/ +#endif +#endif + +#if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set. +#define LV_COLOR_HEX(c) ((lv_color_t){.full = (c | 0xFF000000)}) +#else +#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)c >> 16) & 0xFF), \ + ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ + ((uint32_t) c & 0xFF)) +#endif + +/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ + ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ + ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) + + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val); + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_COLOR*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.c new file mode 100644 index 0000000..0aa7fe2 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.c @@ -0,0 +1,269 @@ +/** + * @file lv_font.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_font.h" +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void) +{ + lv_font_builtin_init(); +} + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t * child, lv_font_t * parent) +{ + if(parent == NULL) return; + + while(parent->next_page != NULL) { + parent = parent->next_page; /*Got to the last page and add the new font there*/ + } + + parent->next_page = child; + +} + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent) +{ + if(parent == NULL) return; + if(child == NULL) return; + + while(parent->next_page != child) { + parent = parent->next_page; /*Got to the last page and add the new font there*/ + } + + parent->next_page = child->next_page; +} + + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) { + /*Glyph found*/ + if(font_i->monospace) return true; + return false; + } + + font_i = font_i->next_page; + } + + return 0; +} + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + while(font_i != NULL) { + const uint8_t * bitmap = font_i->get_bitmap(font_i, letter); + if(bitmap) return bitmap; + + font_i = font_i->next_page; + } + + return NULL; +} + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) { + /*Glyph found*/ + uint8_t m = font_i->monospace; + if(m) w = m; + return w; + } + + font_i = font_i->next_page; + } + + return 0; + +} + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter) +{ + const lv_font_t * font_i = font_p; + int16_t w; + while(font_i != NULL) { + w = font_i->get_width(font_i, letter); + if(w >= 0) return w; + + font_i = font_i->next_page; + } + + return 0; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter) +{ + const lv_font_t * font_i = font; + while(font_i != NULL) { + if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) { + return font_i->bpp; + } + font_i = font_i->next_page; + } + + return 0; + +} + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL; + + uint32_t index = (unicode_letter - font->unicode_first); + return &font->glyph_bitmap[font->glyph_dsc[index].glyph_index]; +} + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL; + + uint32_t i; + for(i = 0; font->unicode_list[i] != 0; i++) { + if(font->unicode_list[i] == unicode_letter) { + return &font->glyph_bitmap[font->glyph_dsc[i].glyph_index]; + } + } + + return NULL; +} + +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) { + return -1; + } + + uint32_t index = (unicode_letter - font->unicode_first); + return font->glyph_dsc[index].w_px; +} + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter) +{ + /*Check the range*/ + if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return -1; + + uint32_t i; + for(i = 0; font->unicode_list[i] != 0; i++) { + if(font->unicode_list[i] == unicode_letter) { + return font->glyph_dsc[i].w_px; + } + } + + return -1; +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.h new file mode 100644 index 0000000..047de22 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_font.h @@ -0,0 +1,191 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include + +#include "lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t w_px :8; + uint32_t glyph_index :24; +} lv_font_glyph_dsc_t; + +typedef struct +{ + uint32_t unicode :21; + uint32_t glyph_dsc_index :11; +} lv_font_unicode_map_t; + +typedef struct _lv_font_struct +{ + uint32_t unicode_first; + uint32_t unicode_last; + const uint8_t * glyph_bitmap; + const lv_font_glyph_dsc_t * glyph_dsc; + const uint32_t * unicode_list; + const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/ + int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/ + struct _lv_font_struct * next_page; /*Pointer to a font extension*/ + uint32_t h_px :8; + uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/ + uint32_t monospace :8; /*Fix width (0: normal width)*/ + uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/ +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void); + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t *child, lv_font_t *parent); + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent); + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter); + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter); + + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the height of a font + * @param font_p pointer to a font + * @return the height of a font + */ +static inline uint8_t lv_font_get_height(const lv_font_t * font_p) +{ + return font_p->h_px; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter); +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter); + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name; + + +/********************** + * ADD BUILT IN FONTS + **********************/ +#include "../lv_fonts/lv_font_builtin.h" + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_FONT*/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.c new file mode 100644 index 0000000..1828e39 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.c @@ -0,0 +1,627 @@ +/** + * @file lv_fs.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_fs.h" +#if USE_LV_FILESYSTEM + +#include "lv_ll.h" +#include +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ + +/* "free" is used as a function pointer (in lv_fs_drv_t). + * We must make sure "free" was not defined to a platform specific + * free function, otherwise compilation would fail. + */ +#ifdef free +#undef free +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static const char * lv_fs_get_real_path(const char * path); +static lv_fs_drv_t * lv_fs_get_drv(char letter); + + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t)); +} + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter) +{ + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(drv == NULL) return false; /*An unknown driver in not ready*/ + + if(drv->ready == NULL) return true; /*Assume the driver is always ready if no handler provided*/ + + return drv->ready(); +} + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode) +{ + file_p->drv = NULL; + file_p->file_d = NULL; + + if(path == NULL) return LV_FS_RES_INV_PARAM; + + char letter = path[0]; + + file_p->drv = lv_fs_get_drv(letter); + + if(file_p->drv == NULL) { + file_p->file_d = NULL; + return LV_FS_RES_NOT_EX; + } + + if(file_p->drv->ready != NULL) { + if(file_p->drv->ready() == false) { + file_p->drv = NULL; + file_p->file_d = NULL; + return LV_FS_RES_HW_ERR; + } + } + + file_p->file_d = lv_mem_alloc(file_p->drv->file_size); + lv_mem_assert(file_p->file_d); + if(file_p->file_d == NULL) { + file_p->drv = NULL; + return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + } + + if(file_p->drv->open == NULL) { + return LV_FS_RES_NOT_IMP; + } + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode); + + if(res != LV_FS_RES_OK) { + lv_mem_free(file_p->file_d); + file_p->file_d = NULL; + file_p->drv = NULL; + } + + return res; +} + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->close == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->close(file_p->file_d); + + lv_mem_free(file_p->file_d); /*Clean up*/ + file_p->file_d = NULL; + file_p->drv = NULL; + file_p->file_d = NULL; + + return res; +} + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove(const char * path) +{ + if(path == NULL) return LV_FS_RES_INV_PARAM; + lv_fs_drv_t * drv = NULL; + + char letter = path[0]; + + drv = lv_fs_get_drv(letter); + if(drv == NULL) return LV_FS_RES_NOT_EX; + if(drv->ready != NULL) { + if(drv->ready() == false) return LV_FS_RES_HW_ERR; + } + + if(drv->remove == NULL) return LV_FS_RES_NOT_IMP; + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = drv->remove(real_path); + + return res; +} + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br) +{ + if(br != NULL) *br = 0; + if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM; + if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP; + + uint32_t br_tmp = 0; + lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp); + if(br != NULL) *br = br_tmp; + + return res; +} + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw) +{ + if(bw != NULL) *bw = 0; + + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->write == NULL) { + return LV_FS_RES_NOT_IMP; + } + + uint32_t bw_tmp = 0; + lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp); + if(bw != NULL) *bw = bw_tmp; + + return res; +} + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->seek == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos); + + return res; +} + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos) +{ + if(file_p->drv == NULL) { + pos = 0; + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->tell == NULL) { + pos = 0; + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos); + + return res; +} + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->tell == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = file_p->drv->trunc(file_p->file_d); + + return res; +} +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size) +{ + if(file_p->drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP; + + + if(size == NULL) return LV_FS_RES_INV_PARAM; + + lv_fs_res_t res = file_p->drv->size(file_p->file_d, size); + + return res; +} + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname) +{ + if(!oldname || !newname) return LV_FS_RES_INV_PARAM; + + char letter = oldname[0]; + + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(!drv) { + return LV_FS_RES_NOT_EX; + } + + if(drv->ready != NULL) { + if(drv->ready() == false) { + return LV_FS_RES_HW_ERR; + } + } + + if(drv->rename == NULL) return LV_FS_RES_NOT_IMP; + + const char * old_real = lv_fs_get_real_path(oldname); + const char * new_real = lv_fs_get_real_path(newname); + lv_fs_res_t res = drv->rename(old_real, new_real); + + return res; +} + + +/** + * Initialize a 'fs_read_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) +{ + if(path == NULL) return LV_FS_RES_INV_PARAM; + + char letter = path[0]; + + rddir_p->drv = lv_fs_get_drv(letter); + + if(rddir_p->drv == NULL) { + rddir_p->dir_d = NULL; + return LV_FS_RES_NOT_EX; + } + + rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size); + lv_mem_assert(rddir_p->dir_d); + if(rddir_p->dir_d == NULL) { + rddir_p->dir_d = NULL; + return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + } + + if(rddir_p->drv->dir_open == NULL) { + return LV_FS_RES_NOT_IMP; + } + + const char * real_path = lv_fs_get_real_path(path); + lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path); + + return res; +} + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn) +{ + if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) { + fn[0] = '\0'; + return LV_FS_RES_INV_PARAM; + } + + if(rddir_p->drv->dir_read == NULL) { + return LV_FS_RES_NOT_IMP; + } + + lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn); + + return res; +} + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p) +{ + if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) { + return LV_FS_RES_INV_PARAM; + } + + lv_fs_res_t res; + + if(rddir_p->drv->dir_close == NULL) { + res = LV_FS_RES_NOT_IMP; + } else { + res = rddir_p->drv->dir_close(rddir_p->dir_d); + } + + lv_mem_free(rddir_p->dir_d); /*Clean up*/ + rddir_p->dir_d = NULL; + rddir_p->drv = NULL; + rddir_p->dir_d = NULL; + + return res; +} + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free(char letter, uint32_t * total_p, uint32_t * free_p) +{ + lv_fs_drv_t * drv = lv_fs_get_drv(letter); + + if(drv == NULL) { + return LV_FS_RES_INV_PARAM; + } + + lv_fs_res_t res; + + if(drv->free == NULL) { + res = LV_FS_RES_NOT_IMP; + } else { + uint32_t total_tmp = 0; + uint32_t free_tmp = 0; + res = drv->free(&total_tmp, &free_tmp); + + if(total_p != NULL) *total_p = total_tmp; + if(free_p != NULL) *free_p = free_tmp; + } + + return res; +} + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p) +{ + /*Save the new driver*/ + lv_fs_drv_t * new_drv; + new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll)); + lv_mem_assert(new_drv); + if(new_drv == NULL) return; + + memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t)); +} + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf) +{ + lv_fs_drv_t * drv; + uint8_t i = 0; + + LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { + buf[i] = drv->letter; + i++; + } + + buf[i] = '\0'; + + return buf; +} + + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn) +{ + uint16_t i; + for(i = strlen(fn); i > 0; i --) { + if(fn[i] == '.') { + return &fn[i + 1]; + } else if(fn[i] == '/' || fn[i] == '\\') { + return ""; /*No extension if a '\' or '/' found*/ + } + } + + return ""; /*Empty string if no '.' in the file name. */ +} + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path) +{ + uint16_t len = strlen(path); + if(len == 0) return path; + + len --; /*Go before the trailing '\0'*/ + + /*Ignore trailing '/' or '\'*/ + while(path[len] == '/' || path[len] == '\\') { + path[len] = '\0'; + if(len > 0) len --; + else return path; + } + + uint16_t i; + for(i = len; i > 0; i --) { + if(path[i] == '/' || path[i] == '\\') break; + } + + if(i > 0) path[i] = '\0'; + + return path; +} + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param path a character sting with the path to search in + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path) +{ + uint16_t len = strlen(path); + if(len == 0) return path; + + len --; /*Go before the trailing '\0'*/ + + /*Ignore trailing '/' or '\'*/ + while(path[len] == '/' || path[len] == '\\') { + if(len > 0) len --; + else return path; + } + + uint16_t i; + for(i = len; i > 0; i --) { + if(path[i] == '/' || path[i] == '\\') break; + } + + /*No '/' or '\' in the path so return with path itself*/ + if(i == 0) return path; + + return &path[i + 1]; +} +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Leave the driver letters and / or \ letters from beginning of the path + * @param path path string (E.g. S:/folder/file.txt) + * @return pointer to the beginning of the real path (E.g. folder/file.txt) + */ +static const char * lv_fs_get_real_path(const char * path) +{ + /* Example path: "S:/folder/file.txt" + * Leave the letter and the : / \ characters*/ + + path ++; /*Ignore the driver letter*/ + + while(*path != '\0') { + if(*path == ':' || *path == '\\' || *path == '/') { + path ++; + } else { + break; + } + } + + return path; +} + +/** + * Give a pointer to a driver from its letter + * @param letter the driver letter + * @return pointer to a driver or NULL if not found + */ +static lv_fs_drv_t * lv_fs_get_drv(char letter) +{ + lv_fs_drv_t * drv; + + LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { + if(drv->letter == letter) { + return drv; + } + } + + return NULL; +} + +#endif /*USE_LV_FILESYSTEM*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.h new file mode 100644 index 0000000..1eb2bfa --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_fs.h @@ -0,0 +1,276 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_FS_RES_OK = 0, + LV_FS_RES_HW_ERR, /*Low level hardware error*/ + LV_FS_RES_FS_ERR, /*Error in the file system structure */ + LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/ + LV_FS_RES_FULL, /*Disk full*/ + LV_FS_RES_LOCKED, /*The file is already opened*/ + LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/ + LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/ + LV_FS_RES_TOUT, /*Process time outed*/ + LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/ + LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/ + LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/ + LV_FS_RES_UNKNOWN, /*Other unknown error*/ +}; +typedef uint8_t lv_fs_res_t; + +struct __lv_fs_drv_t; + +typedef struct +{ + void * file_d; + struct __lv_fs_drv_t* drv; +} lv_fs_file_t; + + +typedef struct +{ + void * dir_d; + struct __lv_fs_drv_t * drv; +} lv_fs_dir_t; + +enum +{ + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + +typedef struct __lv_fs_drv_t +{ + char letter; + uint16_t file_size; + uint16_t rddir_size; + bool (*ready) (void); + + lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close) (void * file_p); + lv_fs_res_t (*remove) (const char * fn); + lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek) (void * file_p, uint32_t pos); + lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p); + lv_fs_res_t (*trunc) (void * file_p); + lv_fs_res_t (*size) (void * file_p, uint32_t * size_p); + lv_fs_res_t (*rename) (const char * oldname, const char * newname); + lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p); + + lv_fs_res_t (*dir_open) (void * rddir_p, const char * path); + lv_fs_res_t (*dir_read) (void * rddir_p, char * fn); + lv_fs_res_t (*dir_close) (void * rddir_p); +} lv_fs_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void); + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p); + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter); + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode); + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p); + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove (const char * path); + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p); + +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size); + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_rdir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p); + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p); + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf); + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn); + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path); + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FS_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.c new file mode 100644 index 0000000..5ec5832 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.c @@ -0,0 +1,40 @@ +/** + * @file lv_gc.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_gc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +#if (!defined(LV_ENABLE_GC)) || LV_ENABLE_GC == 0 +LV_ROOTS +#endif /* LV_ENABLE_GC */ +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.h new file mode 100644 index 0000000..660d7f0 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_gc.h @@ -0,0 +1,75 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +#define LV_GC_ROOTS(prefix) \ + prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \ + prefix lv_ll_t _lv_scr_ll; /*Linked list of screens*/ \ + prefix lv_ll_t _lv_drv_ll;\ + prefix lv_ll_t _lv_file_ll;\ + prefix lv_ll_t _lv_anim_ll;\ + prefix void * _lv_def_scr;\ + prefix void * _lv_act_scr;\ + prefix void * _lv_top_layer;\ + prefix void * _lv_sys_layer;\ + prefix void * _lv_task_act;\ + prefix void * _lv_indev_list;\ + prefix void * _lv_disp_list;\ + +#define LV_NO_PREFIX +#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX) + +#if LV_ENABLE_GC == 1 +# if LV_MEM_CUSTOM != 1 +# error "GC requires CUSTOM_MEM" +# endif /* LV_MEM_CUSTOM */ +#else /* LV_ENABLE_GC */ +# define LV_GC_ROOT(x) x + LV_GC_ROOTS(extern) +#endif /* LV_ENABLE_GC */ + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GC_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.c new file mode 100644 index 0000000..43d8847 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.c @@ -0,0 +1,376 @@ +/** + * @file lv_ll.c + * Handle linked lists. + * The nodes are dynamically allocated by the 'lv_mem' module, + */ + +/********************* + * INCLUDES + *********************/ +#include +#include + +#include "lv_ll.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LL_NODE_META_SIZE (sizeof(lv_ll_node_t*) + sizeof(lv_ll_node_t*)) +#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size) +#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t*)) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev); +static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size) +{ + ll_p->head = NULL; + ll_p->tail = NULL; +#ifdef LV_MEM_ENV64 + /*Round the size up to 8*/ + if(node_size & 0x7) { + node_size = node_size & (~0x7); + node_size += 8; + } +#else + /*Round the size up to 4*/ + if(node_size & 0x3) { + node_size = node_size & (~0x3); + node_size += 4; + } +#endif + + ll_p->n_size = node_size; +} + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p) +{ + lv_ll_node_t * n_new; + + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + + if(n_new != NULL) { + node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/ + node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/ + + if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/ + node_set_prev(ll_p, ll_p->head, n_new); + } + + ll_p->head = n_new; /*Set the new head in the dsc.*/ + if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/ + ll_p->tail = n_new; + } + } + + return n_new; +} + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act) +{ + lv_ll_node_t * n_new; + lv_ll_node_t * n_prev; + + if(NULL == ll_p || NULL == n_act) return NULL; + + if(lv_ll_get_head(ll_p) == n_act) { + n_new = lv_ll_ins_head(ll_p); + if(n_new == NULL) return NULL; + } else { + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + if(n_new == NULL) return NULL; + + n_prev = lv_ll_get_prev(ll_p, n_act); + node_set_next(ll_p, n_prev, n_new); + node_set_prev(ll_p, n_new, n_prev); + node_set_prev(ll_p, n_act, n_new); + node_set_next(ll_p, n_new, n_act); + } + + return n_new; +} + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p) +{ + lv_ll_node_t * n_new; + + n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); + if(n_new == NULL) return NULL; + + if(n_new != NULL) { + node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/ + node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/ + if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/ + node_set_next(ll_p, ll_p->tail, n_new); + } + + ll_p->tail = n_new; /*Set the new tail in the dsc.*/ + if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/ + ll_p->head = n_new; + } + } + + return n_new; +} + + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p) +{ + if(lv_ll_get_head(ll_p) == node_p) { + /*The new head will be the node after 'n_act'*/ + ll_p->head = lv_ll_get_next(ll_p, node_p); + if(ll_p->head == NULL) { + ll_p->tail = NULL; + } else { + node_set_prev(ll_p, ll_p->head, NULL); + } + } else if(lv_ll_get_tail(ll_p) == node_p) { + /*The new tail will be the node before 'n_act'*/ + ll_p->tail = lv_ll_get_prev(ll_p, node_p); + if(ll_p->tail == NULL) { + ll_p->head = NULL; + } else { + node_set_next(ll_p, ll_p->tail, NULL); + } + } else { + lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p); + lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p); + + node_set_next(ll_p, n_prev, n_next); + node_set_prev(ll_p, n_next, n_prev); + } +} + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p) +{ + void * i; + void * i_next; + + i = lv_ll_get_head(ll_p); + i_next = NULL; + + while(i != NULL) { + i_next = lv_ll_get_next(ll_p, i); + + lv_ll_rem(ll_p, i); + lv_mem_free(i); + + i = i_next; + } +} + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) +{ + lv_ll_rem(ll_ori_p, node); + + /*Set node as head*/ + node_set_prev(ll_new_p, node, NULL); + node_set_next(ll_new_p, node, ll_new_p->head); + + if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/ + node_set_prev(ll_new_p, ll_new_p->head, node); + } + + ll_new_p->head = node; /*Set the new head in the dsc.*/ + if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/ + ll_new_p->tail = node; + } +} + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p) +{ + void * head = NULL; + + if(ll_p != NULL) { + head = ll_p->head; + } + + return head; +} + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p) +{ + void * tail = NULL; + + if(ll_p != NULL) { + tail = ll_p->tail; + } + + return tail; +} + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act) +{ + void * next = NULL; + + if(ll_p != NULL) { + const lv_ll_node_t * n_act_d = n_act; + memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *)); + } + + return next; +} + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act) +{ + void * prev = NULL; + + if(ll_p != NULL) { + const lv_ll_node_t * n_act_d = n_act; + memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *)); + } + + return prev; +} + +void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p) +{ + (void)(ll_p); + (void)(n1_p); + (void)(n2_p); + /*TODO*/ +} + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) +{ + if(n_act == n_after) return; /*Can't move before itself*/ + + + void * n_before; + if(n_after != NULL) n_before = lv_ll_get_prev(ll_p, n_after); + else n_before = lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/ + + if(n_act == n_before) return; /*Already before `n_after`*/ + + /*It's much easier to remove from the list and add again*/ + lv_ll_rem(ll_p, n_act); + + /*Add again by setting the prev. and next nodes*/ + node_set_next(ll_p, n_before, n_act); + node_set_prev(ll_p, n_act, n_before); + node_set_prev(ll_p, n_after, n_act); + node_set_next(ll_p, n_act, n_after); + + /*If `n_act` was moved before NULL then it become the new tail*/ + if(n_after == NULL) ll_p->tail = n_act; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Set the 'pervious node pointer' of a node + * @param ll_p pointer to linked list + * @param act pointer to a node which prev. node pointer should be set + * @param prev pointer to a node which should be the previous node before 'act' + */ +static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev) +{ + if(act == NULL) return; /*Can't set the prev node of `NULL`*/ + + uint32_t node_p_size = sizeof(lv_ll_node_t *); + if(prev) memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size); + else memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size); +} + +/** + * Set the 'next node pointer' of a node + * @param ll_p pointer to linked list + * @param act pointer to a node which next node pointer should be set + * @param next pointer to a node which should be the next node before 'act' + */ +static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next) +{ + if(act == NULL) return; /*Can't set the next node of `NULL`*/ + + uint32_t node_p_size = sizeof(lv_ll_node_t *); + if(next) memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size); + else memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size); +} + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.h new file mode 100644 index 0000000..086ba40 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ll.h @@ -0,0 +1,145 @@ +/** + * @file lv_ll.c + * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. + */ + +#ifndef LV_LL_H +#define LV_LL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Dummy type to make handling easier*/ +typedef uint8_t lv_ll_node_t; + +/*Description of a linked list*/ +typedef struct +{ + uint32_t n_size; + lv_ll_node_t* head; + lv_ll_node_t* tail; +} lv_ll_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p); + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p); + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p); + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p); + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p); + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p); + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); + +/********************** + * MACROS + **********************/ + +#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) + +#define LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.c new file mode 100644 index 0000000..bd59cf3 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.c @@ -0,0 +1,82 @@ +/** + * @file lv_log.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_log.h" +#if USE_LV_LOG + +#if LV_LOG_PRINTF +#include +#include +#include +#include +#endif +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static void (*print_cb)(lv_log_level_t, const char *, uint32_t, const char *); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)) +{ + print_cb = f; +} + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc) +{ + if(level >= _LV_LOG_LEVEL_NUM) return; /*Invalid level*/ + + if(level >= LV_LOG_LEVEL) { + +#if LV_LOG_PRINTF + static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; + char *log = (char *)malloc(0x1000); + s_printf(log, "%s: %s \t(%s #%d)\r\n", lvl_prefix[level], dsc, file, line); + uart_send(UART_B, (u8 *)log, strlen(log) + 1); + //gfx_printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line); +#else + if(print_cb) print_cb(level, file, line, dsc); +#endif + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*USE_LV_LOG*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.h new file mode 100644 index 0000000..8e99763 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_log.h @@ -0,0 +1,86 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `USE_LV_LOG`*/ + +#define LV_LOG_LEVEL_TRACE 0 /*A lot of logs to give detailed information*/ +#define LV_LOG_LEVEL_INFO 1 /*Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /*Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_ERROR 3 /*Only critical issue, when the system may fail*/ +#define _LV_LOG_LEVEL_NUM 4 + +typedef int8_t lv_log_level_t; + +#if USE_LV_LOG +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)); + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); + +/********************** + * MACROS + **********************/ + +#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); + +#else /*USE_LV_LOG*/ + +/*Do nothing if `USE_LV_LOG 0`*/ +#define lv_log_add(level, file, line, dsc) {;} +#define LV_LOG_TRACE(dsc) {;} +#define LV_LOG_INFO(dsc) {;} +#define LV_LOG_WARN(dsc) {;} +#define LV_LOG_ERROR(dsc) {;} +#endif /*USE_LV_LOG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LOG_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.c new file mode 100644 index 0000000..a0d2605 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.c @@ -0,0 +1,165 @@ +/** + * @file lv_math.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_math.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static int16_t sin0_90_table[] = { + 0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126, + 5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668, + 11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886, + 16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, + 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730, + 25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087, + 28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591, + 30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165, + 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, + 32767 +}; + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf) +{ + char * buf_ori = buf; + if(num == 0) { + buf[0] = '0'; + buf[1] = '\0'; + return buf; + } else if(num < 0) { + (*buf) = '-'; + buf++; + num = LV_MATH_ABS(num); + } + uint32_t output = 0; + int8_t i; + + for(i = 31; i >= 0; i--) { + if((output & 0xF) >= 5) + output += 3; + if(((output & 0xF0) >> 4) >= 5) + output += (3 << 4); + if(((output & 0xF00) >> 8) >= 5) + output += (3 << 8); + if(((output & 0xF000) >> 12) >= 5) + output += (3 << 12); + if(((output & 0xF0000) >> 16) >= 5) + output += (3 << 16); + if(((output & 0xF00000) >> 20) >= 5) + output += (3 << 20); + if(((output & 0xF000000) >> 24) >= 5) + output += (3 << 24); + if(((output & 0xF0000000) >> 28) >= 5) + output += (3 << 28); + output = (output << 1) | ((num >> i) & 1); + } + + uint8_t digit; + bool leading_zero_ready = false; + for(i = 28; i >= 0; i -= 4) { + digit = ((output >> i) & 0xF) + '0'; + if(digit == '0' && leading_zero_ready == false) continue; + + leading_zero_ready = true; + (*buf) = digit; + buf++; + } + + (*buf) = '\0'; + + return buf_ori; +} + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle) +{ + int16_t ret = 0; + angle = angle % 360; + + if(angle < 0) angle = 360 + angle; + + if(angle < 90) { + ret = sin0_90_table[angle]; + } else if(angle >= 90 && angle < 180) { + angle = 180 - angle; + ret = sin0_90_table[angle]; + } else if(angle >= 180 && angle < 270) { + angle = angle - 180; + ret = - sin0_90_table[angle]; + } else { /*angle >=270*/ + angle = 360 - angle; + ret = - sin0_90_table[angle]; + } + + return ret; +} + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3) +{ + uint32_t t_rem = 1024 - t; + uint32_t t_rem2 = (t_rem * t_rem) >> 10; + uint32_t t_rem3 = (t_rem2 * t_rem) >> 10; + uint32_t t2 = (t * t) >> 10; + uint32_t t3 = (t2 * t) >> 10; + + + uint32_t v1 = ((uint32_t)t_rem3 * u0) >> 10; + uint32_t v2 = ((uint32_t)3 * t_rem2 * t * u1) >> 20; + uint32_t v3 = ((uint32_t)3 * t_rem * t2 * u2) >> 20; + uint32_t v4 = ((uint32_t)t3 * u3) >> 10; + + return v1 + v2 + v3 + v4; + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.h new file mode 100644 index 0000000..a0229eb --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_math.h @@ -0,0 +1,73 @@ +/** + * @file math_base.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ +#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define LV_TRIGO_SIN_MAX 32767 +#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/ + +#define LV_BEZIER_VAL_MAX 1024 /*Max time in Bezier functions (not [0..1] to use integers) */ +#define LV_BEZIER_VAL_SHIFT 10 /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf); + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle); + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.c new file mode 100644 index 0000000..08f52d5 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_mem.c + * General and portable implementation of malloc and free. + * The dynamic memory monitoring is also supported. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include "lv_math.h" +#include + +#include + +#if LV_MEM_CUSTOM != 0 +#include LV_MEM_CUSTOM_INCLUDE +#endif + +/********************* + * DEFINES + *********************/ +#define LV_MEM_ADD_JUNK 0 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/ + + +#ifdef LV_MEM_ENV64 +# define MEM_UNIT uint64_t +#else +# define MEM_UNIT uint32_t +#endif + + +/********************** + * TYPEDEFS + **********************/ + +#if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/ + +/*The size of this union must be 32 bytes (uint32_t * 8)*/ +typedef union { + struct { + MEM_UNIT used: 1; //1: if the entry is used + MEM_UNIT d_size: 31; //Size of the data + }; + MEM_UNIT header; //The header (used + d_size) + MEM_UNIT align[8]; //Align header size to MEM_UNIT * 8 bytes +} lv_mem_header_t; + +static_assert(sizeof(lv_mem_header_t) == 32, "Node header must be 32 bytes!"); + +typedef struct { + lv_mem_header_t header; + uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/ +} lv_mem_ent_t; + +#endif /* LV_ENABLE_GC */ + +/********************** + * STATIC PROTOTYPES + **********************/ +#if LV_MEM_CUSTOM == 0 +static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e); +static void * ent_alloc(lv_mem_ent_t * e, uint32_t size); +static void ent_trunc(lv_mem_ent_t * e, uint32_t size); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +#if LV_MEM_CUSTOM == 0 +static uint8_t * work_mem; +#endif + +static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initiaiize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void) +{ +#if LV_MEM_CUSTOM == 0 + +#if LV_MEM_ADR == 0 + /*Allocate a large array to store the dynamically allocated data*/ + static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)]; + work_mem = (uint8_t *) work_mem_int; +#else + work_mem = (uint8_t *) LV_MEM_ADR; +#endif + + lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem; + full->header.used = 0; + /*The total mem size id reduced by the first header and the close patterns */ + full->header.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t); +#endif +} + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size) +{ + if(size == 0) { + return &zero_mem; + } + + /*Round the size to lv_mem_header_t*/ + if(size & (sizeof(lv_mem_header_t) - 1)) { + size = size & (~(sizeof(lv_mem_header_t) - 1)); + size += sizeof(lv_mem_header_t); + } + + void * alloc = NULL; + +#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/ + lv_mem_ent_t * e = NULL; + + //Search for a appropriate entry + do { + //Get the next entry + e = ent_get_next(e); + + /*If there is next entry then try to allocate there*/ + if(e != NULL) { + alloc = ent_alloc(e, size); + } + //End if there is not next entry OR the alloc. is successful + } while(e != NULL && alloc == NULL); + + +#else /*Use custom, user defined malloc function*/ +#if LV_ENABLE_GC == 1 /*gc must not include header*/ + alloc = LV_MEM_CUSTOM_ALLOC(size); +#else /* LV_ENABLE_GC */ + /*Allocate a header too to store the size*/ + alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t)); + if(alloc != NULL) { + ((lv_mem_ent_t *) alloc)->header.d_size = size; + ((lv_mem_ent_t *) alloc)->header.used = 1; + alloc = &((lv_mem_ent_t *) alloc)->first_data; + } +#endif /* LV_ENABLE_GC */ +#endif /* LV_MEM_CUSTOM */ + +#if LV_MEM_ADD_JUNK + if(alloc != NULL) memset(alloc, 0xaa, size); +#endif + + if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory"); + + return alloc; +} + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data) +{ + if(data == &zero_mem) return; + if(data == NULL) return; + + +#if LV_MEM_ADD_JUNK + memset((void *)data, 0xbb, lv_mem_get_size(data)); +#endif + +#if LV_ENABLE_GC==0 + /*e points to the header*/ + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t)); + e->header.used = 0; +#endif + +#if LV_MEM_CUSTOM == 0 +#if LV_MEM_AUTO_DEFRAG + /* Make a simple defrag. + * Join the following free entries after this*/ + lv_mem_ent_t * e_next; + e_next = ent_get_next(e); + while(e_next != NULL) { + if(e_next->header.used == 0) { + e->header.d_size += e_next->header.d_size + sizeof(e->header); + } else { + break; + } + e_next = ent_get_next(e_next); + } +#endif +#else /*Use custom, user defined free function*/ +#if LV_ENABLE_GC==0 + LV_MEM_CUSTOM_FREE(e); +#else + LV_MEM_CUSTOM_FREE((void*)data); +#endif /*LV_ENABLE_GC*/ +#endif +} + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ + +#if LV_ENABLE_GC==0 + +void * lv_mem_realloc(void * data_p, uint32_t new_size) +{ + /*Round the size to lv_mem_header_t*/ + if(new_size & (sizeof(lv_mem_header_t) - 1)) { + new_size = new_size & (~(sizeof(lv_mem_header_t) - 1)); + new_size += sizeof(lv_mem_header_t); + } + + /*data_p could be previously freed pointer (in this case it is invalid)*/ + if(data_p != NULL) { + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t)); + if(e->header.used == 0) { + data_p = NULL; + } + } + + uint32_t old_size = lv_mem_get_size(data_p); + if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/ + +#if LV_MEM_CUSTOM == 0 + /* Only truncate the memory is possible + * If the 'old_size' was extended by a header size in 'ent_trunc' it avoids reallocating this same memory */ + if(new_size < old_size) { + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t)); + ent_trunc(e, new_size); + return &e->first_data; + } +#endif + + void * new_p; + new_p = lv_mem_alloc(new_size); + + if(new_p != NULL && data_p != NULL) { + /*Copy the old data to the new. Use the smaller size*/ + if(old_size != 0) { + memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size)); + lv_mem_free(data_p); + } + } + + + if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory"); + + return new_p; +} + +#else /* LV_ENABLE_GC */ + +void * lv_mem_realloc(void * data_p, uint32_t new_size) +{ + void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size); + if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory"); + return new_p; +} + +#endif /* lv_enable_gc */ + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void) +{ +#if LV_MEM_CUSTOM == 0 + lv_mem_ent_t * e_free; + lv_mem_ent_t * e_next; + e_free = ent_get_next(NULL); + + while(1) { + /*Search the next free entry*/ + while(e_free != NULL) { + if(e_free->header.used != 0) { + e_free = ent_get_next(e_free); + } else { + break; + } + } + + if(e_free == NULL) return; + + /*Joint the following free entries to the free*/ + e_next = ent_get_next(e_free); + while(e_next != NULL) { + if(e_next->header.used == 0) { + e_free->header.d_size += e_next->header.d_size + sizeof(e_next->header); + } else { + break; + } + + e_next = ent_get_next(e_next); + } + + if(e_next == NULL) return; + + /*Continue from the lastly checked entry*/ + e_free = e_next; + } +#endif +} + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p) +{ + /*Init the data*/ + memset(mon_p, 0, sizeof(lv_mem_monitor_t)); +#if LV_MEM_CUSTOM == 0 + lv_mem_ent_t * e; + e = NULL; + + e = ent_get_next(e); + + while(e != NULL) { + if(e->header.used == 0) { + mon_p->free_cnt++; + mon_p->free_size += e->header.d_size; + if(e->header.d_size > mon_p->free_biggest_size) { + mon_p->free_biggest_size = e->header.d_size; + } + } else { + mon_p->used_cnt++; + } + + e = ent_get_next(e); + } + mon_p->total_size = LV_MEM_SIZE; + mon_p->used_pct = 100 - ((uint64_t)100U * mon_p->free_size) / mon_p->total_size; + mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size; + mon_p->frag_pct = 100 - mon_p->frag_pct; +#endif +} + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ + +#if LV_ENABLE_GC==0 + +uint32_t lv_mem_get_size(const void * data) +{ + if(data == NULL) return 0; + if(data == &zero_mem) return 0; + + lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t)); + + return e->header.d_size; +} + +#else /* LV_ENABLE_GC */ + +uint32_t lv_mem_get_size(const void * data) +{ + return LV_MEM_CUSTOM_GET_SIZE(data); +} + +#endif /*LV_ENABLE_GC*/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +#if LV_MEM_CUSTOM == 0 +/** + * Give the next entry after 'act_e' + * @param act_e pointer to an entry + * @return pointer to an entry after 'act_e' + */ +static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e) +{ + lv_mem_ent_t * next_e = NULL; + + if(act_e == NULL) { /*NULL means: get the first entry*/ + next_e = (lv_mem_ent_t *) work_mem; + } else { /*Get the next entry */ + uint8_t * data = &act_e->first_data; + next_e = (lv_mem_ent_t *)&data[act_e->header.d_size]; + + if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL; + } + + return next_e; +} + + +/** + * Try to do the real allocation with a given size + * @param e try to allocate to this entry + * @param size size of the new memory in bytes + * @return pointer to the allocated memory or NULL if not enough memory in the entry + */ +static void * ent_alloc(lv_mem_ent_t * e, uint32_t size) +{ + void * alloc = NULL; + + /*If the memory is free and big enough then use it */ + if(e->header.used == 0 && e->header.d_size >= size) { + /*Truncate the entry to the desired size */ + ent_trunc(e, size), + + e->header.used = 1; + + /*Save the allocated data*/ + alloc = &e->first_data; + } + + return alloc; +} + +/** + * Truncate the data of entry to the given size + * @param e Pointer to an entry + * @param size new size in bytes + */ +static void ent_trunc(lv_mem_ent_t * e, uint32_t size) +{ + /*Don't let empty space only for a header without data*/ + if(e->header.d_size == size + sizeof(lv_mem_header_t)) { + size = e->header.d_size; + } + + /* Create the new entry after the current if there is space for it */ + if(e->header.d_size != size) { + uint8_t * e_data = &e->first_data; + lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size]; + after_new_e->header.used = 0; + after_new_e->header.d_size = e->header.d_size - size - sizeof(lv_mem_header_t); + } + + /* Set the new size for the original entry */ + e->header.d_size = size; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.h new file mode 100644 index 0000000..c33caa4 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_mem.h @@ -0,0 +1,127 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ +// Check windows +#ifdef __WIN64 +//# define LV_MEM_ENV64 +#endif + +// Check GCC +#ifdef __GNUC__ +# if defined(__x86_64__) || defined(__ppc64__) +//# define LV_MEM_ENV64 +# endif +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t total_size; + uint32_t free_cnt; + uint32_t free_size; + uint32_t free_biggest_size; + uint32_t used_cnt; + uint8_t used_pct; + uint8_t frag_pct; +} lv_mem_monitor_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initiaize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void); + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data); + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ +void * lv_mem_realloc(void * data_p, uint32_t new_size); + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ +uint32_t lv_mem_get_size(const void * data); + + +/********************** + * MACROS + **********************/ + +/** + * Halt on NULL pointer + * p pointer to a memory + */ +#if USE_LV_LOG == 0 +# define lv_mem_assert(p) {if(p == NULL) while(1); } +#else +# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }} +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MEM_H*/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_misc.mk b/ariane/src/bdk/libs/lvgl/lv_misc/lv_misc.mk new file mode 100644 index 0000000..470f123 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_misc.mk @@ -0,0 +1,19 @@ +CSRCS += lv_font.c +CSRCS += lv_circ.c +CSRCS += lv_area.c +CSRCS += lv_task.c +CSRCS += lv_fs.c +CSRCS += lv_anim.c +CSRCS += lv_mem.c +CSRCS += lv_ll.c +CSRCS += lv_color.c +CSRCS += lv_txt.c +CSRCS += lv_ufs.c +CSRCS += lv_math.c +CSRCS += lv_log.c +CSRCS += lv_gc.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc +VPATH += :$(LVGL_DIR)/lvgl/lv_misc + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc" diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h new file mode 100644 index 0000000..762bab9 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_symbol_def.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +/* + * With no UTF-8 support (192- 255) (192..241 is used) + * + * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831 + * - Basic symbols: 0xE000..0xE01F + * - File symbols: 0xE020..0xE03F + * - Feedback symbols: 0xE040..0xE05F + * - Reserved: 0xE060..0xE07F + */ + +#if LV_TXT_UTF8 == 0 +#define LV_SYMBOL_GLYPH_FIRST 0xC0 +#define SYMBOL_DOT _SYMBOL_VALUE1(C0) +#define SYMBOL_CLOCK _SYMBOL_VALUE1(C1) +#define SYMBOL_LIST _SYMBOL_VALUE1(C2) +#define SYMBOL_OK _SYMBOL_VALUE1(C3) +#define SYMBOL_CLOSE _SYMBOL_VALUE1(C4) +#define SYMBOL_POWER _SYMBOL_VALUE1(C5) +#define SYMBOL_SETTINGS _SYMBOL_VALUE1(C6) +#define SYMBOL_TRASH _SYMBOL_VALUE1(C7) +#define SYMBOL_HOME _SYMBOL_VALUE1(C8) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE1(C9) +#define SYMBOL_DRIVE _SYMBOL_VALUE1(CA) +#define SYMBOL_REFRESH _SYMBOL_VALUE1(CB) +#define SYMBOL_REBOOT _SYMBOL_VALUE1(CC) +#define SYMBOL_CHIP _SYMBOL_VALUE1(CD) +#define SYMBOL_SD _SYMBOL_VALUE1(CE) +#define SYMBOL_CIRCUIT _SYMBOL_VALUE1(CF) +#define SYMBOL_EDIT _SYMBOL_VALUE1(D0) +#define SYMBOL_FILE_ALT _SYMBOL_VALUE1(D1) +#define SYMBOL_FILE_CODE _SYMBOL_VALUE1(D2) +#define SYMBOL_FILE_ARC _SYMBOL_VALUE1(D3) +#define SYMBOL_TEMPERATURE _SYMBOL_VALUE1(D4) +#define SYMBOL_MODULES _SYMBOL_VALUE1(D5) +#define SYMBOL_MODULES_ALT _SYMBOL_VALUE1(D6) +#define SYMBOL_LEFT _SYMBOL_VALUE1(D7) +#define SYMBOL_RIGHT _SYMBOL_VALUE1(D8) +#define SYMBOL_KEY _SYMBOL_VALUE1(D9) +#define SYMBOL_INFO _SYMBOL_VALUE1(DA) +#define SYMBOL_WARNING _SYMBOL_VALUE1(DB) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE1(DC) +#define SYMBOL_UP _SYMBOL_VALUE1(DD) +#define SYMBOL_DOWN _SYMBOL_VALUE1(DE) +#define SYMBOL_BRIGHTNESS _SYMBOL_VALUE1(DF) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE1(E0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE1(E1) +#define SYMBOL_USB _SYMBOL_VALUE1(E2) +#define SYMBOL_TOOLS _SYMBOL_VALUE1(E3) +#define SYMBOL_COPY _SYMBOL_VALUE1(E4) +#define SYMBOL_SAVE _SYMBOL_VALUE1(E5) +#define SYMBOL_CHARGE _SYMBOL_VALUE1(E6) +#define SYMBOL_HINT _SYMBOL_VALUE1(E7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE1(E8) +#define SYMBOL_GPS _SYMBOL_VALUE1(E9) +#define SYMBOL_FILE _SYMBOL_VALUE1(EA) +#define SYMBOL_CAMERA _SYMBOL_VALUE1(EB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE1(EC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE1(ED) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE1(EE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE1(EF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE1(F0) +#define SYMBOL_SHRK _SYMBOL_VALUE1(F1) +#define LV_SYMBOL_GLYPH_LAST 0xF1 +#define SYMBOL_DUMMY _SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/ + +#else +#define LV_SYMBOL_GLYPH_FIRST 0xF800 +#define SYMBOL_DOT _SYMBOL_VALUE3(EF,A0,80) +#define SYMBOL_CLOCK _SYMBOL_VALUE3(EF,A0,81) +#define SYMBOL_LIST _SYMBOL_VALUE3(EF,A0,82) +#define SYMBOL_OK _SYMBOL_VALUE3(EF,A0,83) +#define SYMBOL_CLOSE _SYMBOL_VALUE3(EF,A0,84) +#define SYMBOL_POWER _SYMBOL_VALUE3(EF,A0,85) +#define SYMBOL_SETTINGS _SYMBOL_VALUE3(EF,A0,86) +#define SYMBOL_TRASH _SYMBOL_VALUE3(EF,A0,87) +#define SYMBOL_HOME _SYMBOL_VALUE3(EF,A0,88) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE3(EF,A0,89) +#define SYMBOL_DRIVE _SYMBOL_VALUE3(EF,A0,8A) +#define SYMBOL_REFRESH _SYMBOL_VALUE3(EF,A0,8B) +#define SYMBOL_REBOOT _SYMBOL_VALUE3(EF,A0,8C) +#define SYMBOL_CHIP _SYMBOL_VALUE3(EF,A0,8D) +#define SYMBOL_SD _SYMBOL_VALUE3(EF,A0,8E) +#define SYMBOL_CIRCUIT _SYMBOL_VALUE3(EF,A0,8F) +#define SYMBOL_EDIT _SYMBOL_VALUE3(EF,A0,90) +#define SYMBOL_FILE_ALT _SYMBOL_VALUE3(EF,A0,91) +#define SYMBOL_FILE_CODE _SYMBOL_VALUE3(EF,A0,92) +#define SYMBOL_FILE_ARC _SYMBOL_VALUE3(EF,A0,93) +#define SYMBOL_TEMPERATURE _SYMBOL_VALUE3(EF,A0,94) +#define SYMBOL_MODULES _SYMBOL_VALUE3(EF,A0,95) +#define SYMBOL_MODULES_ALT _SYMBOL_VALUE3(EF,A0,96) +#define SYMBOL_LEFT _SYMBOL_VALUE3(EF,A0,97) +#define SYMBOL_RIGHT _SYMBOL_VALUE3(EF,A0,98) +#define SYMBOL_KEY _SYMBOL_VALUE3(EF,A0,99) +#define SYMBOL_INFO _SYMBOL_VALUE3(EF,A0,9A) +#define SYMBOL_WARNING _SYMBOL_VALUE3(EF,A0,9B) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE3(EF,A0,9C) +#define SYMBOL_UP _SYMBOL_VALUE3(EF,A0,9D) +#define SYMBOL_DOWN _SYMBOL_VALUE3(EF,A0,9E) +#define SYMBOL_BRIGHTNESS _SYMBOL_VALUE3(EF,A0,9F) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE3(EF,A0,A0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE3(EF,A0,A1) +#define SYMBOL_USB _SYMBOL_VALUE3(EF,A0,A2) +#define SYMBOL_TOOLS _SYMBOL_VALUE3(EF,A0,A3) +#define SYMBOL_COPY _SYMBOL_VALUE3(EF,A0,A4) +#define SYMBOL_SAVE _SYMBOL_VALUE3(EF,A0,A5) +#define SYMBOL_CHARGE _SYMBOL_VALUE3(EF,A0,A6) +#define SYMBOL_HINT _SYMBOL_VALUE3(EF,A0,A7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE3(EF,A0,A8) +#define SYMBOL_GPS _SYMBOL_VALUE3(EF,A0,A9) +#define SYMBOL_FILE _SYMBOL_VALUE3(EF,A0,AA) +#define SYMBOL_CAMERA _SYMBOL_VALUE3(EF,A0,AB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE3(EF,A0,AC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE3(EF,A0,AD) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE3(EF,A0,AE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE3(EF,A0,AF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE3(EF,A0,B0) +#define SYMBOL_SHRK _SYMBOL_VALUE3(EF,A0,B1) +#define LV_SYMBOL_GLYPH_LAST 0xF831 +#define SYMBOL_DUMMY _SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/ +#endif + +#define _SYMBOL_VALUE1(x) (0x ## x) +#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x) +#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym + +enum +{ + _SYMBOL_NUMSTR(SYMBOL_DOT), + _SYMBOL_NUMSTR(SYMBOL_CLOCK), + _SYMBOL_NUMSTR(SYMBOL_LIST), + _SYMBOL_NUMSTR(SYMBOL_OK), + _SYMBOL_NUMSTR(SYMBOL_CLOSE), + _SYMBOL_NUMSTR(SYMBOL_POWER), + _SYMBOL_NUMSTR(SYMBOL_SETTINGS), + _SYMBOL_NUMSTR(SYMBOL_TRASH), + _SYMBOL_NUMSTR(SYMBOL_HOME), + _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD), + _SYMBOL_NUMSTR(SYMBOL_DRIVE), + _SYMBOL_NUMSTR(SYMBOL_REFRESH), + _SYMBOL_NUMSTR(SYMBOL_REBOOT), + _SYMBOL_NUMSTR(SYMBOL_CHIP), + _SYMBOL_NUMSTR(SYMBOL_SD), + _SYMBOL_NUMSTR(SYMBOL_CIRCUIT), + _SYMBOL_NUMSTR(SYMBOL_EDIT), + _SYMBOL_NUMSTR(SYMBOL_FILE_ALT), + _SYMBOL_NUMSTR(SYMBOL_FILE_CODE), + _SYMBOL_NUMSTR(SYMBOL_FILE_ARC), + _SYMBOL_NUMSTR(SYMBOL_TEMPERATURE), + _SYMBOL_NUMSTR(SYMBOL_MODULES), + _SYMBOL_NUMSTR(SYMBOL_MODULES_ALT), + _SYMBOL_NUMSTR(SYMBOL_LEFT), + _SYMBOL_NUMSTR(SYMBOL_RIGHT), + _SYMBOL_NUMSTR(SYMBOL_KEY), + _SYMBOL_NUMSTR(SYMBOL_INFO), + _SYMBOL_NUMSTR(SYMBOL_WARNING), + _SYMBOL_NUMSTR(SYMBOL_SHUFFLE), + _SYMBOL_NUMSTR(SYMBOL_UP), + _SYMBOL_NUMSTR(SYMBOL_DOWN), + _SYMBOL_NUMSTR(SYMBOL_BRIGHTNESS), + _SYMBOL_NUMSTR(SYMBOL_DIRECTORY), + _SYMBOL_NUMSTR(SYMBOL_UPLOAD), + _SYMBOL_NUMSTR(SYMBOL_USB), + _SYMBOL_NUMSTR(SYMBOL_TOOLS), + _SYMBOL_NUMSTR(SYMBOL_COPY), + _SYMBOL_NUMSTR(SYMBOL_SAVE), + _SYMBOL_NUMSTR(SYMBOL_CHARGE), + _SYMBOL_NUMSTR(SYMBOL_HINT), + _SYMBOL_NUMSTR(SYMBOL_KEYBOARD), + _SYMBOL_NUMSTR(SYMBOL_GPS), + _SYMBOL_NUMSTR(SYMBOL_FILE), + _SYMBOL_NUMSTR(SYMBOL_CAMERA), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_3), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_2), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_1), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY), + _SYMBOL_NUMSTR(SYMBOL_SHRK), + _SYMBOL_NUMSTR(SYMBOL_DUMMY), +}; + +#undef _SYMBOL_VALUE1 +#undef _SYMBOL_VALUE3 + +#define _SYMBOL_STR_(x) #x +#define _SYMBOL_STR(x) _SYMBOL_STR_(x) +#define _SYMBOL_CHAR(c) \x ## c +#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x)) +#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.c new file mode 100644 index 0000000..aac9c12 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.c @@ -0,0 +1,332 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_task.h" +#include "../lv_hal/lv_hal_tick.h" +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ +#define IDLE_MEAS_PERIOD 500 /*[ms]*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_task_exec(lv_task_t * lv_task_p); + +/********************** + * STATIC VARIABLES + **********************/ +static bool lv_task_run = false; +static uint8_t idle_last = 0; +static bool task_deleted; +static bool task_created; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t)); + + /*Initially enable the lv_task handling*/ + lv_task_enable(true); +} + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) +{ + LV_LOG_TRACE("lv_task_handler started"); + + /*Avoid concurrent running of the task handler*/ + static bool task_handler_mutex = false; + if(task_handler_mutex) return; + task_handler_mutex = true; + + static uint32_t idle_period_start = 0; + static uint32_t handler_start = 0; + static uint32_t busy_time = 0; + + if(lv_task_run == false) return; + + handler_start = lv_tick_get(); + + /* Run all task from the highest to the lowest priority + * If a lower priority task is executed check task again from the highest priority + * but on the priority of executed tasks don't run tasks before the executed*/ + lv_task_t * task_interrupter = NULL; + lv_task_t * next; + bool end_flag; + do { + end_flag = true; + task_deleted = false; + task_created = false; + LV_GC_ROOT(_lv_task_act) = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + while(LV_GC_ROOT(_lv_task_act)) { + /* The task might be deleted if it runs only once ('once = 1') + * So get next element until the current is surely valid*/ + next = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act)); + + /*We reach priority of the turned off task. There is nothing more to do.*/ + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) { + break; + } + + /*Here is the interrupter task. Don't execute it again.*/ + if(LV_GC_ROOT(_lv_task_act) == task_interrupter) { + task_interrupter = NULL; /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/ + LV_GC_ROOT(_lv_task_act) = next; + continue; /*Load the next task*/ + } + + /*Just try to run the tasks with highest priority.*/ + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) { + lv_task_exec(LV_GC_ROOT(_lv_task_act)); + } + /*Tasks with higher priority then the interrupted shall be run in every case*/ + else if(task_interrupter) { + if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) { + if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) { + task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */ + end_flag = false; + break; + } + } + } + /* It is no interrupter task or we already reached it earlier. + * Just run the remaining tasks*/ + else { + if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) { + task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */ + end_flag = false; + break; + } + } + + if(task_deleted) break; /*If a task was deleted then this or the next item might be corrupted*/ + if(task_created) break; /*If a task was deleted then this or the next item might be corrupted*/ + + LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/ + } + } while(!end_flag); + + busy_time += lv_tick_elaps(handler_start); + uint32_t idle_period_time = lv_tick_elaps(idle_period_start); + if(idle_period_time >= IDLE_MEAS_PERIOD) { + + idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/ + idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/ + busy_time = 0; + idle_period_start = lv_tick_get(); + + + } + + task_handler_mutex = false; /*Release the mutex*/ + + LV_LOG_TRACE("lv_task_handler ready"); +} + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param) +{ + lv_task_t * new_lv_task = NULL; + lv_task_t * tmp; + + /*Create task lists in order of priority from high to low*/ + tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + if(NULL == tmp) { /*First task*/ + new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + } else { + do { + if(tmp->prio <= prio) { + new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + break; + } + tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp); + } while(tmp != NULL); + + if(tmp == NULL) { /*Only too high priority tasks were found*/ + new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_lv_task); + if(new_lv_task == NULL) return NULL; + } + } + + new_lv_task->period = period; + new_lv_task->task = task; + new_lv_task->prio = prio; + new_lv_task->param = param; + new_lv_task->once = 0; + new_lv_task->last_run = lv_tick_get(); + + task_created = true; + + return new_lv_task; +} + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t * lv_task_p) +{ + lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p); + + lv_mem_free(lv_task_p); + + if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/ +} + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio) +{ + /*Find the tasks with new priority*/ + lv_task_t * i; + LL_READ(LV_GC_ROOT(_lv_task_ll), i) { + if(i->prio <= prio) { + if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i); + break; + } + } + + /*There was no such a low priority so far then add the node to the tail*/ + if(i == NULL) { + lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL); + } + + + lv_task_p->prio = prio; +} + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period) +{ + lv_task_p->period = period; +} + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t * lv_task_p) +{ + lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1; +} + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p) +{ + lv_task_p->once = 1; +} + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t * lv_task_p) +{ + lv_task_p->last_run = lv_tick_get(); +} + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en) +{ + lv_task_run = en; +} + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void) +{ + return idle_last; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Execute task if its the priority is appropriate + * @param lv_task_p pointer to lv_task + * @return true: execute, false: not executed + */ +static bool lv_task_exec(lv_task_t * lv_task_p) +{ + bool exec = false; + + /*Execute if at least 'period' time elapsed*/ + uint32_t elp = lv_tick_elaps(lv_task_p->last_run); + if(elp >= lv_task_p->period) { + lv_task_p->last_run = lv_tick_get(); + task_deleted = false; + task_created = false; + lv_task_p->task(lv_task_p->param); + + /*Delete if it was a one shot lv_task*/ + if(task_deleted == false) { /*The task might be deleted by itself as well*/ + if(lv_task_p->once != 0) { + lv_task_del(lv_task_p); + } + } + exec = true; + } + + return exec; +} + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.h new file mode 100644 index 0000000..aa6c903 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_task.h @@ -0,0 +1,149 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +#ifndef LV_TASK_H +#define LV_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER +#endif +/********************** + * TYPEDEFS + **********************/ +/** + * Possible priorities for lv_tasks + */ +#define LV_TASK_ONESHOT 0 +enum +{ + LV_TASK_PRIO_OFF = 0, + LV_TASK_PRIO_LOWEST, + LV_TASK_PRIO_LOW, + LV_TASK_PRIO_MID, + LV_TASK_PRIO_HIGH, + LV_TASK_PRIO_HIGHEST, + LV_TASK_PRIO_NUM, +}; +typedef uint8_t lv_task_prio_t; + +/** + * Descriptor of a lv_task + */ +typedef struct +{ + uint32_t period; + uint32_t last_run; + void (*task) (void*); + void * param; + uint8_t prio:3; + uint8_t once:1; +} lv_task_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void); + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param); + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t* lv_task_p); + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio); + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period); + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t* lv_task_p); + + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p); + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t* lv_task_p); + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en); + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.c new file mode 100644 index 0000000..11478b7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.c @@ -0,0 +1,36 @@ +/** + * @file lv_templ.c + * + */ + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.h new file mode 100644 index 0000000..a5459e8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_templ.h @@ -0,0 +1,38 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.c new file mode 100644 index 0000000..d80c3b4 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.c @@ -0,0 +1,793 @@ +/** + * @file lv_text.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_txt.h" +#include "lv_math.h" + +/********************* + * DEFINES + *********************/ +#define NO_BREAK_FOUND UINT32_MAX + +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#endif + +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#endif + +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool is_break_char(uint32_t letter); + +#if LV_TXT_UTF8 +static uint8_t lv_txt_utf8_size(const char * str); +static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni); +static uint32_t lv_txt_utf8_conv_wc(uint32_t c); +static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i); +static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start); +static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id); +static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id); +static uint32_t lv_txt_utf8_get_length(const char * txt); +#else +static uint8_t lv_txt_ascii_size(const char * str); +static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni); +static uint32_t lv_txt_ascii_conv_wc(uint32_t c); +static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i); +static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i_start); +static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id); +static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id); +static uint32_t lv_txt_ascii_get_length(const char * txt); +#endif + +/********************** + * STATIC VARIABLES + **********************/ + + +/********************** + * GLOBAL VARIABLES + **********************/ +#if LV_TXT_UTF8 +uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size; +uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc; +uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next; +uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev; +uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id; +uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; +uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length; +#else +uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_ascii_size; +uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_ascii; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_ascii_conv_wc; +uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_ascii_next; +uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_ascii_prev; +uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_ascii_get_byte_id; +uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_ascii_get_char_id; +uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_ascii_get_length; +#endif +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param txt.line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag) +{ + size_res->x = 0; + size_res->y = 0; + + if(text == NULL) return; + if(font == NULL) return; + + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; + + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t act_line_length; + uint8_t letter_height = lv_font_get_height(font); + + /*Calc. the height and longest line*/ + while(text[line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag); + size_res->y += letter_height ; + size_res->y += line_space; + + /*Calculate the the longest line*/ + act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start, + font, letter_space, flag); + + size_res->x = LV_MATH_MAX(act_line_length, size_res->x); + line_start = new_line_start; + } + + /*Make the text one line taller if the last character is '\n' or '\r'*/ + if((line_start != 0) && (text[line_start - 1] == '\n' || text[line_start - 1] == '\r')) { + size_res->y += letter_height + line_space; + } + + /*Correction with the last line space or set the height manually if the text is empty*/ + if(size_res->y == 0) size_res->y = letter_height; + else size_res->y -= line_space; + +} + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag) +{ + if(txt == NULL) return 0; + if(font == NULL) return 0; + + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; + + uint32_t i = 0; + lv_coord_t cur_w = 0; + lv_coord_t w_at_last_break = 0; + uint32_t n_char_since_last_break = 0; /* Used count word length of long words */ + uint32_t last_break = NO_BREAK_FOUND; + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t letter = 0; + + while(txt[i] != '\0') { + lv_coord_t letter_width; + letter = lv_txt_encoded_next(txt, &i); + + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + + /*Check for new line chars*/ + if(letter == '\n' || letter == '\r') { + uint32_t i_tmp = i; + uint32_t letter_next = lv_txt_encoded_next(txt, &i_tmp); + if(letter == '\r' && letter_next == '\n') i = i_tmp; + + return i; /*Return with the first letter of the next line*/ + + } else { /*Check the actual length*/ + n_char_since_last_break++; + letter_width = lv_font_get_width(font, letter); + cur_w += letter_width; + + /* Get the length of the current work and determine best place + * to break the line. */ + if(cur_w > max_width) { + if( last_break != NO_BREAK_FOUND ) { + /* Continue searching for next breakable character to see if the next word will fit */ + uint32_t n_char_fit = n_char_since_last_break - 1; + if( n_char_since_last_break <= LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN ) { + i = last_break; + } + else { + uint32_t i_tmp = i; + cur_w -= w_at_last_break + letter_space; /*ignore the first letter_space after the break char */ + bool other = true; + while(txt[i_tmp] != '\0') { + letter = lv_txt_encoded_next(txt, &i_tmp); + + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + /*Check for new line chars*/ + if(letter == '\n' || letter == '\r' || is_break_char(letter)) { + if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) { + /* Figure out the prettiest place to break */ + uint32_t char_remain; + lv_txt_encoded_prev(txt, &i); + for(char_remain=n_char_since_last_break - n_char_fit; + char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN; + char_remain++) { + lv_txt_encoded_prev(txt, &i); + } + } + else{ + i = last_break; + } + other = false; + break; + } + n_char_since_last_break++; + lv_coord_t letter_width2 = lv_font_get_width(font, letter); + cur_w += letter_width2; + if(cur_w > max_width) { + /* Current letter already exceeds, return previous */ + lv_txt_encoded_prev(txt, &i); + other = false; + break; + } + if(letter_width2 > 0){ + cur_w += letter_space; + } + } + if( other ) { + if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) { + /* Figure out the prettiest place to break */ + uint32_t char_remain; + lv_txt_encoded_prev(txt, &i); + for(char_remain=n_char_since_last_break - n_char_fit; + char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN; + char_remain++){ + lv_txt_encoded_prev(txt, &i); + } + } + else{ + i = last_break; + } + } + } + } else { + /* Now this character is out of the area so it will be first character of the next line*/ + /* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/ + lv_txt_encoded_prev(txt, &i); + } + + /* Do not let to return without doing nothing. + * Find at least one character (Avoid infinite loop )*/ + if(i == 0) lv_txt_encoded_next(txt, &i); + + return i; + } + /*If this char still can fit to this line then check if + * txt can be broken here later */ + else if(is_break_char(letter)) { + last_break = i; /*Save the first char index after break*/ + w_at_last_break = cur_w; + if(letter_width > 0) { + w_at_last_break += letter_space; + } + n_char_since_last_break = 0; + } + } + + if(letter_width > 0) { + cur_w += letter_space; + } + } + + return i; +} + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (à is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag) +{ + if(txt == NULL) return 0; + if(font == NULL) return 0; + + uint32_t i = 0; + lv_coord_t width = 0; + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t letter; + + if(length != 0) { + while(i< length){ + letter = lv_txt_encoded_next(txt, &i); + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, letter) != false) { + continue; + } + } + + lv_coord_t char_width = lv_font_get_width(font, letter); + if(char_width > 0){ + width += char_width; + width += letter_space; + } + } + + if(width > 0) { + width -= letter_space; /*Trim the last letter space. Important if the text is center aligned */ + } + } + + return width; +} + +/** + * Check next character in a string and decide if the character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * (Initied. to TXT_CMD_STATE_WAIT ) + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c) +{ + bool ret = false; + + if(c == (uint32_t)LV_TXT_COLOR_CMD[0]) { + if(*state == LV_TXT_CMD_STATE_WAIT) { /*Start char*/ + *state = LV_TXT_CMD_STATE_PAR; + ret = true; + } else if(*state == LV_TXT_CMD_STATE_PAR) { /*Other start char in parameter is escaped cmd. char */ + *state = LV_TXT_CMD_STATE_WAIT; + } else if(*state == LV_TXT_CMD_STATE_IN) { /*Command end */ + *state = LV_TXT_CMD_STATE_WAIT; + ret = true; + } + } + + /*Skip the color parameter and wait the space after it*/ + if(*state == LV_TXT_CMD_STATE_PAR) { + if(c == ' ') { + *state = LV_TXT_CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + ret = true; + } + + return ret; +} + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before the original text, 1: after the first char etc. + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) +{ + uint32_t old_len = strlen(txt_buf); + uint32_t ins_len = strlen(ins_txt); + uint32_t new_len = ins_len + old_len; +#if LV_TXT_UTF8 != 0 + pos = lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/ +#endif + /*Copy the second part into the end to make place to text to insert*/ + uint32_t i; + for(i = new_len; i >= pos + ins_len; i--) { + txt_buf[i] = txt_buf[i - ins_len]; + } + + /* Copy the text into the new space*/ + memcpy(txt_buf + pos, ins_txt, ins_len); +} + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len) +{ + + uint32_t old_len = strlen(txt); +#if LV_TXT_UTF8 != 0 + pos = lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/ + len = lv_txt_encoded_get_byte_id(&txt[pos], len); +#endif + + /*Copy the second part into the end to make place to text to insert*/ + uint32_t i; + for(i = pos; i <= old_len - len; i++) { + txt[i] = txt[i + len]; + } +} + + +/******************************* + * UTF-8 ENCODER/DECOER + ******************************/ + +#if LV_TXT_UTF8 + +/** + * Give the size of an UTF-8 coded character + * @param str pointer to a character in a string + * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code + */ +static uint8_t lv_txt_utf8_size(const char * str) +{ + if((str[0] & 0x80) == 0) return 1; + else if((str[0] & 0xE0) == 0xC0) return 2; + else if((str[0] & 0xF0) == 0xE0) return 3; + else if((str[0] & 0xF8) == 0xF0) return 4; + return 0; +} + + +/** + * Convert an Unicode letter to UTF-8. + * @param letter_uni an Unicode letter + * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Ã', 'Å°') + */ +static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni) +{ + if(letter_uni < 128) return letter_uni; + uint8_t bytes[4]; + + if(letter_uni < 0x0800) { + bytes[0] = ((letter_uni >> 6) & 0x1F) | 0xC0; + bytes[1] = ((letter_uni >> 0) & 0x3F) | 0x80; + bytes[2] = 0; + bytes[3] = 0; + } else if(letter_uni < 0x010000) { + bytes[0] = ((letter_uni >> 12) & 0x0F) | 0xE0; + bytes[1] = ((letter_uni >> 6) & 0x3F) | 0x80; + bytes[2] = ((letter_uni >> 0) & 0x3F) | 0x80; + bytes[3] = 0; + } else if(letter_uni < 0x110000) { + bytes[0] = ((letter_uni >> 18) & 0x07) | 0xF0; + bytes[1] = ((letter_uni >> 12) & 0x3F) | 0x80; + bytes[2] = ((letter_uni >> 6) & 0x3F) | 0x80; + bytes[3] = ((letter_uni >> 0) & 0x3F) | 0x80; + } + + uint32_t * res_p = (uint32_t *)bytes; + return *res_p; +} + +/** + * Convert a wide character, e.g. 'Ã' little endian to be UTF-8 compatible + * @param c a wide character or a Little endian number + * @return `c` in big endian + */ +static uint32_t lv_txt_utf8_conv_wc(uint32_t c) +{ + /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/ + if((c & 0x80) != 0) { + uint32_t swapped; + uint8_t c8[4]; + memcpy(c8, &c, 4); + swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]); + uint8_t i; + for(i = 0; i < 4; i++) { + if((swapped & 0xFF) == 0) swapped = (swapped >> 8); /*Ignore leading zeros (they were in the end originally)*/ + } + c = swapped; + } + + return c; +} + +/** + * Decode an UTF-8 character from a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. + * After call it will point to the next UTF-8 char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i) +{ + /* Unicode to UTF-8 + * 00000000 00000000 00000000 0xxxxxxx -> 0xxxxxxx + * 00000000 00000000 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx + * 00000000 00000000 zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx + * 00000000 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx + * */ + + uint32_t result = 0; + + /*Dummy 'i' pointer is required*/ + uint32_t i_tmp = 0; + if(i == NULL) i = &i_tmp; + + /*Normal ASCII*/ + if((txt[*i] & 0x80) == 0) { + result = txt[*i]; + (*i)++; + } + /*Real UTF-8 decode*/ + else { + /*2 bytes UTF-8 code*/ + if((txt[*i] & 0xE0) == 0xC0) { + result = (uint32_t)(txt[*i] & 0x1F) << 6; + (*i)++; + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (txt[*i] & 0x3F); + (*i)++; + } + /*3 bytes UTF-8 code*/ + else if((txt[*i] & 0xF0) == 0xE0) { + result = (uint32_t)(txt[*i] & 0x0F) << 12; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 6; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (txt[*i] & 0x3F); + (*i)++; + } + /*4 bytes UTF-8 code*/ + else if((txt[*i] & 0xF8) == 0xF0) { + result = (uint32_t)(txt[*i] & 0x07) << 18; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 12; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += (uint32_t)(txt[*i] & 0x3F) << 6; + (*i)++; + + if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ + result += txt[*i] & 0x3F; + (*i)++; + } else { + (*i)++; /*Not UTF-8 char. Go the next.*/ + } + } + return result; +} + +/** + * Get previous UTF-8 character form a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'. + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i) +{ + uint8_t c_size; + uint8_t cnt = 0; + + /*Try to find a !0 long UTF-8 char by stepping one character back*/ + (*i)--; + do { + if(cnt >= 4) return 0; /*No UTF-8 char found before the initial*/ + + c_size = lv_txt_encoded_size(&txt[*i]); + if(c_size == 0) { + if(*i != 0)(*i)--; + else return 0; + } + cnt++; + } while(c_size == 0); + + uint32_t i_tmp = *i; + uint32_t letter = lv_txt_encoded_next(txt, &i_tmp); /*Character found, get it*/ + + return letter; + +} + +/** + * Convert a character index (in an UTF-8 text) to byte index. + * E.g. in "AÃRT" index of 'R' is 2th char but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param utf8_id character index + * @return byte index of the 'utf8_id'th letter + */ +static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id) +{ + uint32_t i; + uint32_t byte_cnt = 0; + for(i = 0; i < utf8_id; i++) { + byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]); + } + + return byte_cnt; + +} + + +/** + * Convert a byte index (in an UTF-8 text) to character index. + * E.g. in "AÃRT" index of 'R' is 2th char but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id) +{ + uint32_t i = 0; + uint32_t char_cnt = 0; + + while(i < byte_id) { + lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/ + char_cnt++; + } + + return char_cnt; +} + +/** + * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled. + * E.g.: "ÃBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +static uint32_t lv_txt_utf8_get_length(const char * txt) +{ +#if LV_TXT_UTF8 == 0 + return strlen(txt); +#else + uint32_t len = 0; + uint32_t i = 0; + + while(txt[i] != '\0') { + lv_txt_encoded_next(txt, &i); + len++; + } + + return len; +#endif +} + +#else +/** + * Give the size of an UTF-8 coded character + * @param str pointer to a character in a string + * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code + */ +static uint8_t lv_txt_ascii_size(const char * str) +{ + return 1; +} + + +/** + * Convert an Unicode letter to UTF-8. + * @param letter_uni an Unicode letter + * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Ã', 'Å°') + */ +static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni) +{ + if(letter_uni < 128) return letter_uni; + else return ' '; +} + +/** + * Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default. + * So this function does nothing just returns with `c`. + * @param c a character, e.g. 'A' + * @return same as `c` + */ +static uint32_t lv_txt_ascii_conv_wc(uint32_t c) +{ + return c; +} + +/** + * Decode an UTF-8 character from a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. + * After call it will point to the next UTF-8 char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i) +{ + if(i == NULL) return txt[1]; /*Get the next char */ + + uint8_t letter = txt[*i] ; + (*i)++; + return letter; +} + +/** + * Get previous UTF-8 character form a string. + * @param txt pointer to '\0' terminated string + * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'. + * @return the decoded Unicode character or 0 on invalid UTF-8 code + */ +static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i) +{ + if(i == NULL) return *(txt - 1); /*Get the prev. char */ + + (*i)--; + uint8_t letter = txt[*i] ; + + return letter; +} + +/** + * Convert a character index (in an UTF-8 text) to byte index. + * E.g. in "AÃRT" index of 'R' is 2th char but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param utf8_id character index + * @return byte index of the 'utf8_id'th letter + */ +static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id) +{ + return utf8_id; /*In Non encoded no difference*/ +} + + +/** + * Convert a byte index (in an UTF-8 text) to character index. + * E.g. in "AÃRT" index of 'R' is 2th char but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +static uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id) +{ + return byte_id; /*In Non encoded no difference*/ +} + +/** + * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled. + * E.g.: "ÃBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +static uint32_t lv_txt_ascii_get_length(const char * txt) +{ + return strlen(txt); +} +#endif +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Test if char is break char or not (a text can broken here or not) + * @param letter a letter + * @return false: 'letter' is not break char + */ +static bool is_break_char(uint32_t letter) +{ + uint8_t i; + bool ret = false; + + /*Compare the letter to TXT_BREAK_CHARS*/ + for(i = 0; LV_TXT_BREAK_CHARS[i] != '\0'; i++) { + if(letter == (uint32_t)LV_TXT_BREAK_CHARS[i]) { + ret = true; /*If match then it is break char*/ + break; + } + } + + return ret; +} + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.h new file mode 100644 index 0000000..81b55f9 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_txt.h @@ -0,0 +1,197 @@ +/** + * @file lv_text.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "lv_area.h" +#include "lv_font.h" +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_TXT_COLOR_CMD "#" + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_TXT_FLAG_NONE = 0x00, + LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/ + LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/ + LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/ +}; +typedef uint8_t lv_txt_flag_t; + +enum +{ + LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/ + LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/ + LV_TXT_CMD_STATE_IN, /*Processing the command*/ +}; +typedef uint8_t lv_txt_cmd_state_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (à is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag); + + +/** + * Check next character in a string and decide if te character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE + ***************************************************************/ + +/** + * Give the size of an encoded character + * @param str pointer to a character in a string + * @return length of the encoded character (1,2,3 ...). O in invalid + */ +extern uint8_t (*lv_txt_encoded_size)(const char *); + + +/** + * Convert an Unicode letter to encoded + * @param letter_uni an Unicode letter + * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Ã', 'Ãœ') + */ +extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t ); + +/** + * Convert a wide character, e.g. 'Ã' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c); + +/** + * Decode the next encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param i start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid data code + */ +extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * ); + +/** + * Get the previous encoded character form a string. + * @param txt pointer to '\0' terminated string + * @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'. + * @return the decoded Unicode character or 0 on invalid data + */ +extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); + +/** + * Convert a letter index (in an the encoded text) to byte index. + * E.g. in UTF-8 "AÃRT" index of 'R' is 2 but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param enc_id letter index + * @return byte index of the 'enc_id'th letter + */ +extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); + +/** + * Convert a byte index (in an encoded text) to character index. + * E.g. in UTF-8 "AÃRT" index of 'R' is 2 but start at byte 3 because 'Ã' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t); + +/** + * Get the number of characters (and NOT bytes) in a string. + * E.g. in UTF-8 "ÃBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +extern uint32_t (*lv_txt_get_encoded_length)(const char *); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_TXT*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.c b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.c new file mode 100644 index 0000000..ef1a165 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.c @@ -0,0 +1,516 @@ +/** + * @file lv_ufs.c + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_ufs.h" +#if USE_LV_FILESYSTEM + +#include "lv_ll.h" +#include +#include +#include +#include "lv_gc.h" + +#if defined(LV_GC_INCLUDE) +# include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_ufs_ent_t * lv_ufs_ent_get(const char * fn); +static lv_ufs_ent_t * lv_ufs_ent_new(const char * fn); + +/********************** + * STATIC VARIABLES + **********************/ +static bool inited = false; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_file_ll), sizeof(lv_ufs_ent_t)); + + lv_fs_drv_t ufs_drv; + memset(&ufs_drv, 0, sizeof(lv_fs_drv_t)); /*Initialization*/ + + ufs_drv.file_size = sizeof(lv_ufs_file_t); + ufs_drv.rddir_size = sizeof(lv_ufs_dir_t); + ufs_drv.letter = UFS_LETTER; + ufs_drv.ready = lv_ufs_ready; + + ufs_drv.open = lv_ufs_open; + ufs_drv.close = lv_ufs_close; + ufs_drv.remove = lv_ufs_remove; + ufs_drv.read = lv_ufs_read; + ufs_drv.write = lv_ufs_write; + ufs_drv.seek = lv_ufs_seek; + ufs_drv.tell = lv_ufs_tell; + ufs_drv.size = lv_ufs_size; + ufs_drv.trunc = lv_ufs_trunc; + ufs_drv.free = lv_ufs_free; + + ufs_drv.dir_open = lv_ufs_dir_open; + ufs_drv.dir_read = lv_ufs_dir_read; + ufs_drv.dir_close = lv_ufs_dir_close; + + lv_fs_add_drv(&ufs_drv); + + inited = true; +} + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void) +{ + return inited; +} + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_open(void * file_p, const char * fn, lv_fs_mode_t mode) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = lv_ufs_ent_get(fn); + + fp->ent = NULL; + + /*If the file not exists ...*/ + if(ent == NULL) { + if((mode & LV_FS_MODE_WR) != 0) { /*Create the file if opened for write*/ + ent = lv_ufs_ent_new(fn); + if(ent == NULL) return LV_FS_RES_FULL; /*No space for the new file*/ + } else { + return LV_FS_RES_NOT_EX; /*Can not read not existing file*/ + } + } + + /*Can not write already opened and const data files*/ + if((mode & LV_FS_MODE_WR) != 0) { + if(ent->oc != 0) return LV_FS_RES_LOCKED; + if(ent->const_data != 0) return LV_FS_RES_DENIED; + } + + /*No error, the file can be opened*/ + fp->ent = ent; + fp->ar = mode & LV_FS_MODE_RD ? 1 : 0; + fp->aw = mode & LV_FS_MODE_WR ? 1 : 0; + fp->rwp = 0; + ent->oc ++; + + return LV_FS_RES_OK; +} + + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len) +{ + lv_ufs_file_t file; + lv_fs_res_t res; + + /*Error if the file already exists*/ + res = lv_ufs_open(&file, fn, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + lv_ufs_close(&file); + return LV_FS_RES_DENIED; + } + + lv_ufs_close(&file); + + res = lv_ufs_open(&file, fn, LV_FS_MODE_WR); + if(res != LV_FS_RES_OK) return res; + + lv_ufs_ent_t * ent = file.ent; + + if(ent->data_d != NULL) return LV_FS_RES_DENIED; + + ent->data_d = (void *) const_p; + ent->size = len; + ent->const_data = 1; + + res = lv_ufs_close(&file); + if(res != LV_FS_RES_OK) return res; + + return LV_FS_RES_OK; +} + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_close(void * file_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + if(fp->ent == NULL) return LV_FS_RES_OK; + + /*Decrement the Open counter*/ + if(fp->ent->oc > 0) { + fp->ent->oc--; + } + + return LV_FS_RES_OK; +} + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn) +{ + lv_ufs_ent_t * ent = lv_ufs_ent_get(fn); + if(ent == NULL) return LV_FS_RES_DENIED; /*File not exists*/ + + /*Can not be deleted is opened*/ + if(ent->oc != 0) return LV_FS_RES_DENIED; + + lv_ll_rem(&LV_GC_ROOT(_lv_file_ll), ent); + lv_mem_free(ent->fn_d); + ent->fn_d = NULL; + if(ent->const_data == 0) { + lv_mem_free(ent->data_d); + ent->data_d = NULL; + } + + lv_mem_free(ent); + + return LV_FS_RES_OK; +} + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_read(void * file_p, void * buf, uint32_t btr, uint32_t * br) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + lv_ufs_ent_t * ent = fp->ent; + *br = 0; + + if(ent->data_d == NULL || ent->size == 0) { /*Don't read empty files*/ + return LV_FS_RES_OK; + } else if(fp->ar == 0) { /*The file is not opened for read*/ + return LV_FS_RES_DENIED; + } + + /*No error, read the file*/ + if(fp->rwp + btr > ent->size) { /*Check too much bytes read*/ + *br = ent->size - fp->rwp; + } else { + *br = btr; + } + + /*Read the data*/ + uint8_t * data8_p; + if(ent->const_data == 0) { + data8_p = (uint8_t *) ent->data_d; + } else { + data8_p = ent->data_d; + } + + data8_p += fp->rwp; + memcpy(buf, data8_p, *br); + + fp->rwp += *br; /*Refresh the read write pointer*/ + + return LV_FS_RES_OK; +} + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_write(void * file_p, const void * buf, uint32_t btw, uint32_t * bw) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + *bw = 0; + + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + lv_ufs_ent_t * ent = fp->ent; + + /*Reallocate data array if it necessary*/ + uint32_t new_size = fp->rwp + btw; + if(new_size > ent->size) { + uint8_t * new_data = lv_mem_realloc(ent->data_d, new_size); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Cannot allocate the new memory*/ + + ent->data_d = new_data; + ent->size = new_size; + } + + /*Write the file*/ + uint8_t * data8_p = (uint8_t *) ent->data_d; + data8_p += fp->rwp; + memcpy(data8_p, buf, btw); + *bw = btw; + fp->rwp += *bw; + + return LV_FS_RES_OK; +} + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek(void * file_p, uint32_t pos) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + /*Simply move the rwp before EOF*/ + if(pos < ent->size) { + fp->rwp = pos; + } else { /*Expand the file size*/ + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + uint8_t * new_data = lv_mem_realloc(ent->data_d, pos); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/ + + ent->data_d = new_data; + ent->size = pos; + fp->rwp = pos; + } + + return LV_FS_RES_OK; +} + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell(void * file_p, uint32_t * pos_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + + *pos_p = fp->rwp; + + return LV_FS_RES_OK; +} + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc(void * file_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/ + + void * new_data = lv_mem_realloc(ent->data_d, fp->rwp); + lv_mem_assert(new_data); + if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/ + + ent->data_d = new_data; + ent->size = fp->rwp; + + return LV_FS_RES_OK; +} + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_size(void * file_p, uint32_t * size_p) +{ + lv_ufs_file_t * fp = file_p; /*Convert type*/ + lv_ufs_ent_t * ent = fp->ent; + + *size_p = ent->size; + + return LV_FS_RES_OK; +} + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path) +{ + lv_ufs_dir_t * lv_ufs_rddir_p = rddir_p; + + lv_ufs_rddir_p->last_ent = NULL; + + if(path[0] != '\0') return LV_FS_RES_NOT_EX; /*Must be "" */ + else return LV_FS_RES_OK; +} + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn) +{ + lv_ufs_dir_t * ufs_dir_p = dir_p; + + if(ufs_dir_p->last_ent == NULL) { + ufs_dir_p->last_ent = lv_ll_get_head(&LV_GC_ROOT(_lv_file_ll)); + } else { + ufs_dir_p->last_ent = lv_ll_get_next(&LV_GC_ROOT(_lv_file_ll), ufs_dir_p->last_ent); + } + + if(ufs_dir_p->last_ent != NULL) { + strcpy(fn, ufs_dir_p->last_ent->fn_d); + } else { + fn[0] = '\0'; + } + + return LV_FS_RES_OK; +} + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv__fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p) +{ + (void)rddir_p; + return LV_FS_RES_OK; +} + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'lv_fs_res_t' + */ +lv_fs_res_t lv_ufs_free(uint32_t * total_p, uint32_t * free_p) +{ + +#if LV_MEM_CUSTOM == 0 + lv_mem_monitor_t mon; + + lv_mem_monitor(&mon); + *total_p = LV_MEM_SIZE >> 10; /*Convert bytes to kB*/ + *free_p = mon.free_size >> 10; +#else + *free_p = 0; +#endif + return LV_FS_RES_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Gives the lv_ufs_entry from a filename + * @param fn filename ('\0' terminated string) + * @return pointer to the dynamically allocated entry with 'fn' filename. + * NULL if no entry found with that name. + */ +static lv_ufs_ent_t * lv_ufs_ent_get(const char * fn) +{ + lv_ufs_ent_t * fp; + + LL_READ(LV_GC_ROOT(_lv_file_ll), fp) { + if(strcmp(fp->fn_d, fn) == 0) { + return fp; + } + } + + return NULL; +} + +/** + * Create a new entry with 'fn' filename + * @param fn filename ('\0' terminated string) + * @return pointer to the dynamically allocated new entry. + * NULL if no space for the entry. + */ +static lv_ufs_ent_t * lv_ufs_ent_new(const char * fn) +{ + lv_ufs_ent_t * new_ent = NULL; + new_ent = lv_ll_ins_head(&LV_GC_ROOT(_lv_file_ll)); /*Create a new file*/ + lv_mem_assert(new_ent); + if(new_ent == NULL) return NULL; + + new_ent->fn_d = lv_mem_alloc(strlen(fn) + 1); /*Save the name*/ + lv_mem_assert(new_ent->fn_d); + if(new_ent->fn_d == NULL) return NULL; + + strcpy(new_ent->fn_d, fn); + new_ent->data_d = NULL; + new_ent->size = 0; + new_ent->oc = 0; + new_ent->const_data = 0; + + return new_ent; +} + +#endif /*USE_LV_FILESYSTEM*/ + diff --git a/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.h b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.h new file mode 100644 index 0000000..543104f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_misc/lv_ufs.h @@ -0,0 +1,213 @@ +/** + * @file lv_ufs.h + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +#ifndef LV_UFS_H +#define LV_UFS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include "lv_fs.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define UFS_LETTER 'U' + +/********************** + * TYPEDEFS + **********************/ +/*Description of a file entry */ +typedef struct +{ + char * fn_d; + void * data_d; + uint32_t size; /*Data length in bytes*/ + uint16_t oc; /*Open Count*/ + uint8_t const_data :1; +} lv_ufs_ent_t; + +/*File descriptor, used to handle opening an entry more times simultaneously + Contains unique informations about the specific opening*/ +typedef struct +{ + lv_ufs_ent_t* ent; /*Pointer to the entry*/ + uint32_t rwp; /*Read Write Pointer*/ + uint8_t ar :1; /*1: Access for read is enabled */ + uint8_t aw :1; /*1: Access for write is enabled */ +} lv_ufs_file_t; + +/* Read directory descriptor. + * It is used to to iterate through the entries in a directory*/ +typedef struct +{ + lv_ufs_ent_t * last_ent; +} lv_ufs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void); + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void); + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode); + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len); + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_close (void * file_p); + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn); + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc (void * file_p); + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p); + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_read_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path); + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p); + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.c new file mode 100644 index 0000000..683d343 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.c @@ -0,0 +1,310 @@ +/** + * @file lv_arc.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_arc.h" +#if USE_LV_ARC != 0 + +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_arc.h" +#include "../lv_themes/lv_theme.h" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a arc object + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + LV_LOG_TRACE("arc create started"); + + /*Create the ancestor of arc*/ + lv_obj_t * new_arc = lv_obj_create(par, copy); + lv_mem_assert(new_arc); + if(new_arc == NULL) return NULL; + + /*Allocate the arc type specific extended data*/ + lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(new_arc, sizeof(lv_arc_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_arc); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_arc); + + /*Initialize the allocated 'ext' */ + ext->angle_start = 45; + ext->angle_end = 315; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_arc, lv_arc_signal); + lv_obj_set_design_func(new_arc, lv_arc_design); + + /*Init the new arc arc*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, th->arc); + } else { + lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, &lv_style_plain_color); + } + + } + /*Copy an existing arc*/ + else { + lv_arc_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->angle_start = copy_ext->angle_start; + ext->angle_end = copy_ext->angle_end; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_arc); + } + + LV_LOG_INFO("arc created"); + + return new_arc; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + if(start > 360) start = 360; + if(end > 360) end = 360; + + ext->angle_start = start; + ext->angle_end = end; + + lv_obj_invalidate(arc); +} + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_ARC_STYLE_MAIN: + lv_obj_set_style(arc, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + return ext->angle_start; +} + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc) +{ + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + + return ext->angle_end; +} + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_ARC_STYLE_MAIN: + style = lv_obj_get_style(arc); + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the arcs + * @param arc pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc); + lv_style_t * style = lv_arc_get_style(arc, LV_ARC_STYLE_MAIN); + + lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(arc), lv_obj_get_height(arc))) / 2; + lv_coord_t x = arc->coords.x1 + lv_obj_get_width(arc) / 2; + lv_coord_t y = arc->coords.y1 + lv_obj_get_height(arc) / 2; + lv_opa_t opa_scale = lv_obj_get_opa_scale(arc); + lv_draw_arc(x, y, r, mask, ext->angle_start, ext->angle_end, style, opa_scale); + + + /*Draw circle on the ends if enabled */ + if(style->line.rounded) { + lv_coord_t thick_half = style->line.width / 2; + lv_coord_t cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_start) >> LV_TRIGO_SHIFT); + lv_coord_t cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_start + 90) >> LV_TRIGO_SHIFT); + + lv_style_t cir_style; + lv_style_copy(&cir_style, &lv_style_plain); + cir_style.body.grad_color = style->line.color; + cir_style.body.main_color = cir_style.body.grad_color; + cir_style.body.radius = LV_RADIUS_CIRCLE; + lv_area_t cir_area; + cir_area.x1 = cir_x + x - thick_half; + cir_area.y1 = cir_y + y - thick_half; + cir_area.x2 = cir_x + x + thick_half; + cir_area.y2 = cir_y + y + thick_half; + + lv_draw_rect(&cir_area, mask, &cir_style, opa_scale); + + cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_end) >> LV_TRIGO_SHIFT); + cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_end + 90) >> LV_TRIGO_SHIFT); + + cir_area.x1 = cir_x + x - thick_half; + cir_area.y1 = cir_y + y - thick_half; + cir_area.x2 = cir_x + x + thick_half; + cir_area.y2 = cir_y + y + thick_half; + + lv_draw_rect(&cir_area, mask, &cir_style, opa_scale); + } + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the arc + * @param arc pointer to a arc object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(arc, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_arc"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.h new file mode 100644 index 0000000..76231d8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_arc.h @@ -0,0 +1,127 @@ +/** + * @file lv_arc.h + * + */ + + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ARC != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of arc*/ +typedef struct { + /*New data for this type */ + lv_coord_t angle_start; + lv_coord_t angle_end; +} lv_arc_ext_t; + + +/*Styles*/ +enum { + LV_ARC_STYLE_MAIN, +}; +typedef uint8_t lv_arc_style_t; + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a arc objects + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc); + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc); + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ARC*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ARC_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.c new file mode 100644 index 0000000..d83a609 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.c @@ -0,0 +1,429 @@ + + +/** + * @file lv_bar.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_bar.h" +#if USE_LV_BAR != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("lv_bar create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_bar = lv_obj_create(par, copy); + lv_mem_assert(new_bar); + if(new_bar == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_bar); + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_bar); + + /*Allocate the object type specific extended data*/ + lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(new_bar, sizeof(lv_bar_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->min_value = 0; + ext->max_value = 100; + ext->cur_value = 0; + ext->sym = 0; + ext->style_indic = &lv_style_pretty_color; + + lv_obj_set_signal_func(new_bar, lv_bar_signal); + lv_obj_set_design_func(new_bar, lv_bar_design); + + /*Init the new bar object*/ + if(copy == NULL) { + lv_obj_set_click(new_bar, false); + lv_obj_set_size(new_bar, LV_DPI * 2, LV_DPI / 3); + lv_bar_set_value(new_bar, ext->cur_value); + + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_bar_set_style(new_bar, LV_BAR_STYLE_BG, th->bar.bg); + lv_bar_set_style(new_bar, LV_BAR_STYLE_INDIC, th->bar.indic); + } else { + lv_obj_set_style(new_bar, &lv_style_pretty); + } + } else { + lv_bar_ext_t * ext_copy = lv_obj_get_ext_attr(copy); + ext->min_value = ext_copy->min_value; + ext->max_value = ext_copy->max_value; + ext->cur_value = ext_copy->cur_value; + ext->style_indic = ext_copy->style_indic; + ext->sym = ext_copy->sym; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_bar); + + lv_bar_set_value(new_bar, ext->cur_value); + } + + LV_LOG_INFO("bar created"); + + return new_bar; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->cur_value == value) return; + + ext->cur_value = value > ext->max_value ? ext->max_value : value; + ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value; + lv_obj_invalidate(bar); +} + +#if USE_LV_ANIMATION +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->cur_value == value) return; + + int16_t new_value; + new_value = value > ext->max_value ? ext->max_value : value; + new_value = new_value < ext->min_value ? ext->min_value : new_value; + + lv_anim_t a; + a.var = bar; + a.start = ext->cur_value; + a.end = new_value; + a.fp = (lv_anim_fp_t)lv_bar_set_value; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + lv_anim_create(&a); +} +#endif + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + if(ext->min_value == min && ext->max_value == max) return; + + ext->max_value = max; + ext->min_value = min; + if(ext->cur_value > max) { + ext->cur_value = max; + lv_bar_set_value(bar, ext->cur_value); + } + if(ext->cur_value < min) { + ext->cur_value = min; + lv_bar_set_value(bar, ext->cur_value); + } + lv_obj_invalidate(bar); +} + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + ext->sym = en ? 1 : 0; +} + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, lv_style_t * style) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + switch(type) { + case LV_BAR_STYLE_BG: + lv_obj_set_style(bar, style); + break; + case LV_BAR_STYLE_INDIC: + ext->style_indic = style; + lv_obj_refresh_ext_size(bar); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->cur_value; +} + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->min_value; +} + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->max_value; +} + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar) +{ + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + return ext->sym ? true : false; +} + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t * bar, lv_bar_style_t type) +{ + lv_style_t * style = NULL; + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + switch(type) { + case LV_BAR_STYLE_BG: + style = lv_obj_get_style(bar); + break; + case LV_BAR_STYLE_INDIC: + style = ext->style_indic; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the bars + * @param bar pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask area*/ + return ancestor_design_f(bar, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(bar); + +#if USE_LV_GROUP == 0 + ancestor_design_f(bar, mask, mode); +#else + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(bar)) { + lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG); + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.border.width = 0; + lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale); + } else { + ancestor_design_f(bar, mask, mode); + } +#endif + lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar); + + if(ext->cur_value != ext->min_value || ext->sym) { + lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC); + lv_area_t indic_area; + lv_area_copy(&indic_area, &bar->coords); + indic_area.x1 += style_indic->body.padding.hor; + indic_area.x2 -= style_indic->body.padding.hor; + indic_area.y1 += style_indic->body.padding.ver; + indic_area.y2 -= style_indic->body.padding.ver; + + lv_coord_t w = lv_area_get_width(&indic_area); + lv_coord_t h = lv_area_get_height(&indic_area); + + if(w >= h) { + /*Horizontal*/ + indic_area.x2 = (int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value); + indic_area.x2 = indic_area.x1 + indic_area.x2 - 1; + + if(ext->sym && ext->min_value < 0 && ext->max_value > 0) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = indic_area.x1 + (-ext->min_value * w) / (ext->max_value - ext->min_value); + if(indic_area.x2 > zero) indic_area.x1 = zero; + else { + indic_area.x1 = indic_area.x2; + indic_area.x2 = zero; + } + } + } else { + indic_area.y1 = (int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value); + indic_area.y1 = indic_area.y2 - indic_area.y1 + 1; + + if(ext->sym && ext->min_value < 0 && ext->max_value > 0) { + /*Calculate the coordinate of the zero point*/ + lv_coord_t zero; + zero = indic_area.y2 - (-ext->min_value * h) / (ext->max_value - ext->min_value); + if(indic_area.y1 < zero) indic_area.y2 = zero; + else { + indic_area.y2 = indic_area.y1; + indic_area.y1 = zero; + } + } + } + + + /*Draw the indicator*/ + lv_draw_rect(&indic_area, mask, style_indic, opa_scale); + } + } else if(mode == LV_DESIGN_DRAW_POST) { +#if USE_LV_GROUP + /*Draw the border*/ + if(lv_obj_is_focused(bar)) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(bar); + lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG); + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.empty = 1; + style_tmp.body.shadow.width = 0; + lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale); + } +#endif + + } + return true; +} + +/** + * Signal function of the bar + * @param bar pointer to a bar object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(bar, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC); + if(style_indic->body.shadow.width > bar->ext_size) bar->ext_size = style_indic->body.shadow.width; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_bar"; + } + + return res; +} + + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.h new file mode 100644 index 0000000..2190384 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_bar.h @@ -0,0 +1,160 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BAR != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of bar*/ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + int16_t cur_value; /*Current value of the bar*/ + int16_t min_value; /*Minimum value of the bar*/ + int16_t max_value; /*Maximum value of the bar*/ + uint8_t sym :1; /*Symmetric: means the center is around zero value*/ + lv_style_t *style_indic; /*Style of the indicator*/ +} lv_bar_ext_t; + +enum { + LV_BAR_STYLE_BG, + LV_BAR_STYLE_INDIC, +}; +typedef uint8_t lv_bar_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value); + +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time); + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max); + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en); + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar); + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar); + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar); + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar); + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BAR_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.c new file mode 100644 index 0000000..f46250c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.c @@ -0,0 +1,763 @@ +/** + * @file lv_btn.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_btn.h" +#if USE_LV_BTN != 0 + +#include +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_BTN_INK_VALUE_MAX 256 +#define LV_BTN_INK_VALUE_MAX_SHIFT 8 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param); + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT +static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val); +static void lv_btn_ink_effect_anim_ready(void * p); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT +static lv_coord_t ink_act_value; +static lv_obj_t * ink_obj; +static lv_btn_state_t ink_bg_state; +static lv_btn_state_t ink_top_state; +static bool ink_ready; +static bool ink_playback; +static lv_point_t ink_point; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("button create started"); + + lv_obj_t * new_btn; + + new_btn = lv_cont_create(par, copy); + lv_mem_assert(new_btn); + if(new_btn == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btn); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_btn); + + /*Allocate the extended data*/ + lv_btn_ext_t * ext = lv_obj_allocate_ext_attr(new_btn, sizeof(lv_btn_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->state = LV_BTN_STATE_REL; + + ext->actions[LV_BTN_ACTION_PR] = NULL; + ext->actions[LV_BTN_ACTION_CLICK] = NULL; + ext->actions[LV_BTN_ACTION_LONG_PR] = NULL; + ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] = NULL; + + ext->styles[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles[LV_BTN_STATE_INA] = &lv_style_btn_ina; + + ext->long_pr_action_executed = 0; + ext->toggle = 0; + ext->idx = 0; +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ext->ink_in_time = 0; + ext->ink_wait_time = 0; + ext->ink_out_time = 0; +#endif + + lv_obj_set_signal_func(new_btn, lv_btn_signal); + lv_obj_set_design_func(new_btn, lv_btn_design); + + /*If no copy do the basic initialization*/ + if(copy == NULL) { + /*Set layout if the button is not a screen*/ + if(par != NULL) { + lv_btn_set_layout(new_btn, LV_LAYOUT_CENTER); + } + + lv_obj_set_click(new_btn, true); /*Be sure the button is clickable*/ + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_btn_set_style(new_btn, LV_BTN_STYLE_REL, th->btn.rel); + lv_btn_set_style(new_btn, LV_BTN_STYLE_PR, th->btn.pr); + lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_REL, th->btn.tgl_rel); + lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_PR, th->btn.tgl_pr); + lv_btn_set_style(new_btn, LV_BTN_STYLE_INA, th->btn.ina); + } else { + lv_obj_set_style(new_btn, ext->styles[LV_BTN_STATE_REL]); + } + } + /*Copy 'copy'*/ + else { + lv_btn_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->state = copy_ext->state; + ext->toggle = copy_ext->toggle; +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ext->ink_in_time = copy_ext->ink_in_time; + ext->ink_wait_time = copy_ext->ink_wait_time; + ext->ink_out_time = copy_ext->ink_out_time; +#endif + memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions)); + memcpy(ext->styles, copy_ext->styles, sizeof(ext->styles)); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_btn); + } + + LV_LOG_INFO("button created"); + + return new_btn; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + ext->toggle = tgl != false ? 1 : 0; +} + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + if(ext->state != state) { + ext->state = state; + lv_obj_set_style(btn, ext->styles[state]); + } +} + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + switch(ext->state) { + case LV_BTN_STATE_REL: + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + break; + case LV_BTN_STATE_PR: + lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR); + break; + case LV_BTN_STATE_TGL_REL: + lv_btn_set_state(btn, LV_BTN_STATE_REL); + break; + case LV_BTN_STATE_TGL_PR: + lv_btn_set_state(btn, LV_BTN_STATE_PR); + break; + default: + break; + } +} + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action) +{ + if(type >= LV_BTN_ACTION_NUM) return; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->actions[type] = action; +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_in_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_ink_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time) +{ + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_wait_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_wait_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + ext->ink_out_time = time; +#else + (void)btn; /*Unused*/ + (void)time; /*Unused*/ + LV_LOG_WARN("`lv_btn_set_ink_out_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled") +#endif +} + +/** + * Set a style of a button + * @param btn pointer to a button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t * style) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + switch(type) { + case LV_BTN_STYLE_REL: + ext->styles[LV_BTN_STATE_REL] = style; + break; + case LV_BTN_STYLE_PR: + ext->styles[LV_BTN_STATE_PR] = style; + break; + case LV_BTN_STYLE_TGL_REL: + ext->styles[LV_BTN_STATE_TGL_REL] = style; + break; + case LV_BTN_STYLE_TGL_PR: + ext->styles[LV_BTN_STATE_TGL_PR] = style; + break; + case LV_BTN_STYLE_INA: + ext->styles[LV_BTN_STATE_INA] = style; + break; + } + + /*Refresh the object with the new style*/ + lv_obj_set_style(btn, ext->styles[ext->state]); +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->state; +} + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn) +{ + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + return ext->toggle != 0 ? true : false; +} + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type) +{ + if(type >= LV_BTN_ACTION_NUM) return NULL; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->actions[type]; +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_in_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} + + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_wait_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn) +{ +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + return ext->ink_in_time; +#else + (void)btn; /*Unused*/ + return 0; +#endif +} + +/** + * Get a style of a button + * @param btn pointer to a button object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type) +{ + lv_style_t * style = NULL; + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + switch(type) { + case LV_BTN_STYLE_REL: + style = ext->styles[LV_BTN_STATE_REL]; + break; + case LV_BTN_STYLE_PR: + style = ext->styles[LV_BTN_STATE_PR]; + break; + case LV_BTN_STYLE_TGL_REL: + style = ext->styles[LV_BTN_STATE_TGL_REL]; + break; + case LV_BTN_STYLE_TGL_PR: + style = ext->styles[LV_BTN_STATE_TGL_PR]; + break; + case LV_BTN_STYLE_INA: + style = ext->styles[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the drop down lists + * @param btn pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } else if(mode == LV_DESIGN_DRAW_MAIN) { + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + if(btn != ink_obj) { + ancestor_design(btn, mask, mode); + } else { + lv_opa_t opa_scale = lv_obj_get_opa_scale(btn); + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + + /*Draw the normal button*/ + if(ink_playback == false) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, ext->styles[ink_bg_state]); + style_tmp.body.shadow.width = ext->styles[ink_top_state]->body.shadow.width; + lv_draw_rect(&btn->coords, mask, &style_tmp, opa_scale); + + lv_coord_t w = lv_obj_get_width(btn); + lv_coord_t h = lv_obj_get_height(btn); + lv_coord_t r_max = LV_MATH_MIN(w, h) / 2; + + /*In the first part of the animation increase the size of the circle (ink effect) */ + lv_area_t cir_area; + + lv_coord_t coord_state = ink_act_value < LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value : LV_BTN_INK_VALUE_MAX / 2; + lv_point_t p_act; + p_act.x = ink_point.x; + p_act.y = ink_point.y; + lv_coord_t x_err = (btn->coords.x1 + w / 2) - p_act.x; + lv_coord_t y_err = (btn->coords.y1 + h / 2) - p_act.y; + + p_act.x += (x_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1); + p_act.y += (y_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1); + + lv_coord_t half_side = LV_MATH_MAX(w, h) / 2; + cir_area.x1 = p_act.x - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.y1 = p_act.y - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.x2 = p_act.x + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + cir_area.y2 = p_act.y + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + + lv_area_intersect(&cir_area, &btn->coords, &cir_area); /*Limit the area. (It might be too big on the smaller side)*/ + + /*In the second part animate the radius. Circle -> body.radius*/ + lv_coord_t r_state = ink_act_value > LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value - LV_BTN_INK_VALUE_MAX / 2 : 0; + + lv_style_copy(&style_tmp, ext->styles[ink_top_state]); + style_tmp.body.radius = r_max + (((ext->styles[ink_bg_state]->body.radius - r_max) * r_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1)); + style_tmp.body.border.width = 0; + + /*Draw the circle*/ + lv_draw_rect(&cir_area, mask, &style_tmp, opa_scale); + } else { + lv_style_t res; + lv_style_copy(&res, ext->styles[ink_bg_state]); + lv_style_mix(ext->styles[ink_bg_state], ext->styles[ink_top_state], &res, ink_act_value); + lv_draw_rect(&btn->coords, mask, &res, opa_scale); + + } + } +#else + ancestor_design(btn, mask, mode); +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(btn, mask, mode); + } + + return true; +} + +/** + * Signal function of the button + * @param btn pointer to a button object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(btn, sign, param); + if(res != LV_RES_OK) return res; + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); + lv_btn_state_t state = lv_btn_get_state(btn); + bool tgl = lv_btn_get_toggle(btn); + + if(sign == LV_SIGNAL_PRESSED) { + /*Refresh the state*/ + if(ext->state == LV_BTN_STATE_REL) { + lv_btn_set_state(btn, LV_BTN_STATE_PR); +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ink_bg_state = LV_BTN_STATE_REL; + ink_top_state = LV_BTN_STATE_PR; +#endif + } else if(ext->state == LV_BTN_STATE_TGL_REL) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR); +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + ink_bg_state = LV_BTN_STATE_TGL_REL; + ink_top_state = LV_BTN_STATE_TGL_PR; +#endif + } + + ext->long_pr_action_executed = 0; + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + /*Forget the old inked button*/ + if(ink_obj != NULL && ink_obj != btn) { + lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim); + lv_obj_invalidate(ink_obj); + ink_obj = NULL; + } + /*Save the new data for inking and start it's animation if enabled*/ + if(ext->ink_in_time > 0) { + ink_obj = btn; + ink_playback = false; + ink_ready = false; + lv_indev_get_point(lv_indev_get_act(), &ink_point); + + lv_anim_t a; + a.var = btn; + a.start = 0; + a.end = LV_BTN_INK_VALUE_MAX; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = 0; + a.time = ext->ink_in_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif + /*Call the press action, 'param' is the caller indev_proc*/ + if(ext->actions[LV_BTN_ACTION_PR] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_PR](btn); + } + } else if(sign == LV_SIGNAL_PRESS_LOST) { + /*Refresh the state*/ + if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(sign == LV_SIGNAL_PRESSING) { + /*When the button begins to drag revert pressed states to released*/ + if(lv_indev_is_dragging(param) != false) { + if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + } else if(sign == LV_SIGNAL_RELEASED) { + /*If not dragged and it was not long press action then + *change state and run the action*/ + if(lv_indev_is_dragging(param) == false && ext->long_pr_action_executed == 0) { + if(ext->state == LV_BTN_STATE_PR && tgl == false) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == false) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(ext->state == LV_BTN_STATE_PR && tgl == true) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == true) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } + + if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else { /*If dragged change back the state*/ + if(ext->state == LV_BTN_STATE_PR) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else if(ext->state == LV_BTN_STATE_TGL_PR) { + lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + } + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + /*Draw the toggled state in the inking instead*/ + if(ext->toggle) { + ink_top_state = ext->state; + } + /*If not a toggle button and the "IN" inking is ready then start an "OUT" inking*/ + else if(ink_ready && ext->ink_out_time > 0) { + ink_obj = btn; + ink_playback = true; /*It is the playback. If not set `lv_btn_ink_effect_anim_ready` will start its own playback*/ + lv_indev_get_point(lv_indev_get_act(), &ink_point); + + lv_anim_t a; + a.var = ink_obj; + a.start = LV_BTN_INK_VALUE_MAX; + a.end = 0; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = 0; + a.time = ext->ink_out_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif + } else if(sign == LV_SIGNAL_LONG_PRESS) { + if(ext->actions[LV_BTN_ACTION_LONG_PR] && state != LV_BTN_STATE_INA) { + ext->long_pr_action_executed = 1; + res = ext->actions[LV_BTN_ACTION_LONG_PR](btn); + } + } else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + if(ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT](btn); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_REL); + if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } else if(c == LV_GROUP_KEY_ENTER) { + if(!ext->long_pr_action_executed) { + if(lv_btn_get_toggle(btn)) { + if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + } else { + if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL); + else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); + } + if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) { + res = ext->actions[LV_BTN_ACTION_CLICK](btn); + } + } + if(res != LV_RES_INV) { + ext->long_pr_action_executed = 0; + } + } + } else if(sign == LV_SIGNAL_CLEANUP) { +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + if(btn == ink_obj) { + lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim); + ink_obj = NULL; + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_btn"; + } + + return res; +} + +#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT + +/** + * The animator function of inking. CAlled to increase the radius of ink + * @param btn pointer to the animated button + * @param val the new radius + */ +static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val) +{ + if(btn) { + ink_act_value = val; + lv_obj_invalidate(btn); + } +} + +/** + * Called to clean up when the ink animation is ready + * @param p unused + */ +static void lv_btn_ink_effect_anim_ready(void * p) +{ + (void) p; /*Unused*/ + + lv_btn_ext_t * ext = lv_obj_get_ext_attr(ink_obj); + lv_btn_state_t state = lv_btn_get_state(ink_obj); + + lv_obj_invalidate(ink_obj); + ink_ready = true; + + if((state == LV_BTN_STATE_REL || state == LV_BTN_STATE_TGL_REL) && ext->toggle == 0 && ink_playback == false) { + lv_anim_t a; + a.var = ink_obj; + a.start = LV_BTN_INK_VALUE_MAX; + a.end = 0; + a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim; + a.path = lv_anim_path_linear; + a.end_cb = lv_btn_ink_effect_anim_ready; + a.act_time = -ext->ink_wait_time; + a.time = ext->ink_out_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + + ink_playback = true; + } else { + ink_obj = NULL; + } +} +#endif /*USE_LV_ANIMATION*/ + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.h new file mode 100644 index 0000000..3a48b62 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btn.h @@ -0,0 +1,280 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "../lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* Button states + * It can be used not only by buttons but other button-like objects too*/ +enum +{ + LV_BTN_STATE_REL, + LV_BTN_STATE_PR, + LV_BTN_STATE_TGL_REL, + LV_BTN_STATE_TGL_PR, + LV_BTN_STATE_INA, + LV_BTN_STATE_NUM, +}; +typedef uint8_t lv_btn_state_t; + +enum +{ + LV_BTN_ACTION_CLICK, + LV_BTN_ACTION_PR, + LV_BTN_ACTION_LONG_PR, + LV_BTN_ACTION_LONG_PR_REPEAT, + LV_BTN_ACTION_NUM, +}; +typedef uint8_t lv_btn_action_t; + + +/*Data of button*/ +typedef struct +{ + lv_cont_ext_t cont; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t actions[LV_BTN_ACTION_NUM]; + lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/ + lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/ + int idx; +#if LV_BTN_INK_EFFECT + uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/ + uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */ + uint16_t ink_out_time; /*[ms] Time of ink disappearing*/ +#endif + uint8_t toggle :1; /*1: Toggle enabled*/ + uint8_t long_pr_action_executed :1; /*1: Long press action executed (Handled by the library)*/ +} lv_btn_ext_t; + +/*Styles*/ +enum { + LV_BTN_STYLE_REL, + LV_BTN_STYLE_PR, + LV_BTN_STYLE_TGL_REL, + LV_BTN_STYLE_TGL_PR, + LV_BTN_STYLE_INA, +}; +typedef uint8_t lv_btn_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl); + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state); + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn); + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action); + +/** + * Set the layout on a button + * @param btn pointer to a button object + * @param layout a layout from 'lv_cont_layout_t' + */ +static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout) +{ + lv_cont_set_layout(btn, layout); +} + +/** + * Enable the horizontal or vertical fit. + * The button size will be set to involve the children horizontally or vertically. + * @param btn pointer to a button object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +static inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(btn, hor_en, ver_en); +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time); + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time); + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time); + +/** + * Set a style of a button. + * @param btn pointer to button object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn); + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn); + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type); + +/** + * Get the layout of a button + * @param btn pointer to button object + * @return the layout from 'lv_cont_layout_t' + */ +static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn) +{ + return lv_cont_get_layout(btn); +} + +/** + * Get horizontal fit enable attribute of a button + * @param btn pointer to a button object + * @return true: horizontal fit is enabled; false: disabled + */ +static inline bool lv_btn_get_hor_fit(const lv_obj_t * btn) +{ + return lv_cont_get_hor_fit(btn); +} + +/** + * Get vertical fit enable attribute of a container + * @param btn pointer to a button object + * @return true: vertical fit is enabled; false: disabled + */ +static inline bool lv_btn_get_ver_fit(const lv_obj_t * btn) +{ + return lv_cont_get_ver_fit(btn); +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn); + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn); + +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn); + +/** + * Get style of a button. + * @param btn pointer to button object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BUTTON*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTN_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.c new file mode 100644 index 0000000..68d04e1 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.c @@ -0,0 +1,881 @@ +/** + * @file lv_btnm.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_btnm.h" +#if USE_LV_BTNM != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_refr.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param); +static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode); +static uint8_t get_button_width(const char * btn_str); +static bool button_is_hidden(const char * btn_str); +static bool button_is_repeat_disabled(const char * btn_str); +static bool button_is_inactive(const char * btn_str); +const char * cut_ctrl_byte(const char * btn_str); +static uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p); +static uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id); +static void allocate_btn_areas(lv_obj_t * btnm, const char ** map); + +/********************** + * STATIC VARIABLES + **********************/ +static const char * lv_btnm_def_map[] = {"Btn1", "Btn2", "Btn3", "\n", + "\002Btn4", "Btn5", "" + }; + +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("button matrix create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_btnm = lv_obj_create(par, copy); + lv_mem_assert(new_btnm); + if(new_btnm == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btnm); + + /*Allocate the object type specific extended data*/ + lv_btnm_ext_t * ext = lv_obj_allocate_ext_attr(new_btnm, sizeof(lv_btnm_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->btn_cnt = 0; + ext->btn_id_pr = LV_BTNM_PR_NONE; + ext->btn_id_tgl = LV_BTNM_PR_NONE; + ext->button_areas = NULL; + ext->action = NULL; + ext->map_p = NULL; + ext->toggle = 0; + ext->recolor = 0; + ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_btnm); + + lv_obj_set_signal_func(new_btnm, lv_btnm_signal); + lv_obj_set_design_func(new_btnm, lv_btnm_design); + + /*Init the new button matrix object*/ + if(copy == NULL) { + lv_obj_set_size(new_btnm, LV_HOR_RES / 2, LV_VER_RES / 4); + lv_btnm_set_map(new_btnm, lv_btnm_def_map); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BG, th->btnm.bg); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_REL, th->btnm.btn.rel); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_PR, th->btnm.btn.pr); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_REL, th->btnm.btn.tgl_rel); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_PR, th->btnm.btn.tgl_pr); + lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_INA, th->btnm.btn.ina); + } else { + lv_obj_set_style(new_btnm, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_btnm_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + memcpy(ext->styles_btn, copy_ext->styles_btn, sizeof(ext->styles_btn)); + ext->action = copy_ext->action; + ext->toggle = copy_ext->toggle; + ext->btn_id_tgl = copy_ext->btn_id_tgl; + lv_btnm_set_map(new_btnm, lv_btnm_get_map(copy)); + } + + LV_LOG_INFO("button matrix created"); + + return new_btnm; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) (\24x) + * - bit 4: no repeat (on long press) (\22x) + * - bit 3: hidden (\21x) + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map) +{ + if(map == NULL) return; + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + ext->map_p = map; + + /*Analyze the map and create the required number of buttons*/ + allocate_btn_areas(btnm, map); + + /*Set size and positions of the buttons*/ + lv_style_t * style_bg = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + lv_coord_t max_w = lv_obj_get_width(btnm) - 2 * style_bg->body.padding.hor; + lv_coord_t max_h = lv_obj_get_height(btnm) - 2 * style_bg->body.padding.ver; + lv_coord_t act_y = style_bg->body.padding.ver; + + /*Count the lines to calculate button height*/ + uint8_t line_cnt = 1; + uint8_t li; + for(li = 0; strlen(map[li]) != 0; li++) { + if(strcmp(map[li], "\n") == 0) line_cnt ++; + } + + lv_coord_t btn_h = max_h - ((line_cnt - 1) * style_bg->body.padding.inner); + btn_h = btn_h / line_cnt; + btn_h --; /*-1 because e.g. height = 100 means 101 pixels (0..100)*/ + + /* Count the units and the buttons in a line + * (A button can be 1,2,3... unit wide)*/ + uint16_t unit_cnt; /*Number of units in a row*/ + uint16_t unit_act_cnt; /*Number of units currently put in a row*/ + uint16_t btn_cnt; /*Number of buttons in a row*/ + uint16_t i_tot = 0; /*Act. index in the str map*/ + uint16_t btn_i = 0; /*Act. index of button areas*/ + const char ** map_p_tmp = map; + + /*Count the units and the buttons in a line*/ + while(1) { + unit_cnt = 0; + btn_cnt = 0; + /*Count the buttons in a line*/ + while(strcmp(map_p_tmp[btn_cnt], "\n") != 0 && + strlen(map_p_tmp[btn_cnt]) != 0) { /*Check a line*/ + unit_cnt += get_button_width(map_p_tmp[btn_cnt]); + btn_cnt ++; + } + + /*Make sure the last row is at the bottom of 'btnm'*/ + if(map_p_tmp[btn_cnt][0] == '\0') { /*Last row?*/ + btn_h = max_h - act_y + style_bg->body.padding.ver - 1; + } + + /*Only deal with the non empty lines*/ + if(btn_cnt != 0) { + /*Calculate the width of all units*/ + lv_coord_t all_unit_w = max_w - ((btn_cnt - 1) * style_bg->body.padding.inner); + + /*Set the button size and positions and set the texts*/ + uint16_t i; + lv_coord_t act_x = style_bg->body.padding.hor; + lv_coord_t act_unit_w; + unit_act_cnt = 0; + for(i = 0; i < btn_cnt; i++) { + /* one_unit_w = all_unit_w / unit_cnt + * act_unit_w = one_unit_w * button_width + * do this two operations but the multiply first to divide a greater number */ + act_unit_w = (all_unit_w * get_button_width(map_p_tmp[i])) / unit_cnt; + act_unit_w --; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/ + + /*Always recalculate act_x because of rounding errors */ + act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + style_bg->body.padding.hor; + + /* Set the button's area. + * If inner padding is zero then use the prev. button x2 as x1 to avoid rounding errors*/ + if(style_bg->body.padding.inner == 0 && act_x != style_bg->body.padding.hor) { + lv_area_set(&ext->button_areas[btn_i], ext->button_areas[btn_i - 1].x2, act_y, + act_x + act_unit_w, act_y + btn_h); + } else { + lv_area_set(&ext->button_areas[btn_i], act_x, act_y, + act_x + act_unit_w, act_y + btn_h); + } + + unit_act_cnt += get_button_width(map_p_tmp[i]); + + i_tot ++; + btn_i ++; + } + } + act_y += btn_h + style_bg->body.padding.inner; + + + if(strlen(map_p_tmp[btn_cnt]) == 0) break; /*Break on end of map*/ + map_p_tmp = &map_p_tmp[btn_cnt + 1]; /*Set the map to the next line*/ + i_tot ++; /*Skip the '\n'*/ + } + + lv_obj_invalidate(btnm); +} + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param cb pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + ext->action = action; +} + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + ext->toggle = en == false ? 0 : 1; + if(ext->toggle != 0) { + if(id >= ext->btn_cnt) id = ext->btn_cnt - 1; + ext->btn_id_tgl = id; + } else { + ext->btn_id_tgl = LV_BTNM_PR_NONE; + } + + lv_obj_invalidate(btnm); +} + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, lv_style_t * style) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + switch(type) { + case LV_BTNM_STYLE_BG: + lv_obj_set_style(btnm, style); + break; + case LV_BTNM_STYLE_BTN_REL: + ext->styles_btn[LV_BTN_STATE_REL] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_PR: + ext->styles_btn[LV_BTN_STATE_PR] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_TGL_REL: + ext->styles_btn[LV_BTN_STATE_TGL_REL] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_TGL_PR: + ext->styles_btn[LV_BTN_STATE_TGL_PR] = style; + lv_obj_invalidate(btnm); + break; + case LV_BTNM_STYLE_BTN_INA: + ext->styles_btn[LV_BTN_STATE_INA] = style; + lv_obj_invalidate(btnm); + break; + } +} + +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + ext->recolor = en; + lv_obj_invalidate(btnm); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->map_p; +} + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->action; +} + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->btn_id_pr; +} + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + if(ext->toggle == 0) return LV_BTNM_PR_NONE; + else return ext->btn_id_tgl; +} + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type) +{ + lv_style_t * style = NULL; + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + switch(type) { + case LV_BTNM_STYLE_BG: + style = lv_obj_get_style(btnm); + break; + case LV_BTNM_STYLE_BTN_REL: + style = ext->styles_btn[LV_BTN_STATE_REL]; + break; + case LV_BTNM_STYLE_BTN_PR: + style = ext->styles_btn[LV_BTN_STATE_PR]; + break; + case LV_BTNM_STYLE_BTN_TGL_REL: + style = ext->styles_btn[LV_BTN_STATE_TGL_REL]; + break; + case LV_BTNM_STYLE_BTN_TGL_PR: + style = ext->styles_btn[LV_BTN_STATE_TGL_PR]; + break; + case LV_BTNM_STYLE_BTN_INA: + style = ext->styles_btn[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} + +bool lv_btnm_get_recolor(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + return ext->recolor; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the button matrixs + * @param btnm pointer to a button matrix object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design_f(btnm, mask, mode); + /*Return false if the object is not covers the mask_p area*/ + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + ancestor_design_f(btnm, mask, mode); + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + lv_style_t * bg_style = lv_obj_get_style(btnm); + lv_style_t * btn_style; + lv_opa_t opa_scale = lv_obj_get_opa_scale(btnm); + + lv_area_t area_btnm; + lv_obj_get_coords(btnm, &area_btnm); + + lv_area_t area_tmp; + lv_coord_t btn_w; + lv_coord_t btn_h; + + uint16_t btn_i = 0; + uint16_t txt_i = 0; + lv_style_t style_tmp; + lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE; + + if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR; + + for(btn_i = 0; btn_i < ext->btn_cnt; btn_i ++, txt_i ++) { + /*Search the next valid text in the map*/ + while(strcmp(ext->map_p[txt_i], "\n") == 0) { + txt_i ++; + } + + /*Skip hidden buttons*/ + if(button_is_hidden(ext->map_p[txt_i])) continue; + + lv_area_copy(&area_tmp, &ext->button_areas[btn_i]); + area_tmp.x1 += area_btnm.x1; + area_tmp.y1 += area_btnm.y1; + area_tmp.x2 += area_btnm.x1; + area_tmp.y2 += area_btnm.y1; + + btn_w = lv_area_get_width(&area_tmp); + btn_h = lv_area_get_height(&area_tmp); + + /*Load the style*/ + if(button_is_inactive(ext->map_p[txt_i])) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_INA); + else if(btn_i != ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL); + else if(btn_i == ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_PR); + else if(btn_i != ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_REL); + else if(btn_i == ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_PR); + else btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL); /*Not possible option, just to be sure*/ + + lv_style_copy(&style_tmp, btn_style); + + /*Remove borders on the edges if `LV_BORDER_INTERNAL`*/ + if(style_tmp.body.border.part & LV_BORDER_INTERNAL) { + if(area_tmp.y1 == btnm->coords.y1 + bg_style->body.padding.ver) { + style_tmp.body.border.part &= ~LV_BORDER_TOP; + } + if(area_tmp.y2 == btnm->coords.y2 - bg_style->body.padding.ver) { + style_tmp.body.border.part &= ~LV_BORDER_BOTTOM; + } + + if(txt_i == 0) { + style_tmp.body.border.part &= ~LV_BORDER_LEFT; + } + else if(strcmp(ext->map_p[txt_i - 1],"\n") == 0) { + style_tmp.body.border.part &= ~LV_BORDER_LEFT; + } + + if(ext->map_p[txt_i + 1][0] == '\0' || strcmp(ext->map_p[txt_i + 1], "\n") == 0) { + style_tmp.body.border.part &= ~LV_BORDER_RIGHT; + } + } + lv_draw_rect(&area_tmp, mask, &style_tmp, opa_scale); + + /*Calculate the size of the text*/ + if(btn_style->glass) btn_style = bg_style; + const lv_font_t * font = btn_style->text.font; + lv_point_t txt_size; + lv_txt_get_size(&txt_size, ext->map_p[txt_i], font, + btn_style->text.letter_space, btn_style->text.line_space, + lv_area_get_width(&area_btnm), txt_flag); + + area_tmp.x1 += (btn_w - txt_size.x) / 2; + area_tmp.y1 += (btn_h - txt_size.y) / 2; + area_tmp.x2 = area_tmp.x1 + txt_size.x; + area_tmp.y2 = area_tmp.y1 + txt_size.y; + + lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL); + } + } + return true; +} + +/** + * Signal function of the button matrix + * @param btnm pointer to a button matrix object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(btnm, sign, param); + if(res != LV_RES_OK) return res; + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + lv_area_t btnm_area; + lv_area_t btn_area; + lv_point_t p; + if(sign == LV_SIGNAL_CLEANUP) { + lv_mem_free(ext->button_areas); + } else if(sign == LV_SIGNAL_STYLE_CHG || sign == LV_SIGNAL_CORD_CHG) { + lv_btnm_set_map(btnm, ext->map_p); + } else if(sign == LV_SIGNAL_PRESSING) { + uint16_t btn_pr; + /*Search the pressed area*/ + lv_indev_get_point(param, &p); + btn_pr = get_button_from_point(btnm, &p); + /*Invalidate to old and the new areas*/; + lv_obj_get_coords(btnm, &btnm_area); + if(btn_pr != ext->btn_id_pr) { + lv_indev_reset_lpr(param); + if(ext->btn_id_pr != LV_BTNM_PR_NONE) { + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + } + if(btn_pr != LV_BTNM_PR_NONE) { + lv_area_copy(&btn_area, &ext->button_areas[btn_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + } + } + + ext->btn_id_pr = btn_pr; + } + + else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + if(ext->action && ext->btn_id_pr != LV_BTNM_PR_NONE) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(txt_i != LV_BTNM_PR_NONE) { + if(button_is_repeat_disabled(ext->map_p[txt_i]) == false && + button_is_inactive(ext->map_p[txt_i]) == false) { + res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + } + } + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(ext->btn_id_pr != LV_BTNM_PR_NONE) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(button_is_inactive(ext->map_p[txt_i]) == false && txt_i != LV_BTNM_PR_NONE) { /*Ignore the inactive buttons anf click between the buttons*/ + if(ext->action) res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + if(res == LV_RES_OK) { + + /*Invalidate to old pressed area*/; + lv_obj_get_coords(btnm, &btnm_area); + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + + if(ext->toggle != 0) { + /*Invalidate to old toggled area*/; + lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_tgl]); + btn_area.x1 += btnm_area.x1; + btn_area.y1 += btnm_area.y1; + btn_area.x2 += btnm_area.x1; + btn_area.y2 += btnm_area.y1; + lv_inv_area(&btn_area); + ext->btn_id_tgl = ext->btn_id_pr; + + } + + #if USE_LV_GROUP + /*Leave the clicked button when releases if this not the focused object in a group*/ + lv_group_t * g = lv_obj_get_group(btnm); + if(lv_group_get_focused(g) != btnm) { + ext->btn_id_pr = LV_BTNM_PR_NONE; + } + #else + ext->btn_id_pr = LV_BTNM_PR_NONE; + #endif + + } + } + } + } else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_DEFOCUS) { + ext->btn_id_pr = LV_BTNM_PR_NONE; + lv_obj_invalidate(btnm); + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_indev_t * indev = lv_indev_get_act(); + lv_hal_indev_type_t indev_type = lv_indev_get_type(indev); + if(indev_type == LV_INDEV_TYPE_POINTER) { + /*Select the clicked button*/ + lv_point_t p1; + lv_indev_get_point(indev, &p1); + uint16_t btn_i = get_button_from_point(btnm, &p1); + ext->btn_id_pr = btn_i; + } else if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigation mode don't select any button but in edit mode select the fist*/ + if(lv_group_get_editing(lv_obj_get_group(btnm))) ext->btn_id_pr = 0; + else ext->btn_id_pr = LV_BTNM_PR_NONE; + } else { + ext->btn_id_pr = 0; + } +#else + ext->btn_id_pr = 0; +#endif + lv_obj_invalidate(btnm); + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT) { + if(ext->btn_id_pr == LV_BTNM_PR_NONE) ext->btn_id_pr = 0; + else ext->btn_id_pr++; + if(ext->btn_id_pr >= ext->btn_cnt - 1) ext->btn_id_pr = ext->btn_cnt - 1; + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_LEFT) { + if(ext->btn_id_pr == LV_BTNM_PR_NONE) ext->btn_id_pr = 0; + if(ext->btn_id_pr > 0) ext->btn_id_pr--; + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_DOWN) { + lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + /*Find the area below the the current*/ + if(ext->btn_id_pr == LV_BTNM_PR_NONE) { + ext->btn_id_pr = 0; + } else { + uint16_t area_below; + lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1); + + for(area_below = ext->btn_id_pr; area_below < ext->btn_cnt; area_below ++) { + if(ext->button_areas[area_below].y1 > ext->button_areas[ext->btn_id_pr].y1 && + pr_center >= ext->button_areas[area_below].x1 && + pr_center <= ext->button_areas[area_below].x2 + style->body.padding.hor) { + break; + } + } + + if(area_below < ext->btn_cnt) ext->btn_id_pr = area_below; + } + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_UP) { + lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG); + /*Find the area below the the current*/ + if(ext->btn_id_pr == LV_BTNM_PR_NONE) { + ext->btn_id_pr = 0; + } else { + int16_t area_above; + lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1); + + for(area_above = ext->btn_id_pr; area_above >= 0; area_above --) { + if(ext->button_areas[area_above].y1 < ext->button_areas[ext->btn_id_pr].y1 && + pr_center >= ext->button_areas[area_above].x1 - style->body.padding.hor && + pr_center <= ext->button_areas[area_above].x2) { + break; + } + } + if(area_above >= 0) ext->btn_id_pr = area_above; + + } + lv_obj_invalidate(btnm); + } else if(c == LV_GROUP_KEY_ENTER) { + if(ext->action != NULL) { + uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr); + if(txt_i != LV_BTNM_PR_NONE) { + res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i])); + } + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_btnm"; + } + + + return res; +} + +/** + * Create the required number of buttons according to a map + * @param btnm pointer to button matrix object + * @param map_p pointer to a string array + */ +static void allocate_btn_areas(lv_obj_t * btnm, const char ** map) +{ + /*Count the buttons in the map*/ + uint16_t btn_cnt = 0; + uint16_t i = 0; + while(strlen(map[i]) != 0) { + if(strcmp(map[i], "\n") != 0) { /*Do not count line breaks*/ + btn_cnt ++; + } + i++; + } + + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + + if(ext->button_areas != NULL) { + lv_mem_free(ext->button_areas); + ext->button_areas = NULL; + } + + ext->button_areas = lv_mem_alloc(sizeof(lv_area_t) * btn_cnt); + lv_mem_assert(ext->button_areas); + if(ext->button_areas == NULL) btn_cnt = 0; + + ext->btn_cnt = btn_cnt; +} + +/** + * Get the width of a button in units. It comes from the first "letter". + * @param btn_str The descriptor string of a button. E.g. "apple" or "\004banana" + * @return the width of the button in units + */ +static uint8_t get_button_width(const char * btn_str) +{ + if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) { + return btn_str[0] & LV_BTNM_WIDTH_MASK; + } + + return 1; /*Default width is 1*/ +} + +static bool button_is_hidden(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_HIDE_MASK)) { + return true; + } + + return false; +} + +static bool button_is_repeat_disabled(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_REPEAT_DISABLE_MASK)) { + return true; + } + + return false; +} + +static bool button_is_inactive(const char * btn_str) +{ + /*If control byte presents and hidden bit is '1' then the button is hidden*/ + if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) && + (btn_str[0] & LV_BTNM_INACTIVE_MASK)) { + return true; + } + + return false; +} + + +const char * cut_ctrl_byte(const char * btn_str) +{ + /*Cut the control byte if present*/ + if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) return &btn_str[1]; + else return btn_str; +} + +/** + * Gives the button id of a button under a given point + * @param btnm pointer to a button matrix object + * @param p a point with absolute coordinates + * @return the id of the button or LV_BTNM_PR_NONE. + */ +static uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p) +{ + lv_area_t btnm_cords; + lv_area_t btn_area; + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + uint16_t i; + lv_obj_get_coords(btnm, &btnm_cords); + + for(i = 0; i < ext->btn_cnt; i++) { + lv_area_copy(&btn_area, &ext->button_areas[i]); + btn_area.x1 += btnm_cords.x1; + btn_area.y1 += btnm_cords.y1; + btn_area.x2 += btnm_cords.x1; + btn_area.y2 += btnm_cords.y1; + if(lv_area_is_point_on(&btn_area, p) != false) { + break; + } + } + + if(i == ext->btn_cnt) i = LV_BTNM_PR_NONE; + + return i; +} + +/** + * Get the text of a button + * @param btnm pointer to a button matrix object + * @param btn_id button id + * @return text id in ext->map_p or LV_BTNM_PR_NONE if 'btn_id' was invalid + */ +static uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + if(btn_id > ext->btn_cnt) return LV_BTNM_PR_NONE; + + uint16_t txt_i = 0; + uint16_t btn_i = 0; + + /* Search the text of ext->btn_pr the buttons text in the map + * Skip "\n"-s*/ + while(btn_i != btn_id) { + btn_i ++; + txt_i ++; + if(strcmp(ext->map_p[txt_i], "\n") == 0) txt_i ++; + } + + if(btn_i == ext->btn_cnt) return LV_BTNM_PR_NONE; + + return txt_i; +} + + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.h new file mode 100644 index 0000000..de334b7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_btnm.h @@ -0,0 +1,197 @@ +/** + * @file lv_btnm.h + * + */ + + +#ifndef LV_BTNM_H +#define LV_BTNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_BTNM != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_label.h" +#include "lv_btn.h" + +/********************* + * DEFINES + *********************/ + +/*Control byte*/ +#define LV_BTNM_CTRL_CODE 0x80 /*The control byte has to begin (if present) with 0b10xxxxxx*/ +#define LV_BTNM_CTRL_MASK 0xC0 +#define LV_BTNM_WIDTH_MASK 0x07 +#define LV_BTNM_HIDE_MASK 0x08 +#define LV_BTNM_REPEAT_DISABLE_MASK 0x10 +#define LV_BTNM_INACTIVE_MASK 0x20 + + +#define LV_BTNM_PR_NONE 0xFFFF +/********************** + * TYPEDEFS + **********************/ + +/* Type of callback function which is called when a button is released or long pressed on the button matrix + * Parameters: button matrix, text of the released button + * return LV_ACTION_RES_INV if the button matrix is deleted else LV_ACTION_RES_OK*/ +typedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt); + +/*Data of button matrix*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + const char ** map_p; /*Pointer to the current map*/ + lv_area_t *button_areas; /*Array of areas of buttons*/ + lv_btnm_action_t action; /*A function to call when a button is releases*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t btn_id_pr; /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/ + uint16_t btn_id_tgl; /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */ + uint8_t toggle :1; /*Enable toggling*/ + uint8_t recolor :1; /*Enable button recoloring*/ +} lv_btnm_ext_t; + +enum { + LV_BTNM_STYLE_BG, + LV_BTNM_STYLE_BTN_REL, + LV_BTNM_STYLE_BTN_PR, + LV_BTNM_STYLE_BTN_TGL_REL, + LV_BTNM_STYLE_BTN_TGL_PR, + LV_BTNM_STYLE_BTN_INA, +}; +typedef uint8_t lv_btnm_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) + * - bit 4: no repeat (on long press) + * - bit 3: hidden + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map); + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param action pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action); + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id); + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm); + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type); + +/** + * Find whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_btnm_get_recolor(const lv_obj_t * btnm); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BTNM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTNM_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.c new file mode 100644 index 0000000..50304c3 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.c @@ -0,0 +1,1038 @@ +/** + * @file lv_calendar.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_calendar.h" +#if USE_LV_CALENDAR != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_hal/lv_hal_indev.h" +#include "../lv_misc/lv_math.h" +#include "../lv_core/lv_indev.h" +#include "../lv_themes/lv_theme.h" +//#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +enum { + DAY_DRAW_PREV_MONTH, + DAY_DRAW_ACT_MONTH, + DAY_DRAW_NEXT_MONTH, +}; +typedef uint8_t day_draw_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param); +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point); +static lv_coord_t get_header_height(lv_obj_t * calendar); +static lv_coord_t get_day_names_height(lv_obj_t * calendar); +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask); +static void draw_days(lv_obj_t * calendar, const lv_area_t * mask); +static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day); +static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day); +static const char * get_day_name(lv_obj_t * calendar, uint8_t day); +static const char * get_month_name(lv_obj_t * calendar, int32_t month); +static uint8_t get_month_length(int32_t year, int32_t month); +static uint8_t is_leap_year(uint32_t year); + + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; +static const char * day_name[7] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; +static const char * month_name[12] = {"January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" +}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a calendar object + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("calendar create started"); + + /*Create the ancestor of calendar*/ + lv_obj_t * new_calendar = lv_obj_create(par, copy); + lv_mem_assert(new_calendar); + if(new_calendar == NULL) return NULL; + + /*Allocate the calendar type specific extended data*/ + lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(new_calendar, sizeof(lv_calendar_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_calendar); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_calendar); + + /*Initialize the allocated 'ext' */ + ext->today.year = 2018; + ext->today.month = 1; + ext->today.day = 1; + + ext->showed_date.year = 2018; + ext->showed_date.month = 1; + ext->showed_date.day = 1; + + ext->pressed_date.year = 0; + ext->pressed_date.month = 0; + ext->pressed_date.day = 0; + + ext->highlighted_dates = NULL; + ext->highlighted_dates_num = 0; + ext->day_names = NULL; + ext->month_names = NULL; + ext->actions[LV_CALENDAR_ACTION_PR] = NULL; + ext->actions[LV_CALENDAR_ACTION_CLICK] = NULL; + ext->actions[LV_CALENDAR_ACTION_LONG_PR] = NULL; + ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] = NULL; + ext->style_header = &lv_style_plain_color; + ext->style_header_pr = &lv_style_pretty_color; + ext->style_highlighted_days = &lv_style_plain_color; + ext->style_inactive_days = &lv_style_btn_ina; + ext->style_week_box = &lv_style_plain_color; + ext->style_today_box = &lv_style_pretty_color; + ext->style_day_names = &lv_style_pretty; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_calendar, lv_calendar_signal); + lv_obj_set_design_func(new_calendar, lv_calendar_design); + + /*Init the new calendar calendar*/ + if(copy == NULL) { + lv_obj_set_size(new_calendar, LV_DPI * 2, LV_DPI * 2); + lv_obj_set_style(new_calendar, &lv_style_pretty); + + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, th->calendar.bg); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, th->calendar.header); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, th->calendar.header_pr); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, th->calendar.day_names); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, th->calendar.week_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, th->calendar.today_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, th->calendar.highlighted_days); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, th->calendar.inactive_days); + } else { + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, &lv_style_pretty); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, ext->style_header); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, ext->style_header_pr); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, ext->style_day_names); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, ext->style_week_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, ext->style_today_box); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, ext->style_highlighted_days); + lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, ext->style_inactive_days); + + } + + } + /*Copy an existing calendar*/ + else { + lv_calendar_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->today.year = copy_ext->today.year; + ext->today.month = copy_ext->today.month; + ext->today.day = copy_ext->today.day; + + ext->showed_date.year = copy_ext->showed_date.year; + ext->showed_date.month = copy_ext->showed_date.month; + ext->showed_date.day = copy_ext->showed_date.day; + + ext->highlighted_dates = copy_ext->highlighted_dates; + ext->highlighted_dates_num = copy_ext->highlighted_dates_num; + ext->day_names = copy_ext->day_names; + + memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions)); + + ext->month_names = copy_ext->month_names; + ext->style_header = copy_ext->style_header; + ext->style_header_pr = copy_ext->style_header_pr; + ext->style_highlighted_days = copy_ext->style_highlighted_days; + ext->style_inactive_days = copy_ext->style_inactive_days; + ext->style_week_box = copy_ext->style_week_box; + ext->style_today_box = copy_ext->style_today_box; + ext->style_day_names = copy_ext->style_day_names; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_calendar); + } + + LV_LOG_INFO("calendar created"); + + return new_calendar; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action) +{ + if(type >= LV_CALENDAR_ACTION_NUM) return; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->actions[type] = action; +} + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->today.year = today->year; + ext->today.month = today->month; + ext->today.day = today->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->showed_date.year = showed->year; + ext->showed_date.month = showed->month; + ext->showed_date.day = showed->day; + + lv_obj_invalidate(calendar); +} + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->highlighted_dates = highlighted; + ext->highlighted_dates_num = date_num; + + lv_obj_invalidate(calendar); +} + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->day_names = day_names; + lv_obj_invalidate(calendar); +} + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->month_names = day_names; + lv_obj_invalidate(calendar); +} + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t * style) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + switch(type) { + case LV_CALENDAR_STYLE_BG: + lv_obj_set_style(calendar, style); + break; + case LV_CALENDAR_STYLE_DAY_NAMES: + ext->style_day_names = style; + break; + case LV_CALENDAR_STYLE_HEADER: + ext->style_header = style; + break; + case LV_CALENDAR_STYLE_HEADER_PR: + ext->style_header_pr = style; + break; + case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS: + ext->style_highlighted_days = style; + break; + case LV_CALENDAR_STYLE_INACTIVE_DAYS: + ext->style_inactive_days = style; + break; + case LV_CALENDAR_STYLE_TODAY_BOX: + ext->style_today_box = style; + break; + case LV_CALENDAR_STYLE_WEEK_BOX: + ext->style_week_box = style; + break; + } + + lv_obj_invalidate(calendar); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type) +{ + if(type >= LV_CALENDAR_ACTION_NUM) return NULL; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->actions[type]; +} + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->today; +} + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->showed_date; +} + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return &ext->pressed_date; +} + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates; +} + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->highlighted_dates_num; +} + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->day_names; +} + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + return ext->month_names; +} + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type) +{ + lv_style_t * style = NULL; + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + switch(type) { + case LV_CALENDAR_STYLE_BG: + style = lv_obj_get_style(calendar); + break; + case LV_CALENDAR_STYLE_HEADER: + style = ext->style_header; + break; + case LV_CALENDAR_STYLE_HEADER_PR: + style = ext->style_header_pr; + break; + case LV_CALENDAR_STYLE_DAY_NAMES: + style = ext->style_day_names; + break; + case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS: + style = ext->style_highlighted_days; + break; + case LV_CALENDAR_STYLE_INACTIVE_DAYS: + style = ext->style_inactive_days; + break; + case LV_CALENDAR_STYLE_WEEK_BOX: + style = ext->style_week_box; + break; + case LV_CALENDAR_STYLE_TODAY_BOX: + style = ext->style_today_box; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the calendars + * @param calendar pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + lv_draw_rect(&calendar->coords, mask, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG), opa_scale); + + draw_header(calendar, mask); + draw_day_names(calendar, mask); + draw_days(calendar, mask); + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the calendar + * @param calendar pointer to a calendar object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(calendar, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_PRESSED) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + /*Call the press action, 'param' is the caller indev_proc*/ + if(ext->actions[LV_CALENDAR_ACTION_PR]) { + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + + if(calculate_touched_day(calendar, &p)){ + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + res = ext->actions[LV_CALENDAR_ACTION_PR](calendar); + } + } + } else if(sign == LV_SIGNAL_PRESSING) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_area_t header_area; + lv_area_copy(&header_area, &calendar->coords); + header_area.y2 = header_area.y1 + get_header_height(calendar); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + + if(lv_area_is_point_on(&header_area, &p)) { + if(p.x < header_area.x1 + lv_area_get_width(&header_area) / 2) { + if(ext->btn_pressing != -1) lv_obj_invalidate(calendar); + ext->btn_pressing = -1; + } else { + if(ext->btn_pressing != 1) lv_obj_invalidate(calendar); + ext->btn_pressing = 1; + } + + ext->pressed_date.year = 0; + } else if(calculate_touched_day(calendar, &p)) { + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + } else { + if(ext->btn_pressing != 0) lv_obj_invalidate(calendar); + ext->btn_pressing = 0; + ext->pressed_date.year = 0; + } + } else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + ext->pressed_date.year = 0; + ext->btn_pressing = 0; + lv_obj_invalidate(calendar); + + } else if(sign == LV_SIGNAL_RELEASED) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->btn_pressing < 0) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year --; + } else { + ext->showed_date.month --; + } + } else if(ext->btn_pressing > 0) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year ++; + } else { + ext->showed_date.month ++; + } + } + else if(ext->pressed_date.year != 0) + { + if(ext->actions[LV_CALENDAR_ACTION_CLICK]) { + res = ext->actions[LV_CALENDAR_ACTION_CLICK](calendar); + } + } + + ext->pressed_date.year = 0; + ext->btn_pressing = 0; + lv_obj_invalidate(calendar); + + + } else if(sign == LV_SIGNAL_LONG_PRESS) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->actions[LV_CALENDAR_ACTION_LONG_PR] && (ext->pressed_date.year != 0)) { + res = ext->actions[LV_CALENDAR_ACTION_LONG_PR](calendar); + } + } else if(sign == LV_SIGNAL_LONG_PRESS_REP) { + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] && (ext->pressed_date.year != 0)) { + res = ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT](calendar); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + uint8_t c = *((uint8_t *) param); + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + if(ext->showed_date.month >= 12) { + ext->showed_date.month = 1; + ext->showed_date.year ++; + } else { + ext->showed_date.month ++; + } + lv_obj_invalidate(calendar); + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + if(ext->showed_date.month <= 1) { + ext->showed_date.month = 12; + ext->showed_date.year --; + } else { + ext->showed_date.month --; + } + lv_obj_invalidate(calendar); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set date*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_calendar"; + } + + return res; +} + +/** + * It will check if the days part of calendar is touched + * and if it is, it will calculate the day and put it in pressed_date of calendar object. + * @param calendar pointer to a calendar object + * @param pointer to a point + * @return true: days part of calendar is touched and its related date is put in pressed date + * false: the point is out of days part area. + */ +static bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point) +{ + lv_area_t days_area; + lv_area_copy(&days_area, &calendar->coords); + lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG); + days_area.x1 += style_bg->body.padding.hor; + days_area.x2 -= style_bg->body.padding.hor; + days_area.y1 = calendar->coords.y1 + get_header_height(calendar) + get_day_names_height(calendar) - style_bg->body.padding.ver; + + if(lv_area_is_point_on(&days_area, touched_point)) { + lv_coord_t w = (days_area.x2 - days_area.x1 + 1) / 7; + lv_coord_t h = (days_area.y2 - days_area.y1 + 1) / 6; + uint8_t x_pos = 0; + x_pos = (touched_point->x - days_area.x1) / w; + if(x_pos > 6) x_pos = 6; + uint8_t y_pos = 0; + y_pos = (touched_point->y - days_area.y1) / h; + if(y_pos > 5) y_pos = 5; + + uint8_t i_pos = 0; + i_pos = (y_pos * 7) + x_pos; + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(i_pos < get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) ) { + ext->pressed_date.year = ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 1 ? 12 : (ext->showed_date.month - 1); + ext->pressed_date.day = get_month_length(ext->pressed_date.year, ext->pressed_date.month) - + get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + 1 + i_pos; + } + else if(i_pos < (get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + + get_month_length(ext->showed_date.year, ext->showed_date.month))) { + ext->pressed_date.year = ext->showed_date.year; + ext->pressed_date.month = ext->showed_date.month; + ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + } + else if(i_pos < 42) { + ext->pressed_date.year = ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0); + ext->pressed_date.month = ext->showed_date.month == 12 ? 1 : (ext->showed_date.month + 1); + ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + - get_month_length(ext->showed_date.year, ext->showed_date.month); + } + return true; + }else { + return false; + } +} + +/** + * Get the height of a calendar's header based on it's style + * @param calendar point to a calendar + * @return the header's height + */ +static lv_coord_t get_header_height(lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + return lv_font_get_height(ext->style_header->text.font) + ext->style_header->body.padding.ver * 2; +} + +/** + * Get the height of a calendar's day_names based on it's style + * @param calendar point to a calendar + * @return the day_names's height + */ +static lv_coord_t get_day_names_height(lv_obj_t * calendar) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + return lv_font_get_height(ext->style_day_names->text.font) + ext->style_day_names->body.padding.ver * 2; +} + +/** + * Draw the calendar header with month name and arrows + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + + lv_area_t header_area; + header_area.x1 = calendar->coords.x1; + header_area.x2 = calendar->coords.x2; + header_area.y1 = calendar->coords.y1; + header_area.y2 = calendar->coords.y1 + get_header_height(calendar); + + lv_draw_rect(&header_area, mask, ext->style_header, opa_scale); + + /*Add the year + month name*/ + char txt_buf[64]; + lv_math_num_to_str(ext->showed_date.year, txt_buf); + txt_buf[4] = ' '; + txt_buf[5] = '\0'; + strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month)); + header_area.y1 += ext->style_header->body.padding.ver; + lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL); + + /*Add the left arrow*/ + lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header; + header_area.x1 += ext->style_header->body.padding.hor; + lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL); + + /*Add the right arrow*/ + arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header; + header_area.x1 = header_area.x2 - ext->style_header->body.padding.hor - + lv_txt_get_width(SYMBOL_RIGHT, strlen(SYMBOL_RIGHT), arrow_style->text.font, + arrow_style->text.line_space, LV_TXT_FLAG_NONE); + lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL); + +} + +/** + * Draw the day's name below the header + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + + lv_coord_t hpad = ext->style_day_names->body.padding.hor; + lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad; + lv_coord_t box_w = w / 7; + lv_area_t label_area; + label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + ext->style_day_names->body.padding.ver; + label_area.y2 = label_area.y1 + lv_font_get_height(ext->style_day_names->text.font); + uint32_t i; + for(i = 0; i < 7; i++) { + label_area.x1 = calendar->coords.x1 + (w * i) / 7 + hpad; + label_area.x2 = label_area.x1 + box_w; + lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER, NULL); + } + +} + +/** + * Draw the date numbers in a matrix + * @param calendar point to a calendar + * @param mask a mask for drawing + */ +static void draw_days(lv_obj_t * calendar, const lv_area_t * mask) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG); + lv_coord_t hpad = style_bg->body.padding.hor; + lv_area_t label_area; + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); + label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + + ext->style_day_names->body.padding.ver + lv_font_get_height(ext->style_day_names->text.font) + + ext->style_day_names->body.padding.ver; + label_area.y2 = label_area.y1 + lv_font_get_height(style_bg->text.font); + + lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad; + lv_coord_t h = calendar->coords.y2 - label_area.y1 - style_bg->body.padding.ver; + lv_coord_t box_w = w / 7; + lv_coord_t vert_space = (h - (6 * lv_font_get_height(style_bg->text.font))) / 5; + + uint32_t week; + uint8_t day_cnt; + uint8_t month_start_day = get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1); + day_draw_state_t draw_state; /*true: Not the prev. or next month is drawn*/ + lv_style_t * act_style; + + /*If starting with the first day of the week then the previous month is not visible*/ + if(month_start_day == 0) { + day_cnt = 1; + draw_state = DAY_DRAW_ACT_MONTH; + act_style = style_bg; + } else { + draw_state = DAY_DRAW_PREV_MONTH; + day_cnt = get_month_length(ext->showed_date.year, ext->showed_date.month - 1); /*Length of the previous month*/ + day_cnt -= month_start_day - 1; /*First visible number of the previous month*/ + act_style = ext->style_inactive_days; + } + + + bool month_of_today_shown = false; + if(ext->showed_date.year == ext->today.year && + ext->showed_date.month == ext->today.month) { + month_of_today_shown = true; + } + + char buf[3]; + bool in_week_box = false; + + /*Draw 6 weeks*/ + for(week = 0; week < 6; week++) { + + /*Draw the "week box"*/ + if(month_of_today_shown && + ((draw_state == DAY_DRAW_ACT_MONTH && ext->today.day >= day_cnt && ext->today.day < day_cnt + 7) || + (draw_state == DAY_DRAW_PREV_MONTH && ext->today.day <= 7 - month_start_day && week == 0))) { + lv_area_t week_box_area; + lv_area_copy(&week_box_area, &label_area); /*'label_area' is already set for this row*/ + week_box_area.x1 = calendar->coords.x1 + style_bg->body.padding.hor - ext->style_week_box->body.padding.hor; + week_box_area.x2 = calendar->coords.x2 - style_bg->body.padding.hor + ext->style_week_box->body.padding.hor; + + week_box_area.y1 -= ext->style_week_box->body.padding.ver; + week_box_area.y2 += ext->style_week_box->body.padding.ver; + lv_draw_rect(&week_box_area, mask, ext->style_week_box, opa_scale); + + in_week_box = true; + } else { + in_week_box = false; + } + + /*Draw the 7 days of a week*/ + uint32_t day; + for(day = 0; day < 7; day++) { + /*The previous month is over*/ + if(draw_state == DAY_DRAW_PREV_MONTH && day == month_start_day) { + draw_state = DAY_DRAW_ACT_MONTH; + day_cnt = 1; + act_style = style_bg; + } + /*The current month is over*/ + if(draw_state == DAY_DRAW_ACT_MONTH && + day_cnt > get_month_length(ext->showed_date.year, ext->showed_date.month)) { + draw_state = DAY_DRAW_NEXT_MONTH; + day_cnt = 1; + act_style = ext->style_inactive_days; + } + + label_area.x1 = calendar->coords.x1 + (w * day) / 7 + hpad; + label_area.x2 = label_area.x1 + box_w; + + /*Draw the "today box"*/ + if(draw_state == DAY_DRAW_ACT_MONTH && month_of_today_shown && ext->today.day == day_cnt) { + lv_area_t today_box_area; + lv_area_copy(&today_box_area, &label_area); + today_box_area.x1 = label_area.x1; + today_box_area.x2 = label_area.x2; + + today_box_area.y1 = label_area.y1 - ext->style_today_box->body.padding.ver; + today_box_area.y2 = label_area.y2 + ext->style_today_box->body.padding.ver; + lv_draw_rect(&today_box_area, mask, ext->style_today_box, opa_scale); + } + + /*Get the final style : highlighted/week box/today box/normal*/ + lv_style_t * final_style; + if(draw_state == DAY_DRAW_PREV_MONTH && + is_highlighted(calendar, ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0), + ext->showed_date.month == 1 ? 12 : ext->showed_date.month - 1, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(draw_state == DAY_DRAW_ACT_MONTH && + is_highlighted(calendar, ext->showed_date.year, + ext->showed_date.month, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(draw_state == DAY_DRAW_NEXT_MONTH && + is_highlighted(calendar, ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0), + ext->showed_date.month == 12 ? 1 : ext->showed_date.month + 1, + day_cnt)) { + final_style = ext->style_highlighted_days; + } else if(month_of_today_shown && day_cnt == ext->today.day && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_today_box; + else if(in_week_box && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_week_box; + else final_style = act_style; + + /*Write the day's number*/ + lv_math_num_to_str(day_cnt, buf); + lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL); + + /*Go to the next day*/ + day_cnt ++; + + } + + /*Got to the next weeks row*/ + label_area.y1 += vert_space + lv_font_get_height(style_bg->text.font); + label_area.y2 += vert_space + lv_font_get_height(style_bg->text.font); + } +} + +/** + * Check weather a date is highlighted or not + * @param calendar pointer to a calendar object + * @param year a year + * @param month a month [1..12] + * @param day a day [1..31] + * @return true: highlighted + */ +static bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day) +{ + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + if(ext->highlighted_dates == NULL || ext->highlighted_dates_num == 0) return false; + + uint32_t i; + for(i = 0; i < ext->highlighted_dates_num; i++) { + if(ext->highlighted_dates[i].year == year && + ext->highlighted_dates[i].month == month && + ext->highlighted_dates[i].day == day) { + return true; + } + } + + return false; +} + +/** + * Get the day name + * @param calendar pointer to a calendar object + * @param day a day in [0..6] + * @return + */ +static const char * get_day_name(lv_obj_t * calendar, uint8_t day) +{ + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->day_names) return ext->day_names[day]; + else return day_name[day]; +} + +/** + * Get the month name + * @param calendar pointer to a calendar object + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year + * @return + */ +static const char * get_month_name(lv_obj_t * calendar, int32_t month) +{ + month --; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) month = 12 + month; + + lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + if(ext->month_names) return ext->month_names[month]; + else return month_name[month]; +} + +/** + * Get the number of days in a month + * @param year a year + * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year + * @return [28..31] + */ +static uint8_t get_month_length(int32_t year, int32_t month) +{ + month --; /*Range of months id [1..12] but range of indexes is [0..11]*/ + if(month < 0) { + year--; /*Already in the previous year (won't be less then -12 to skip a whole year)*/ + month = 12 + month; /*`month` is negative, the result will be < 12*/ + } + if(month >= 12) { + year ++; + month -= 12; + } + + /*month == 1 is february*/ + return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2; + + +} + +/** + * Tells whether a year is leap year or not + * @param year a year + * @return 0: not leap year; 1: leap year + */ +static uint8_t is_leap_year(uint32_t year) +{ + return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1; +} + +/** + * Get the day of the week + * @param year a year + * @param month a month + * @param day a day + * @return [0..6] which means [Sun..Sat] + */ +static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day) +{ + uint32_t a = month < 3 ? 1 : 0; + uint32_t b = year - a; + + uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + + b + (b / 4) - (b / 100) + (b / 400)) % 7; + + return day_of_week; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.h new file mode 100644 index 0000000..e573ae5 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_calendar.h @@ -0,0 +1,246 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CALENDAR != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +enum +{ + LV_CALENDAR_ACTION_CLICK, + LV_CALENDAR_ACTION_PR, + LV_CALENDAR_ACTION_LONG_PR, + LV_CALENDAR_ACTION_LONG_PR_REPEAT, + LV_CALENDAR_ACTION_NUM, +}; +typedef uint8_t lv_calendar_action_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/ + uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + lv_action_t actions[LV_CALENDAR_ACTION_NUM]; + + /*Styles*/ + lv_style_t * style_header; + lv_style_t * style_header_pr; + lv_style_t * style_day_names; + lv_style_t * style_highlighted_days; + lv_style_t * style_inactive_days; + lv_style_t * style_week_box; + lv_style_t * style_today_box; +} lv_calendar_ext_t; + +/*Styles*/ +enum { + LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/ + LV_CALENDAR_STYLE_HEADER, + LV_CALENDAR_STYLE_HEADER_PR, + LV_CALENDAR_STYLE_DAY_NAMES, + LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, + LV_CALENDAR_STYLE_INACTIVE_DAYS, + LV_CALENDAR_STYLE_WEEK_BOX, + LV_CALENDAR_STYLE_TODAY_BOX, +}; +typedef uint8_t lv_calendar_style_t; + + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action); + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num); + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type); + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.c new file mode 100644 index 0000000..0c6d9dd --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.c @@ -0,0 +1,593 @@ +/** + * @file lv_canvas.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_canvas.h" +#if USE_LV_CANVAS != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("canvas create started"); + + /*Create the ancestor of canvas*/ + lv_obj_t * new_canvas = lv_img_create(par, copy); + lv_mem_assert(new_canvas); + if(new_canvas == NULL) return NULL; + + /*Allocate the canvas type specific extended data*/ + lv_canvas_ext_t * ext = lv_obj_allocate_ext_attr(new_canvas, sizeof(lv_canvas_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_canvas); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_canvas); + + /*Initialize the allocated 'ext' */ + ext->dsc.header.always_zero = 0; + ext->dsc.header.cf = LV_IMG_CF_TRUE_COLOR; + ext->dsc.header.h = 0; + ext->dsc.header.w = 0; + ext->dsc.data_size = 0; + ext->dsc.data = NULL; + + lv_img_set_src(new_canvas, &ext->dsc); + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_canvas, lv_canvas_signal); + + /*Init the new canvas canvas*/ + if(copy == NULL) { + + } + /*Copy an existing canvas*/ + else { + //lv_canvas_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_canvas); + } + + LV_LOG_INFO("canvas created"); + + return new_canvas; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + * + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + + ext->dsc.header.cf = cf; + ext->dsc.header.w = w; + ext->dsc.header.h = h; + ext->dsc.data = buf; + ext->dsc.data_size = (lv_img_color_format_get_px_size(cf) * w * h) / 8; + + lv_img_set_src(canvas, &ext->dsc); +} +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c) +{ + + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_set_px: x or y out of the canvas"); + return; + } + + uint8_t * buf_u8 = (uint8_t *) ext->dsc.data; + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR || + ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t); + + memcpy(&buf_u8[px], &c, sizeof(lv_color_t)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += 4 * 2; + uint8_t bit = x & 0x7; + x = x >> 3; + + uint32_t px = (ext->dsc.header.w >> 3) * y + x; + buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += 4 * 4; + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + uint32_t px = (ext->dsc.header.w >> 2) * y + x; + + buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += 4 * 16; + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + uint32_t px = (ext->dsc.header.w >> 1) * y + x; + + buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit)); + buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += 4 * 256; + uint32_t px = ext->dsc.header.w * y + x; + buf_u8[px] = c.full; + } +} + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_CANVAS_STYLE_MAIN: + lv_img_set_style(canvas, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y) +{ + lv_color_t p_color = LV_COLOR_BLACK; + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_get_px: x or y out of the canvas"); + return p_color; + } + + uint8_t * buf_u8 = (uint8_t *) ext->dsc.data; + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR || + ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t); + memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t)); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) { + buf_u8 += 4 * 2; + uint8_t bit = x & 0x7; + x = x >> 3; + + uint32_t px = (ext->dsc.header.w >> 3) * y + x; + p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) { + buf_u8 += 4 * 4; + uint8_t bit = (x & 0x3) * 2; + x = x >> 2; + + uint32_t px = (ext->dsc.header.w >> 2) * y + x; + p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) { + buf_u8 += 4 * 16; + uint8_t bit = (x & 0x1) * 4; + x = x >> 1; + + uint32_t px = (ext->dsc.header.w >> 1) * y + x; + p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit); + } + else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) { + buf_u8 += 4 * 256; + uint32_t px = ext->dsc.header.w * y + x; + p_color.full = buf_u8[px]; + } + return p_color; +} + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type) +{ + // lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + lv_style_t * style = NULL; + + switch(type) { + case LV_CANVAS_STYLE_MAIN: + style = lv_img_get_style(canvas); + break; + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_copy_buf: x or y out of the canvas"); + return; + } + + uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3; + uint32_t px = ext->dsc.header.w * y * px_size + x * px_size; + uint8_t * to_copy8 = (uint8_t *) to_copy; + lv_coord_t i; + for(i = 0; i < h; i++) { + memcpy((void*)&ext->dsc.data[px], to_copy8, w * px_size); + px += ext->dsc.header.w * px_size; + to_copy8 += w * px_size; + } +} + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y) +{ + lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas); + if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) { + LV_LOG_WARN("lv_canvas_mult_buf: x or y out of the canvas"); + return; + } + + if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { + LV_LOG_WARN("lv_canvas_mult_buf: LV_IMG_CF_TRUE_COLOR_ALPHA is not supported"); + return; + } + + uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3; + uint32_t px = ext->dsc.header.w * y * px_size + x * px_size; + lv_color_t * copy_buf_color = (lv_color_t *) to_copy; + lv_color_t * canvas_buf_color = (lv_color_t *) &ext->dsc.data[px]; + + lv_coord_t i; + lv_coord_t j; + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) { +#if LV_COLOR_DEPTH == 32 + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 8; + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 8; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 8; +#elif LV_COLOR_DEPTH == 16 + + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 5; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 5; +# if LV_COLOR_16_SWAP == 0 + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 6; +# else + uint8_t green_canvas = (canvas_buf_color[j].green_h << 3) + (canvas_buf_color[j].green_l); + uint8_t green_buf = (copy_buf_color[j].green_h << 3) + (copy_buf_color[j].green_l); + uint8_t green_res = (uint16_t)((uint16_t)green_canvas * green_buf) >> 6; + canvas_buf_color[j].green_h = (green_res >> 3) & 0x07; + canvas_buf_color[j].green_l = green_res & 0x07; +# endif /*LV_COLOR_16_SWAP*/ + +#elif LV_COLOR_DEPTH == 8 + canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 3; + canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 3; + canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 2; +#endif + } + copy_buf_color += w; + canvas_buf_color += ext->dsc.header.w; + } +} + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color) +{ + int x = radius; + int y = 0; + int err = 0; + + while (x >= y) + { + lv_canvas_set_px(canvas, x0 + x, y0 + y, color); + lv_canvas_set_px(canvas, x0 + y, y0 + x, color); + lv_canvas_set_px(canvas, x0 - y, y0 + x, color); + lv_canvas_set_px(canvas, x0 - x, y0 + y, color); + lv_canvas_set_px(canvas, x0 - x, y0 - y, color); + lv_canvas_set_px(canvas, x0 - y, y0 - x, color); + lv_canvas_set_px(canvas, x0 + y, y0 - x, color); + lv_canvas_set_px(canvas, x0 + x, y0 - y, color); + + if (err <= 0) + { + y += 1; + err += 2*y + 1; + } + + if (err > 0) + { + x -= 1; + err -= 2*x + 1; + } + } +} + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +/* + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color) +{ + lv_coord_t x0, y0, x1, y1; + + x0 = point1.x; + y0 = point1.y; + x1 = point2.x; + y1 = point2.y; + + int dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; + + for(;;){ + lv_canvas_set_px(canvas, x0, y0, color); + + if (x0==x1 && y0==y1) break; + e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color) +{ + lv_canvas_draw_polygon(canvas, points, 3, color); +} + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color) +{ + lv_canvas_draw_polygon(canvas, points, 4, color); +} + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color) +{ + uint8_t i; + + for(i=0; i < (size - 1); i++) { + lv_canvas_draw_line(canvas, points[i], points[i + 1], color); + } + + lv_canvas_draw_line(canvas, points[size - 1], points[0], color); +} + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color) +{ + uint32_t x = 0, y = 0; + uint8_t i; + + for(i=0; itype[i] == NULL) break; + } + buf->type[i] = "lv_canvas"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.h new file mode 100644 index 0000000..cd5827f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_canvas.h @@ -0,0 +1,229 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CANVAS != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of canvas*/ +typedef struct { + lv_img_ext_t img; /*Ext. of ancestor*/ + /*New data for this type */ + lv_img_dsc_t dsc; +} lv_canvas_ext_t; + + +/*Styles*/ +enum { + LV_CANVAS_STYLE_MAIN, +}; +typedef uint8_t lv_canvas_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y); + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color); + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color); + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color); + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color); +/** + * Boundary fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param boundary_color edge/boundary color of the area + * @param fill_color fill color of the area + */ +void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color); + +/** + * Flood fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param fill_color fill color of the area + * @param bg_color background color of the area + */ +void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CANVAS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.c new file mode 100644 index 0000000..6b0277e --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.c @@ -0,0 +1,347 @@ +/** + * @file lv_cb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cb.h" +#if USE_LV_CB != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_bg_design; +static lv_design_func_t ancestor_bullet_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + LV_LOG_TRACE("check box create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_cb = lv_btn_create(par, copy); + lv_mem_assert(new_cb); + if(new_cb == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cb); + if(ancestor_bg_design == NULL) ancestor_bg_design = lv_obj_get_design_func(new_cb); + + lv_cb_ext_t * ext = lv_obj_allocate_ext_attr(new_cb, sizeof(lv_cb_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->bullet = NULL; + ext->label = NULL; + + lv_obj_set_signal_func(new_cb, lv_cb_signal); + lv_obj_set_design_func(new_cb, lv_cb_design); + + /*Init the new checkbox object*/ + if(copy == NULL) { + ext->bullet = lv_btn_create(new_cb, NULL); + if(ancestor_bullet_design == NULL) ancestor_bullet_design = lv_obj_get_design_func(ext->bullet); + lv_obj_set_click(ext->bullet, false); + + ext->label = lv_label_create(new_cb, NULL); + + lv_cb_set_text(new_cb, "Check box"); + lv_btn_set_layout(new_cb, LV_LAYOUT_ROW_M); + lv_btn_set_fit(new_cb, true, true); + lv_btn_set_toggle(new_cb, true); + lv_obj_set_protect(new_cb, LV_PROTECT_PRESS_LOST); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_cb_set_style(new_cb, LV_CB_STYLE_BG, th->cb.bg); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, th->cb.box.rel); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_PR, th->cb.box.pr); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_REL, th->cb.box.tgl_rel); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_PR, th->cb.box.tgl_pr); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_INA, th->cb.box.ina); + } else { + lv_cb_set_style(new_cb, LV_CB_STYLE_BG, &lv_style_transp); + lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, &lv_style_pretty); + } + } else { + lv_cb_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->bullet = lv_btn_create(new_cb, copy_ext->bullet); + ext->label = lv_label_create(new_cb, copy_ext->label); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_cb); + } + + lv_obj_set_design_func(ext->bullet, lv_bullet_design); + + + LV_LOG_INFO("check box created"); + + return new_cb; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + lv_label_set_text(ext->label, txt); +} + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t * style) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + switch(type) { + case LV_CB_STYLE_BG: + lv_btn_set_style(cb, LV_BTN_STYLE_REL, style); + lv_btn_set_style(cb, LV_BTN_STYLE_PR, style); + lv_btn_set_style(cb, LV_BTN_STYLE_TGL_REL, style); + lv_btn_set_style(cb, LV_BTN_STYLE_TGL_PR, style); + lv_btn_set_style(cb, LV_BTN_STYLE_INA, style); + break; + case LV_CB_STYLE_BOX_REL: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_REL, style); + break; + case LV_CB_STYLE_BOX_PR: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_PR, style); + break; + case LV_CB_STYLE_BOX_TGL_REL: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_REL, style); + break; + case LV_CB_STYLE_BOX_TGL_PR: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_PR, style); + break; + case LV_CB_STYLE_BOX_INA: + lv_btn_set_style(ext->bullet, LV_BTN_STYLE_INA, style); + break; + } +} + + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb) +{ + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + return lv_label_get_text(ext->label); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type) +{ + lv_style_t * style = NULL; + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + switch(type) { + case LV_CB_STYLE_BOX_REL: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_REL); + break; + case LV_CB_STYLE_BOX_PR: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_PR); + break; + case LV_CB_STYLE_BOX_TGL_REL: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_REL); + break; + case LV_CB_STYLE_BOX_TGL_PR: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_PR); + break; + case LV_CB_STYLE_BOX_INA: + style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the check boxes + * @param cb pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode) +{ + bool result = true; + + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + result = ancestor_bg_design(cb, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN || mode == LV_DESIGN_DRAW_POST) { + lv_cb_ext_t * cb_ext = lv_obj_get_ext_attr(cb); + lv_btn_ext_t * bullet_ext = lv_obj_get_ext_attr(cb_ext->bullet); + + /*Be sure the state of the bullet is the same as the parent button*/ + bullet_ext->state = cb_ext->bg_btn.state; + + result = ancestor_bg_design(cb, mask, mode); + + } else { + result = ancestor_bg_design(cb, mask, mode); + } + + return result; +} + +/** + * Handle the drawing related tasks of the check boxes + * @param bullet pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_bullet_design(bullet, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { +#if USE_LV_GROUP + /* If the check box is the active in a group and + * the background is not visible (transparent or empty) + * then activate the style of the bullet*/ + lv_style_t * style_ori = lv_obj_get_style(bullet); + lv_obj_t * bg = lv_obj_get_parent(bullet); + lv_style_t * style_page = lv_obj_get_style(bg); + lv_group_t * g = lv_obj_get_group(bg); + if(style_page->body.empty != 0 || style_page->body.opa == LV_OPA_TRANSP) { /*Background is visible?*/ + if(lv_group_get_focused(g) == bg) { + lv_style_t * style_mod; + style_mod = lv_group_mod_style(g, style_ori); + bullet->style_p = style_mod; /*Temporally change the style to the activated */ + } + } +#endif + ancestor_bullet_design(bullet, mask, mode); + +#if USE_LV_GROUP + bullet->style_p = style_ori; /*Revert the style*/ +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_bullet_design(bullet, mask, mode); + } + + return true; +} + + +/** + * Signal function of the check box + * @param cb pointer to a check box object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(cb, sign, param); + if(res != LV_RES_OK) return res; + + lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb); + + if(sign == LV_SIGNAL_STYLE_CHG) { + lv_style_t * label_style = lv_label_get_style(ext->label); + lv_obj_set_size(ext->bullet, lv_font_get_height(label_style->text.font), lv_font_get_height(label_style->text.font)); + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } else if(sign == LV_SIGNAL_PRESSED || + sign == LV_SIGNAL_RELEASED || + sign == LV_SIGNAL_PRESS_LOST) { + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN || + c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP || + c == LV_GROUP_KEY_ENTER) { + lv_btn_set_state(ext->bullet, lv_btn_get_state(cb)); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_cb"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.h new file mode 100644 index 0000000..b587733 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cb.h @@ -0,0 +1,174 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CB_H +#define LV_CB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of check box*/ +typedef struct +{ + lv_btn_ext_t bg_btn; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * bullet; /*Pointer to button*/ + lv_obj_t * label; /*Pointer to label*/ +} lv_cb_ext_t; + +enum { + LV_CB_STYLE_BG, + LV_CB_STYLE_BOX_REL, + LV_CB_STYLE_BOX_PR, + LV_CB_STYLE_BOX_TGL_REL, + LV_CB_STYLE_BOX_TGL_PR, + LV_CB_STYLE_BOX_INA, +}; +typedef uint8_t lv_cb_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt); + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +static inline void lv_cb_set_checked(lv_obj_t * cb, bool checked) +{ + lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_inactive(lv_obj_t * cb) +{ + lv_btn_set_state(cb, LV_BTN_STATE_INA); +} + +/** + * Set a function to call when the check box is clicked + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action) +{ + lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action); +} + + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb); + +/** + * Get the current state of the check box + * @param cb pointer to a check box object + * @return true: checked; false: not checked + */ +static inline bool lv_cb_is_checked(const lv_obj_t * cb) +{ + return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true; +} + +/** + * Get the action of a check box + * @param cb pointer to a button object + * @return pointer to the action function + */ +static inline lv_action_t lv_cb_get_action(const lv_obj_t * cb) +{ + return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CB_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.c new file mode 100644 index 0000000..0060c14 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.c @@ -0,0 +1,824 @@ +/** + * @file lv_chart.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_chart.h" +#if USE_LV_CHART != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_YMIN_DEF 0 +#define LV_CHART_YMAX_DEF 100 +#define LV_CHART_HDIV_DEF 3 +#define LV_CHART_VDIV_DEF 5 +#define LV_CHART_PNUM_DEF 10 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param); +static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("chart create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_chart = lv_obj_create(par, copy); + lv_mem_assert(new_chart); + if(new_chart == NULL) return NULL; + + /*Allocate the object type specific extended data*/ + lv_chart_ext_t * ext = lv_obj_allocate_ext_attr(new_chart, sizeof(lv_chart_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t)); + ext->series.num = 0; + ext->ymin = LV_CHART_YMIN_DEF; + ext->ymax = LV_CHART_YMAX_DEF; + ext->hdiv_cnt = LV_CHART_HDIV_DEF; + ext->vdiv_cnt = LV_CHART_VDIV_DEF; + ext->point_cnt = LV_CHART_PNUM_DEF; + ext->type = LV_CHART_TYPE_LINE; + ext->series.opa = LV_OPA_COVER; + ext->series.dark = LV_OPA_50; + ext->series.width = 2; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_chart); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_chart); + + lv_obj_set_signal_func(new_chart, lv_chart_signal); + lv_obj_set_design_func(new_chart, lv_chart_design); + + /*Init the new chart background object*/ + if(copy == NULL) { + lv_obj_set_size(new_chart, LV_HOR_RES / 3, LV_VER_RES / 3); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_chart_set_style(new_chart, th->chart); + } else { + lv_chart_set_style(new_chart, &lv_style_pretty); + } + + } else { + lv_chart_ext_t * ext_copy = lv_obj_get_ext_attr(copy); + ext->type = ext_copy->type; + ext->ymin = ext_copy->ymin; + ext->ymax = ext_copy->ymax; + ext->hdiv_cnt = ext_copy->hdiv_cnt; + ext->vdiv_cnt = ext_copy->vdiv_cnt; + ext->point_cnt = ext_copy->point_cnt; + ext->series.opa = ext_copy->series.opa; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_chart); + } + + LV_LOG_INFO("chart created"); + + + return new_chart; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_chart_series_t * ser = lv_ll_ins_head(&ext->series_ll); + lv_mem_assert(ser); + if(ser == NULL) return NULL; + + lv_coord_t def = LV_CHART_POINT_DEF; + + if(ser == NULL) return NULL; + + ser->color = color; + + ser->points = lv_mem_alloc(sizeof(lv_coord_t) * ext->point_cnt); + lv_mem_assert(ser->points); + if(ser->points == NULL) { + lv_ll_rem(&ext->series_ll, ser); + lv_mem_free(ser); + return NULL; + } + + ser->start_point = 0; + + uint16_t i; + lv_coord_t * p_tmp = ser->points; + for(i = 0; i < ext->point_cnt; i++) { + *p_tmp = def; + p_tmp++; + } + + ext->series.num++; + + return ser; +} + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie) +{ + if(chart == NULL || serie == NULL) + return; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext == NULL) return; + + uint32_t i; + for(i = 0; i < ext->point_cnt; i++) + { + serie->points[i] = LV_CHART_POINT_DEF; + } + + serie->start_point = 0; + +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->hdiv_cnt == hdiv && ext->vdiv_cnt == vdiv) return; + + ext->hdiv_cnt = hdiv; + ext->vdiv_cnt = vdiv; + + lv_obj_invalidate(chart); +} + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->ymin == ymin && ext->ymax == ymax) return; + + ext->ymin = ymin; + ext->ymax = ymax; + + lv_chart_refresh(chart); +} + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->type == type) return; + + ext->type = type; + + lv_chart_refresh(chart); +} + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->point_cnt == point_cnt) return; + + lv_chart_series_t * ser; + uint16_t point_cnt_old = ext->point_cnt; + uint16_t i; + lv_coord_t def = LV_CHART_POINT_DEF; + + if(point_cnt < 1) point_cnt = 1; + + LL_READ_BACK(ext->series_ll, ser) { + if(ser->start_point != 0) { + lv_coord_t * new_points = lv_mem_alloc(sizeof(lv_coord_t) * point_cnt); + lv_mem_assert(new_points); + if(new_points == NULL) return; + + if(point_cnt >= point_cnt_old) { + for(i = 0; i < point_cnt_old; i++) { + new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old]; /*Copy old contents to new array*/ + } + for(i = point_cnt_old; i < point_cnt; i++) { + new_points[i] = def; /*Fill up the rest with default value*/ + } + } else { + for(i = 0; i < point_cnt; i++) { + new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old]; /*Copy old contents to new array*/ + } + } + + /*Switch over pointer from old to new*/ + lv_mem_free(ser->points); + ser->points = new_points; + } else { + ser->points = lv_mem_realloc(ser->points, sizeof(lv_coord_t) * point_cnt); + lv_mem_assert(ser->points); + if(ser->points == NULL) return; + /*Initialize the new points*/ + if(point_cnt > point_cnt_old) { + for(i = point_cnt_old - 1; i < point_cnt; i++) { + ser->points[i] = def; + } + } + } + + ser->start_point = 0; + } + + ext->point_cnt = point_cnt; + + lv_chart_refresh(chart); +} + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.opa == opa) return; + + ext->series.opa = opa; + lv_obj_invalidate(chart); +} + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.width == width) return; + + ext->series.width = width; + lv_obj_invalidate(chart); +} +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + if(ext->series.dark == dark_eff) return; + + ext->series.dark = dark_eff; + lv_obj_invalidate(chart); +} + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + uint16_t i; + for(i = 0; i < ext->point_cnt; i++) { + ser->points[i] = y; + } + ser->start_point = 0; + lv_chart_refresh(chart); +} + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + memcpy(ser->points, y_array, ext->point_cnt * (sizeof(lv_coord_t))); + ser->start_point = 0; + lv_chart_refresh(chart); +} + +/** + * Shift all data left and set the rightmost data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the rightmost data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + ser->points[ser->start_point] = y; /*This was the place of the former left most value, after shifting it is the rightmost*/ + ser->start_point = (ser->start_point + 1) % ext->point_cnt; + + lv_chart_refresh(chart); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->type; +} + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->point_cnt; +} + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.opa; +} + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.width; +} + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + return ext->series.dark; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart) +{ + lv_obj_invalidate(chart); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the chart backgrounds + * @param chart pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return ancestor_design_f(chart, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the background*/ + lv_draw_rect(&chart->coords, mask, lv_obj_get_style(chart), lv_obj_get_opa_scale(chart)); + + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + lv_chart_draw_div(chart, mask); + + if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask); + if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask); + if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask); + if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask); + } + return true; +} + +/** + * Signal function of the chart background + * @param chart pointer to a chart background object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + */ +static lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(chart, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + lv_coord_t ** datal; + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + LL_READ(ext->series_ll, datal) { + lv_mem_free(*datal); + } + lv_ll_clear(&ext->series_ll); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_chart"; + } + + return res; +} + +/** + * Draw the division lines on chart background + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_style_t * style = lv_obj_get_style(chart); + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + + uint8_t div_i; + uint8_t div_i_end; + uint8_t div_i_start; + lv_point_t p1; + lv_point_t p2; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + + if(ext->hdiv_cnt != 0) { + /*Draw slide lines if no border*/ + if(style->body.border.width != 0) { + div_i_start = 1; + div_i_end = ext->hdiv_cnt; + } else { + div_i_start = 0; + div_i_end = ext->hdiv_cnt + 1; + } + + p1.x = 0 + x_ofs; + p2.x = w + x_ofs; + for(div_i = div_i_start; div_i <= div_i_end; div_i++) { + p1.y = (int32_t)((int32_t)h * div_i) / (ext->hdiv_cnt + 1); + p1.y += y_ofs; + if(div_i == div_i_start) p1.y += (style->line.width >> 1) + 1; /*The first line might not be visible*/ + if(div_i == div_i_end) p1.y -= (style->line.width >> 1) + 1; /*The last line might not be visible*/ + + p2.y = p1.y; + lv_draw_line(&p1, &p2, mask, style, opa_scale); + } + } + + if(ext->vdiv_cnt != 0) { + /*Draw slide lines if no border*/ + if(style->body.border.width != 0) { + div_i_start = 1; + div_i_end = ext->vdiv_cnt; + } else { + div_i_start = 0; + div_i_end = ext->vdiv_cnt + 1; + } + + p1.y = 0 + y_ofs; + p2.y = h + y_ofs; + for(div_i = div_i_start; div_i <= div_i_end; div_i ++) { + p1.x = (int32_t)((int32_t)w * div_i) / (ext->vdiv_cnt + 1); + p1.x += x_ofs; + if(div_i == div_i_start) p1.x += (style->line.width >> 1) + 1; /*The first line might not be visible*/ + if(div_i == div_i_end) p1.x -= (style->line.width >> 1) + 1; /*The last line might not be visible*/ + p2.x = p1.x; + lv_draw_line(&p1, &p2, mask, style, opa_scale); + } + } +} + +/** + * Draw the data lines as lines on a chart + * @param obj pointer to chart object + */ +static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_point_t p1; + lv_point_t p2; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_coord_t p_prev; + lv_coord_t p_act; + lv_chart_series_t * ser; + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + lv_style_t style; + lv_style_copy(&style, &lv_style_plain); + style.line.opa = ext->series.opa; + style.line.width = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style.line.color = ser->color; + + p1.x = 0 + x_ofs; + p2.x = 0 + x_ofs; + + p_prev = ser->start_point; + y_tmp = (int32_t)((int32_t) ser->points[p_prev] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + for(i = 1; i < ext->point_cnt; i ++) { + p1.x = p2.x; + p1.y = p2.y; + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + + p_act = (ser->start_point + i) % ext->point_cnt; + + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(ser->points[p_prev] != LV_CHART_POINT_DEF && ser->points[p_act] != LV_CHART_POINT_DEF) + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + + p_prev = p_act; + } + } +} + +/** + * Draw the data lines as points on a chart + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_area_t cir_a; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_coord_t p_act; + lv_chart_series_t * ser; + uint8_t series_cnt = 0; + lv_style_t style_point; + lv_style_copy(&style_point, &lv_style_plain); + + style_point.body.border.width = 0; + style_point.body.empty = 0; + style_point.body.radius = LV_RADIUS_CIRCLE; + style_point.body.opa = ext->series.opa; + style_point.body.radius = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style_point.body.main_color = ser->color; + style_point.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark); + + for(i = 0; i < ext->point_cnt; i ++) { + cir_a.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + cir_a.x2 = cir_a.x1 + style_point.body.radius; + cir_a.x1 -= style_point.body.radius; + p_act = (ser->start_point + i) % ext->point_cnt; + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + cir_a.y1 = h - y_tmp + y_ofs; + cir_a.y2 = cir_a.y1 + style_point.body.radius; + cir_a.y1 -= style_point.body.radius; + + if(ser->points[p_act] != LV_CHART_POINT_DEF) + lv_draw_rect(&cir_a, mask, &style_point, lv_obj_get_opa_scale(chart)); + } + series_cnt++; + } +} + +/** + * Draw the data lines as columns on a chart + * @param chart pointer to chart object + * @param mask mask, inherited from the design function + */ +static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_area_t col_a; + lv_area_t col_mask; + bool mask_ret; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + int32_t y_tmp; + lv_chart_series_t * ser; + lv_style_t rects; + lv_coord_t col_w = w / ((ext->series.num + 1) * ext->point_cnt); /* Suppose + 1 series as separator*/ + lv_coord_t x_ofs = col_w / 2; /*Shift with a half col.*/ + + lv_style_copy(&rects, &lv_style_plain); + rects.body.border.width = 0; + rects.body.empty = 0; + rects.body.radius = 0; + rects.body.opa = ext->series.opa; + + col_a.y2 = chart->coords.y2; + + lv_coord_t x_act; + + /*Go through all points*/ + for(i = 0; i < ext->point_cnt; i ++) { + x_act = (int32_t)((int32_t) w * i) / ext->point_cnt; + x_act += chart->coords.x1 + x_ofs; + + /*Draw the current point of all data line*/ + LL_READ_BACK(ext->series_ll, ser) { + rects.body.main_color = ser->color; + rects.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark); + col_a.x1 = x_act; + col_a.x2 = col_a.x1 + col_w; + x_act += col_w; + + lv_coord_t p_act = (ser->start_point + i) % ext->point_cnt; + y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + col_a.y1 = h - y_tmp + chart->coords.y1; + + mask_ret = lv_area_intersect(&col_mask, mask, &col_a); + if(mask_ret != false && ser->points[p_act] != LV_CHART_POINT_DEF) { + lv_draw_rect(&chart->coords, &col_mask, &rects, lv_obj_get_opa_scale(chart)); + } + } + } +} + +/** + * Draw the data lines as vertical lines on a chart if there is only 1px between point + * @param obj pointer to chart object + */ +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask) +{ + + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + lv_coord_t w = lv_obj_get_width(chart); + /*Vertical lines works only if the width == point count. Else use the normal line type*/ + if(ext->point_cnt != w) { + lv_chart_draw_lines(chart, mask); + return; + } + + uint16_t i; + lv_point_t p1; + lv_point_t p2; + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_chart_series_t * ser; + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + lv_style_t style; + lv_style_copy(&style, &lv_style_plain); + style.line.opa = ext->series.opa; + style.line.width = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style.line.color = ser->color; + + p1.x = 0 + x_ofs; + p2.x = 0 + x_ofs; + y_tmp = (int32_t)((int32_t) ser->points[0] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + p1.y = p2.y; + + for(i = 0; i < ext->point_cnt; i++) + { + + y_tmp = (int32_t)((int32_t) ser->points[i] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(p1.y == p2.y) + { + p2.x++; + } + + if(ser->points[i] != LV_CHART_POINT_DEF) { + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + } + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + p1.x = p2.x; + p1.y = p2.y; + } + } +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.h new file mode 100644 index 0000000..baea9d0 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_chart.h @@ -0,0 +1,262 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CHART != 0 + +#include "../lv_core/lv_obj.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_POINT_DEF (LV_COORD_MIN) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + lv_coord_t * points; + lv_color_t color; + uint16_t start_point; +} lv_chart_series_t; + +/*Data of chart */ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_dl_t)*/ + lv_coord_t ymin; /*y min value (used to scale the data)*/ + lv_coord_t ymax; /*y max value (used to scale the data)*/ + uint8_t hdiv_cnt; /*Number of horizontal division lines*/ + uint8_t vdiv_cnt; /*Number of vertical division lines*/ + uint16_t point_cnt; /*Point number in a data line*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ + struct { + lv_coord_t width; /*Line width or point radius*/ + uint8_t num; /*Number of data lines in dl_ll*/ + lv_opa_t opa; /*Opacity of data lines*/ + lv_opa_t dark; /*Dark level of the point/column bottoms*/ + } series; +} lv_chart_ext_t; + +/*Chart types*/ +enum +{ + LV_CHART_TYPE_LINE = 0x01, /*Connect the points with lines*/ + LV_CHART_TYPE_COLUMN = 0x02, /*Draw columns*/ + LV_CHART_TYPE_POINT = 0x04, /*Draw circles on the points*/ + LV_CHART_TYPE_VERTICAL_LINE = 0x08, /*Draw vertical lines on points (useful when chart width == point count)*/ +}; +typedef uint8_t lv_chart_type_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv); + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type); + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt); + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa); + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width); + +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff); + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array); + +/** + * Shift all data right and set the most right data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the most right data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the style of a chart + * @param chart pointer to a chart object + * @param style pointer to a style + */ +static inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style) +{ + lv_obj_set_style(chart, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart); + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart); + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart); + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart); + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart); + +/** + * Get the style of an chart object + * @param chart pointer to an chart object + * @return pointer to the chart's style + */ +static inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart) +{ + return lv_obj_get_style(chart); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CHART*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CHART_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.c new file mode 100644 index 0000000..bd84cd9 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.c @@ -0,0 +1,642 @@ +/** + * @file lv_cont.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_cont.h" +#if USE_LV_CONT != 0 + +#include +#include + +#include "../lv_draw/lv_draw.h" +#include "../lv_draw/lv_draw_vbasic.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param); +static void lv_cont_refr_layout(lv_obj_t * cont); +static void lv_cont_layout_col(lv_obj_t * cont); +static void lv_cont_layout_row(lv_obj_t * cont); +static void lv_cont_layout_center(lv_obj_t * cont); +static void lv_cont_layout_pretty(lv_obj_t * cont); +static void lv_cont_layout_grid(lv_obj_t * cont); +static void lv_cont_refr_autofit(lv_obj_t * cont); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy) +{ + + + LV_LOG_TRACE("container create started"); + + /*Create a basic object*/ + lv_obj_t * new_cont = lv_obj_create(par, copy); + lv_mem_assert(new_cont); + if(new_cont == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cont); + + lv_obj_allocate_ext_attr(new_cont, sizeof(lv_cont_ext_t)); + lv_cont_ext_t * ext = lv_obj_get_ext_attr(new_cont); + if(ext == NULL) return NULL; + + lv_mem_assert(ext); + ext->hor_fit = 0; + ext->ver_fit = 0; + ext->layout = LV_LAYOUT_OFF; + + lv_obj_set_signal_func(new_cont, lv_cont_signal); + + /*Init the new container*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_cont_set_style(new_cont, th->cont); + } else { + lv_cont_set_style(new_cont, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_cont_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->hor_fit = copy_ext->hor_fit; + ext->ver_fit = copy_ext->ver_fit; + ext->layout = copy_ext->layout; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_cont); + } + + LV_LOG_INFO("container created"); + + + return new_cont; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + if(ext->layout == layout) return; + + ext->layout = layout; + + /*Send a signal to refresh the layout*/ + cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL); +} + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en) +{ + lv_obj_invalidate(cont); + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + if(ext->hor_fit == hor_en && ext->ver_fit == ver_en) return; + + ext->hor_fit = hor_en == false ? 0 : 1; + ext->ver_fit = ver_en == false ? 0 : 1; + + /*Send a signal to refresh the layout*/ + cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->layout; +} + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->hor_fit == 0 ? false : true; +} + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + return ext->ver_fit == 0 ? false : true; +} + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont) +{ + lv_style_t * style = lv_cont_get_style(cont); + + return lv_obj_get_width(cont) - 2 * style->body.padding.hor; +} + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont) +{ + lv_style_t * style = lv_cont_get_style(cont); + + return lv_obj_get_height(cont) - 2 * style->body.padding.ver; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the container + * @param cont pointer to a container object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(cont, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_STYLE_CHG) { /*Recalculate the padding if the style changed*/ + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } else if(sign == LV_SIGNAL_CHILD_CHG) { + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_obj_get_width(cont) != lv_area_get_width(param) || + lv_obj_get_height(cont) != lv_area_get_height(param)) { + lv_cont_refr_layout(cont); + lv_cont_refr_autofit(cont); + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_cont"; + } + + return res; +} + + +/** + * Refresh the layout of a container + * @param cont pointer to an object which layout should be refreshed + */ +static void lv_cont_refr_layout(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + + /*'cont' has to be at least 1 child*/ + if(lv_obj_get_child(cont, NULL) == NULL) return; + + if(type == LV_LAYOUT_OFF) return; + + if(type == LV_LAYOUT_CENTER) { + lv_cont_layout_center(cont); + } else if(type == LV_LAYOUT_COL_L || type == LV_LAYOUT_COL_M || type == LV_LAYOUT_COL_R) { + lv_cont_layout_col(cont); + } else if(type == LV_LAYOUT_ROW_T || type == LV_LAYOUT_ROW_M || type == LV_LAYOUT_ROW_B) { + lv_cont_layout_row(cont); + } else if(type == LV_LAYOUT_PRETTY) { + lv_cont_layout_pretty(cont); + } else if(type == LV_LAYOUT_GRID) { + lv_cont_layout_grid(cont); + } +} + +/** + * Handle column type layouts + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_col(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + lv_obj_t * child; + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t hpad_corr; + + switch(type) { + case LV_LAYOUT_COL_L: + hpad_corr = style->body.padding.hor; + align = LV_ALIGN_IN_TOP_LEFT; + break; + case LV_LAYOUT_COL_M: + hpad_corr = 0; + align = LV_ALIGN_IN_TOP_MID; + break; + case LV_LAYOUT_COL_R: + hpad_corr = -style->body.padding.hor; + align = LV_ALIGN_IN_TOP_RIGHT; + break; + default: + hpad_corr = 0; + align = LV_ALIGN_IN_TOP_LEFT; + break; + } + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + /* Align the children */ + lv_coord_t last_cord = style->body.padding.ver; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, align, hpad_corr, last_cord); + last_cord += lv_obj_get_height(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle row type layouts + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_row(lv_obj_t * cont) +{ + lv_layout_t type = lv_cont_get_layout(cont); + lv_obj_t * child; + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t vpad_corr = style->body.padding.ver; + + switch(type) { + case LV_LAYOUT_ROW_T: + vpad_corr = style->body.padding.ver; + align = LV_ALIGN_IN_TOP_LEFT; + break; + case LV_LAYOUT_ROW_M: + vpad_corr = 0; + align = LV_ALIGN_IN_LEFT_MID; + break; + case LV_LAYOUT_ROW_B: + vpad_corr = -style->body.padding.ver; + align = LV_ALIGN_IN_BOTTOM_LEFT; + break; + default: + vpad_corr = 0; + align = LV_ALIGN_IN_TOP_LEFT; + break; + } + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t last_cord = style->body.padding.hor; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, align, last_cord, vpad_corr); + last_cord += lv_obj_get_width(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the center layout + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_center(lv_obj_t * cont) +{ + lv_obj_t * child; + lv_style_t * style = lv_obj_get_style(cont); + uint32_t obj_num = 0; + lv_coord_t h_tot = 0; + + LL_READ(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + h_tot += lv_obj_get_height(child) + style->body.padding.inner; + obj_num ++; + } + + if(obj_num == 0) return; + + h_tot -= style->body.padding.inner; + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t last_cord = - (h_tot / 2); + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + lv_obj_align(child, cont, LV_ALIGN_CENTER, 0, last_cord + lv_obj_get_height(child) / 2); + last_cord += lv_obj_get_height(child) + style->body.padding.inner; + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the pretty layout. Put as many object as possible in row + * then begin a new row + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_pretty(lv_obj_t * cont) +{ + lv_obj_t * child_rs; /* Row starter child */ + lv_obj_t * child_rc; /* Row closer child */ + lv_obj_t * child_tmp; /* Temporary child */ + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t w_obj = lv_obj_get_width(cont); + lv_coord_t act_y = style->body.padding.ver; + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + + child_rs = lv_ll_get_tail(&cont->child_ll); /*Set the row starter child*/ + if(child_rs == NULL) return; /*Return if no child*/ + + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + child_rc = child_rs; /*Initially the the row starter and closer is the same*/ + while(child_rs != NULL) { + lv_coord_t h_row = 0; + lv_coord_t w_row = style->body.padding.hor * 2; /*The width is at least the left+right hpad*/ + uint32_t obj_num = 0; + + /*Find the row closer object and collect some data*/ + do { + if(lv_obj_get_hidden(child_rc) == false && + lv_obj_is_protected(child_rc, LV_PROTECT_POS) == false) { + /*If this object is already not fit then break*/ + if(w_row + lv_obj_get_width(child_rc) > w_obj) { + /*Step back one child because the last already not fit, so the previous is the closer*/ + if(child_rc != NULL && obj_num != 0) { + child_rc = lv_ll_get_next(&cont->child_ll, child_rc); + } + break; + } + w_row += lv_obj_get_width(child_rc) + style->body.padding.inner; /*Add the object width + opad*/ + h_row = LV_MATH_MAX(h_row, lv_obj_get_height(child_rc)); /*Search the highest object*/ + obj_num ++; + if(lv_obj_is_protected(child_rc, LV_PROTECT_FOLLOW)) break; /*If can not be followed by an other object then break here*/ + + } + child_rc = lv_ll_get_prev(&cont->child_ll, child_rc); /*Load the next object*/ + if(obj_num == 0) child_rs = child_rc; /*If the first object was hidden (or too long) then set the next as first */ + } while(child_rc != NULL); + + /*If the object is too long then align it to the middle*/ + if(obj_num == 0) { + if(child_rc != NULL) { + lv_obj_align(child_rc, cont, LV_ALIGN_IN_TOP_MID, 0, act_y); + h_row = lv_obj_get_height(child_rc); /*Not set previously because of the early break*/ + } + } + /*If there is only one object in the row then align it to the middle*/ + else if(obj_num == 1) { + lv_obj_align(child_rs, cont, LV_ALIGN_IN_TOP_MID, 0, act_y); + } + /*If there are two object in the row then align them proportionally*/ + else if(obj_num == 2) { + lv_obj_t * obj1 = child_rs; + lv_obj_t * obj2 = lv_ll_get_prev(&cont->child_ll, child_rs); + w_row = lv_obj_get_width(obj1) + lv_obj_get_width(obj2); + lv_coord_t pad = (w_obj - w_row) / 3; + lv_obj_align(obj1, cont, LV_ALIGN_IN_TOP_LEFT, pad, act_y + (h_row - lv_obj_get_height(obj1)) / 2); + lv_obj_align(obj2, cont, LV_ALIGN_IN_TOP_RIGHT, -pad, act_y + (h_row - lv_obj_get_height(obj2)) / 2); + } + /* Align the children (from child_rs to child_rc)*/ + else { + w_row -= style->body.padding.inner * obj_num; + lv_coord_t new_opad = (w_obj - w_row) / (obj_num - 1); + lv_coord_t act_x = style->body.padding.hor; /*x init*/ + child_tmp = child_rs; + while(child_tmp != NULL) { + if(lv_obj_get_hidden(child_tmp) == false && + lv_obj_is_protected(child_tmp, LV_PROTECT_POS) == false) { + lv_obj_align(child_tmp, cont, LV_ALIGN_IN_TOP_LEFT, act_x, act_y + (h_row - lv_obj_get_height(child_tmp)) / 2); + act_x += lv_obj_get_width(child_tmp) + new_opad; + } + if(child_tmp == child_rc) break; + child_tmp = lv_ll_get_prev(&cont->child_ll, child_tmp); + } + + } + + if(child_rc == NULL) break; + act_y += style->body.padding.inner + h_row; /*y increment*/ + child_rs = lv_ll_get_prev(&cont->child_ll, child_rc); /*Go to the next object*/ + child_rc = child_rs; + } + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle the grid layout. Align same-sized objects in a grid + * @param cont pointer to an object which layout should be handled + */ +static void lv_cont_layout_grid(lv_obj_t * cont) +{ + lv_obj_t * child; + lv_style_t * style = lv_obj_get_style(cont); + lv_coord_t w_tot = lv_obj_get_width(cont); + lv_coord_t w_obj = lv_obj_get_width(lv_obj_get_child(cont, NULL)); + lv_coord_t h_obj = lv_obj_get_height(lv_obj_get_child(cont, NULL)); + uint16_t obj_row = (w_tot - (2 * style->body.padding.hor)) / (w_obj + style->body.padding.inner); /*Obj. num. in a row*/ + lv_coord_t x_ofs; + if(obj_row > 1) { + x_ofs = w_obj + (w_tot - (2 * style->body.padding.hor) - (obj_row * w_obj)) / (obj_row - 1); + } else { + x_ofs = w_tot / 2 - w_obj / 2; + } + lv_coord_t y_ofs = h_obj + style->body.padding.inner; + + /* Disable child change action because the children will be moved a lot + * an unnecessary child change signals could be sent*/ + lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); + + /* Align the children */ + lv_coord_t act_x = style->body.padding.hor; + lv_coord_t act_y = style->body.padding.ver; + uint16_t obj_cnt = 0; + LL_READ_BACK(cont->child_ll, child) { + if(lv_obj_get_hidden(child) != false || + lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; + + if(obj_row > 1) { + lv_obj_set_pos(child, act_x, act_y); + act_x += x_ofs; + } else { + lv_obj_set_pos(child, x_ofs, act_y); + } + obj_cnt ++; + + if(obj_cnt >= obj_row) { + obj_cnt = 0; + act_x = style->body.padding.hor; + act_y += y_ofs; + } + } + + lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG); +} + +/** + * Handle auto fit. Set the size of the object to involve all children. + * @param cont pointer to an object which size will be modified + */ +static void lv_cont_refr_autofit(lv_obj_t * cont) +{ + lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont); + + if(ext->hor_fit == 0 && + ext->ver_fit == 0) { + return; + } + + lv_area_t new_cords; + lv_area_t ori; + lv_style_t * style = lv_obj_get_style(cont); + lv_obj_t * i; + lv_coord_t hpad = style->body.padding.hor; + lv_coord_t vpad = style->body.padding.ver; + + /*Search the side coordinates of the children*/ + lv_obj_get_coords(cont, &ori); + lv_obj_get_coords(cont, &new_cords); + + new_cords.x1 = LV_COORD_MAX; + new_cords.y1 = LV_COORD_MAX; + new_cords.x2 = LV_COORD_MIN; + new_cords.y2 = LV_COORD_MIN; + + LL_READ(cont->child_ll, i) { + if(lv_obj_get_hidden(i) != false) continue; + new_cords.x1 = LV_MATH_MIN(new_cords.x1, i->coords.x1); + new_cords.y1 = LV_MATH_MIN(new_cords.y1, i->coords.y1); + new_cords.x2 = LV_MATH_MAX(new_cords.x2, i->coords.x2); + new_cords.y2 = LV_MATH_MAX(new_cords.y2, i->coords.y2); + } + + /*If the value is not the init value then the page has >=1 child.*/ + if(new_cords.x1 != LV_COORD_MAX) { + if(ext->hor_fit != 0) { + new_cords.x1 -= hpad; + new_cords.x2 += hpad; + } else { + new_cords.x1 = cont->coords.x1; + new_cords.x2 = cont->coords.x2; + } + if(ext->ver_fit != 0) { + new_cords.y1 -= vpad; + new_cords.y2 += vpad; + } else { + new_cords.y1 = cont->coords.y1; + new_cords.y2 = cont->coords.y2; + } + + /*Do nothing if the coordinates are not changed*/ + if(cont->coords.x1 != new_cords.x1 || + cont->coords.y1 != new_cords.y1 || + cont->coords.x2 != new_cords.x2 || + cont->coords.y2 != new_cords.y2) { + + lv_obj_invalidate(cont); + lv_area_copy(&cont->coords, &new_cords); + lv_obj_invalidate(cont); + + /*Notify the object about its new coordinates*/ + cont->signal_func(cont, LV_SIGNAL_CORD_CHG, &ori); + + /*Inform the parent about the new coordinates*/ + lv_obj_t * par = lv_obj_get_parent(cont); + par->signal_func(par, LV_SIGNAL_CHILD_CHG, cont); + } + } +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.h new file mode 100644 index 0000000..3259c77 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_cont.h @@ -0,0 +1,163 @@ +/** + * @file lv_cont.h + * + */ + +#ifndef LV_CONT_H +#define LV_CONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_CONT != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Layout options*/ +enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_CENTER, + LV_LAYOUT_COL_L, /*Column left align*/ + LV_LAYOUT_COL_M, /*Column middle align*/ + LV_LAYOUT_COL_R, /*Column right align*/ + LV_LAYOUT_ROW_T, /*Row top align*/ + LV_LAYOUT_ROW_M, /*Row middle align*/ + LV_LAYOUT_ROW_B, /*Row bottom align*/ + LV_LAYOUT_PRETTY, /*Put as many object as possible in row and begin a new row*/ + LV_LAYOUT_GRID, /*Align same-sized object into a grid*/ +}; +typedef uint8_t lv_layout_t; + +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ + /*New data for this type */ + uint8_t layout :4; /*A layout from 'lv_cont_layout_t' enum*/ + uint8_t hor_fit :1; /*1: Enable horizontal fit to involve all children*/ + uint8_t ver_fit :1; /*1: Enable horizontal fit to involve all children*/ +} lv_cont_ext_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en); + +/** + * Set the style of a container + * @param cont pointer to a container object + * @param style pointer to the new style + */ +static inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style) +{ + lv_obj_set_style(cont, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont); + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont); + + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont); + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont); + +/** + * Get the style of a container + * @param cont pointer to a container object + * @return pointer to the container's style + */ +static inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont) +{ + return lv_obj_get_style(cont); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CONT*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CONT_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.c new file mode 100644 index 0000000..c3776e8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_ddlist.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_ddlist.h" +#if USE_LV_DDLIST != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_indev.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_symbol_def.h" +#include "../lv_misc/lv_anim.h" +//#include + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 200 /*ms*/ +# endif +#else +# undef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 0 /*No animation*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param); +static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist); +static lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist); +static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en); +static void lv_ddlist_pos_current_option(lv_obj_t * ddlist); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("drop down list create started"); + + /*Create the ancestor drop down list*/ + lv_obj_t * new_ddlist = lv_page_create(par, copy); + lv_mem_assert(new_ddlist); + if(new_ddlist == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ddlist); + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ddlist)); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ddlist); + + /*Allocate the drop down list type specific extended data*/ + lv_ddlist_ext_t * ext = lv_obj_allocate_ext_attr(new_ddlist, sizeof(lv_ddlist_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->label = NULL; + ext->action = NULL; + ext->opened = 0; + ext->fix_height = 0; + ext->sel_opt_id = 0; + ext->sel_opt_id_ori = 0; + ext->option_cnt = 0; + ext->anim_time = LV_DDLIST_ANIM_TIME; + ext->sel_style = &lv_style_plain_color; + ext->draw_arrow = 0; /*Do not draw arrow by default*/ + ext->direction_up = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_ddlist, lv_ddlist_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_ddlist), lv_ddlist_scrl_signal); + lv_obj_set_design_func(new_ddlist, lv_ddlist_design); + + /*Init the new drop down list drop down list*/ + if(copy == NULL) { + lv_obj_t * scrl = lv_page_get_scrl(new_ddlist); + lv_obj_set_drag(scrl, false); + lv_page_set_scrl_fit(new_ddlist, true, true); + + ext->label = lv_label_create(new_ddlist, NULL); + lv_cont_set_fit(new_ddlist, true, false); + lv_page_set_rel_action(new_ddlist, lv_ddlist_release_action); + lv_page_set_pr_action(new_ddlist, lv_ddlist_press_action); + lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_DRAG); + lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE); + lv_page_set_style(new_ddlist, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + + lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3"); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, th->ddlist.bg); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, th->ddlist.bgo); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, th->ddlist.pr); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, th->ddlist.sel); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, th->ddlist.sb); + } else { + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, &lv_style_pretty); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color); + lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color); + } + } + /*Copy an existing drop down list*/ + else { + lv_ddlist_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->label = lv_label_create(new_ddlist, copy_ext->label); + lv_label_set_text(ext->label, lv_label_get_text(copy_ext->label)); + ext->sel_opt_id = copy_ext->sel_opt_id; + ext->fix_height = copy_ext->fix_height; + ext->action = copy_ext->action; + ext->option_cnt = copy_ext->option_cnt; + ext->sel_style = copy_ext->sel_style; + ext->anim_time = copy_ext->anim_time; + ext->draw_arrow = copy_ext->draw_arrow; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_ddlist); + } + + LV_LOG_INFO("drop down list created"); + + + return new_ddlist; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*Set the flag*/ + ext->draw_arrow = en; +} + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*Count the '\n'-s to determine the number of options*/ + ext->option_cnt = 0; + uint16_t i; + for(i = 0; options[i] != '\0'; i++) { + if(options[i] == '\n') ext->option_cnt++; + } + ext->option_cnt++; /*Last option in the at row*/ + + lv_label_set_text(ext->label, options); + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + if(ext->sel_opt_id == sel_opt) return; + + ext->sel_opt_id = sel_opt < ext->option_cnt ? sel_opt : ext->option_cnt - 1; + ext->sel_opt_id_ori = ext->sel_opt_id; + /*Move the list to show the current option*/ + if(ext->opened == 0) { + lv_ddlist_pos_current_option(ddlist); + } else { + lv_obj_invalidate(ddlist); + } +} + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->action = action; +} + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + if(ext->fix_height == h) return; + + ext->fix_height = h; + + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en) +{ + lv_cont_set_fit(ddlist, en, lv_cont_get_ver_fit(ddlist)); + lv_page_set_scrl_fit(ddlist, en, lv_page_get_scrl_fit_ver(ddlist)); + + lv_ddlist_refr_size(ddlist, false); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + ext->anim_time = anim_time; +} + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ddlist_set_style(lv_obj_t * ddlist, lv_ddlist_style_t type, lv_style_t * style) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + switch(type) { + case LV_DDLIST_STYLE_BG: + lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style); + break; + case LV_DDLIST_STYLE_BGO: + lv_page_set_style(ddlist, LV_PAGE_STYLE_BGO, style); + break; + case LV_DDLIST_STYLE_PR: + lv_page_set_style(ddlist, LV_PAGE_STYLE_PR, style); + break; + case LV_DDLIST_STYLE_SB: + lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style); + break; + case LV_DDLIST_STYLE_SEL: + ext->sel_style = style; + lv_obj_t * scrl = lv_page_get_scrl(ddlist); + lv_obj_refresh_ext_size(scrl); /*Because of the wider selected rectangle*/ + break; + } +} + +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + lv_label_set_align(ext->label, align); +} + +void lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + ext->direction_up = enable; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return ext->draw_arrow; +} + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return lv_label_get_text(ext->label); +} + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return ext->sel_opt_id; +} + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + uint16_t i; + uint16_t line = 0; + const char * opt_txt = lv_label_get_text(ext->label); + uint16_t txt_len = strlen(opt_txt); + + + for(i = 0; i < txt_len && line != ext->sel_opt_id; i++) { + if(opt_txt[i] == '\n') line ++; + } + + uint16_t c; + for(c = 0; opt_txt[i] != '\n' && i < txt_len; c++, i++) buf[c] = opt_txt[i]; + + buf[c] = '\0'; +} + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->action; +} + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->fix_height; +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + return ext->anim_time; +} + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t * ddlist, lv_ddlist_style_t type) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + switch(type) { + case LV_DDLIST_STYLE_BG: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_BG); + case LV_DDLIST_STYLE_BGO: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_BGO); + case LV_DDLIST_STYLE_PR: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_PR); + case LV_DDLIST_STYLE_SB: + return lv_page_get_style(ddlist, LV_PAGE_STYLE_SB); + case LV_DDLIST_STYLE_SEL: + return ext->sel_style; + default: + return NULL; + } + + /*To avoid warning*/ + return NULL; +} + +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + return lv_label_get_align(ext->label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->opened = 1; + lv_obj_set_drag(lv_page_get_scrl(ddlist), true); + lv_ddlist_refr_size(ddlist, anim_en); +} + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->opened = 0; + lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + lv_ddlist_refr_size(ddlist, anim_en); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Get the text alignment flag for a drop down list. + * @param ddlist drop down list + * @return text alignment flag + */ +static lv_txt_flag_t lv_ddlist_get_txt_flag(const lv_obj_t *ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*The label might be already deleted so just return with some value*/ + if(!ext->label) return LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(ext->label); + + switch(align) + { + default: + case LV_LABEL_ALIGN_LEFT: + return LV_TXT_FLAG_NONE; + case LV_LABEL_ALIGN_CENTER: + return LV_TXT_FLAG_CENTER; + case LV_LABEL_ALIGN_RIGHT: + return LV_TXT_FLAG_RIGHT; + } +} + +/** + * Handle the drawing related tasks of the drop down lists + * @param ddlist pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(ddlist, mask, mode); + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + ancestor_design(ddlist, mask, mode); + + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist); + /*If the list is opened draw a rectangle under the selected item*/ + if(ext->opened != 0) { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + /*Draw the selected*/ + lv_area_t rect_area; + rect_area.y1 = ext->label->coords.y1; + rect_area.y1 += ext->sel_opt_id * (font_h + style->text.line_space); + rect_area.y1 -= style->text.line_space / 2; + + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = ddlist->coords.x1; + rect_area.x2 = ddlist->coords.x2; + + lv_draw_rect(&rect_area, mask, ext->sel_style, opa_scale); + } + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + /*Redraw the text on the selected area with a different color*/ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist); + + /*Redraw only in opened state*/ + if(ext->opened) { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + lv_area_t area_sel; + area_sel.y1 = ext->label->coords.y1; + area_sel.y1 += ext->sel_opt_id * (font_h + style->text.line_space); + area_sel.y1 -= style->text.line_space / 2; + + area_sel.y2 = area_sel.y1 + font_h + style->text.line_space - 1; + area_sel.x1 = ddlist->coords.x1; + area_sel.x2 = ddlist->coords.x2; + lv_area_t mask_sel; + bool area_ok; + area_ok = lv_area_intersect(&mask_sel, mask, &area_sel); + if(area_ok) { + lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_SEL); + lv_style_t new_style; + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_txt_flag_t flag = lv_ddlist_get_txt_flag(ddlist); + lv_draw_label(&ext->label->coords, &mask_sel, &new_style, opa_scale, + lv_label_get_text(ext->label), flag, NULL); + } + } + + /*Add a down symbol in ddlist when closed*/ + else + { + /*Draw a arrow in ddlist if enabled*/ + if(ext->draw_arrow) + { + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + const lv_font_t * font = style->text.font; + lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + lv_coord_t font_h = lv_font_get_height(font); + lv_style_t new_style; + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_area_t area_arrow; + area_arrow.x2 = ddlist->coords.x2 - style->body.padding.hor; + if (!ext->direction_up) + area_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_DOWN, strlen(SYMBOL_DOWN), sel_style->text.font, 0, 0); + else + area_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_UP, strlen(SYMBOL_UP), sel_style->text.font, 0, 0); + + area_arrow.y1 = ddlist->coords.y1 + style->text.line_space; + area_arrow.y2 = area_arrow.y1 + font_h; + + + lv_area_t mask_arrow; + bool area_ok; + area_ok = lv_area_intersect(&mask_arrow, mask, &area_arrow); + if (area_ok) + { + if (!ext->direction_up) + lv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale, + SYMBOL_DOWN, LV_TXT_FLAG_NONE, NULL); /*Use a down arrow in ddlist, you can replace it with your custom symbol*/ + else + lv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale, + SYMBOL_UP, LV_TXT_FLAG_NONE, NULL); /*Use a down arrow in ddlist, you can replace it with your custom symbol*/ + } + } + } + /*Draw the scrollbar in the ancestor page design function*/ + ancestor_design(ddlist, mask, mode); + } + + return true; +} + +/** + * Signal function of the drop down list + * @param ddlist pointer to a drop down list object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param) +{ + lv_res_t res; + /* Include the ancient signal function */ + res = ancestor_signal(ddlist, sign, param); + if(res != LV_RES_OK) return res; + + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if(sign == LV_SIGNAL_STYLE_CHG) { + //! lv_ddlist_refr_size(ddlist, 0); // uncommented in OG + } else if(sign == LV_SIGNAL_CLEANUP) { + ext->label = NULL; + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(ddlist); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*Open the list if editing*/ + if(editing) { + ext->opened = true; + ext->sel_opt_id_ori = ext->sel_opt_id; + lv_ddlist_refr_size(ddlist, true); + } + /*Close the lift if navigating*/ + else { + ext->opened = false; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + + } + } else { + /*Open the list if closed*/ + if(!ext->opened) { + ext->opened = true; + ext->sel_opt_id_ori = ext->sel_opt_id; /*Save the current value. Used to revert this state if ENER wont't be pressed*/ + lv_ddlist_refr_size(ddlist, true); + } + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { + if(ext->opened) { + ext->opened = false; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + if(!ext->opened) { + ext->opened = 1; + lv_ddlist_refr_size(ddlist, true); + } + + if(ext->sel_opt_id + 1 < ext->option_cnt) { + ext->sel_opt_id ++; + lv_ddlist_pos_current_option(ddlist); + lv_obj_invalidate(ddlist); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + if(!ext->opened) { + ext->opened = 1; + lv_ddlist_refr_size(ddlist, true); + } + if(ext->sel_opt_id > 0) { + ext->sel_opt_id --; + lv_ddlist_pos_current_option(ddlist); + lv_obj_invalidate(ddlist); + } + } else if(c == LV_GROUP_KEY_ENTER) { + if(ext->opened) { + ext->sel_opt_id_ori = ext->sel_opt_id; + ext->opened = 0; + if(ext->action) ext->action(ddlist); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(ddlist); + bool editing = lv_group_get_editing(g); + if(editing) lv_group_set_editing(g, false); /*In edit mode go to navigate mode if an option is selected*/ +#endif + } else { + ext->opened = 1; + } + + lv_ddlist_refr_size(ddlist, true); + } else if(c == LV_GROUP_KEY_ESC) { + if(ext->opened) { + ext->opened = 0; + ext->sel_opt_id = ext->sel_opt_id_ori; + lv_ddlist_refr_size(ddlist, true); + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_ddlist"; + } + + return res; +} + +/** + * Signal function of the drop down list's scrollable part + * @param scrl pointer to a drop down list's scrollable part + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * ddlist = lv_obj_get_parent(scrl); + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /* Because of the wider selected rectangle ext. size + * In this way by dragging the scrollable part the wider rectangle area can be redrawn too*/ + lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG); + if(scrl->ext_size < style->body.padding.hor) scrl->ext_size = style->body.padding.hor; + } else if(sign == LV_SIGNAL_CLEANUP) { + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + ext->label = NULL; /*The label is already deleted*/ + } + + return res; +} + +/** + * Called when a drop down list is released to open it or set new option + * @param ddlist pointer to a drop down list object + * @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK + */ +static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if (!lv_obj_get_click(ddlist)) return LV_RES_OK; + + if(ext->opened == 0) { /*Open the list*/ + ext->opened = 1; + lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO)); + lv_obj_set_drag(lv_page_get_scrl(ddlist), true); + } else { + ext->opened = 0; + //lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR))); + lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + + /*Search the clicked option*/ + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t p; + lv_indev_get_point(indev, &p); + p.x -= ext->label->coords.x1; + p.y -= ext->label->coords.y1; + uint16_t letter_i; + letter_i = lv_label_get_letter_on(ext->label, &p); + + uint16_t new_opt = 0; + const char * txt = lv_label_get_text(ext->label); + uint32_t i = 0; + uint32_t line_cnt = 0; + uint32_t letter; + for(line_cnt = 0; line_cnt < letter_i; line_cnt++) { + letter = lv_txt_encoded_next(txt, &i); + if(letter == '\n') new_opt ++; + } + + ext->sel_opt_id = new_opt; + + if(ext->action != NULL) { + ext->action(ddlist); + } + } + lv_ddlist_refr_size(ddlist, true); + + return LV_RES_OK; +} + +static lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + if (!lv_obj_get_click(ddlist)) return LV_RES_OK; + + if (ext->opened == 0) + { /*Open the list*/ + lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR)); + } + else + { + //lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO)); + //lv_obj_set_drag(lv_page_get_scrl(ddlist), false); + + ///*Search the clicked option*/ + //lv_indev_t * indev = lv_indev_get_act(); + //lv_point_t p; + //lv_indev_get_point(indev, &p); + //p.x -= ext->label->coords.x1; + //p.y -= ext->label->coords.y1; + //uint16_t letter_i; + //letter_i = lv_label_get_letter_on(ext->label, &p); + + //uint16_t new_opt = 0; + //const char * txt = lv_label_get_text(ext->label); + //uint32_t i = 0; + //uint32_t line_cnt = 0; + //uint32_t letter; + //for (line_cnt = 0; line_cnt < letter_i; line_cnt++) + //{ + // letter = lv_txt_encoded_next(txt, &i); + // if (letter == '\n') new_opt++; + //} + + //ext->sel_opt_id = new_opt; + + //if (ext->action != NULL) + //{ + // ext->action(ddlist); + //} + } + + return LV_RES_OK; +} + +/** + * Refresh the size of drop down list according to its status (open or closed) + * @param ddlist pointer to a drop down list object + * @param anim_en Change the size (open/close) with or without animation (true/false) + */ +static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_style_t * style = lv_obj_get_style(ddlist); + lv_coord_t new_height, full_height; + bool current_state = 0; + + if(ext->opened) { /*Open the list*/ + if(ext->fix_height == 0) new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver; + else new_height = ext->fix_height; + current_state = 1; + + lv_page_set_sb_mode(ddlist, LV_SB_MODE_UNHIDE); + } else { /*Close the list*/ + const lv_font_t * font = style->text.font; + lv_style_t * label_style = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(font); + new_height = font_h + 2 * label_style->text.line_space; + //full_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver; + current_state = 0; + + lv_page_set_sb_mode(ddlist, LV_SB_MODE_HIDE); + } + + if(anim_en == 0 || ext->direction_up) { + lv_obj_set_height(ddlist, new_height); + if (ext->direction_up) + { + full_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) - lv_font_get_height(style->text.font); + if (current_state) + lv_obj_set_y(ddlist, lv_obj_get_y(ddlist) - full_height); + else + lv_obj_set_y(ddlist, lv_obj_get_y(ddlist) + full_height); + } + + lv_ddlist_pos_current_option(ddlist); +#if USE_LV_ANIMATION + lv_anim_del(ddlist, (lv_anim_fp_t)lv_obj_set_height); /*If an animation is in progress then it will overwrite this changes*/ + } else { + lv_anim_t a; + a.var = ddlist; + a.start = lv_obj_get_height(ddlist); + a.end = new_height; + a.fp = (lv_anim_fp_t)lv_obj_set_height; + a.path = lv_anim_path_linear; + a.end_cb = (lv_anim_cb_t)lv_ddlist_pos_current_option; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + lv_anim_create(&a); +#endif + } +} + +/** + * Set the position of list when it is closed to show the selected item + * @param ddlist pointer to a drop down list + */ +static void lv_ddlist_pos_current_option(lv_obj_t * ddlist) +{ + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_style_t * style = lv_obj_get_style(ddlist); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_style_t * label_style = lv_obj_get_style(ext->label); + lv_obj_t * scrl = lv_page_get_scrl(ddlist); + + lv_coord_t h = lv_obj_get_height(ddlist); + lv_coord_t line_y1 = ext->sel_opt_id * (font_h + label_style->text.line_space) + ext->label->coords.y1 - scrl->coords.y1; + + lv_obj_set_y(scrl, - line_y1 + (h - font_h) / 2); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.h new file mode 100644 index 0000000..db00080 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ddlist.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_ddlist.h + * + */ + +#ifndef LV_DDLIST_H +#define LV_DDLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_DDLIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_page.h" +#include "../lv_objx/lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of drop down list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *label; /*Label for the options*/ + lv_style_t * sel_style; /*Style of the selected option*/ + lv_action_t action; /*Pointer to function to call when an option is selected*/ + uint16_t option_cnt; /*Number of options*/ + uint16_t sel_opt_id; /*Index of the current option*/ + uint16_t sel_opt_id_ori; /*Store the original index on focus*/ + uint16_t anim_time; /*Open/Close animation time [ms]*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + uint8_t draw_arrow :1; /*1: Draw arrow*/ + uint8_t direction_up : 1; /*1: Open direction*/ + + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ +} lv_ddlist_ext_t; + +enum { + LV_DDLIST_STYLE_BG, + LV_DDLIST_STYLE_BGO, + LV_DDLIST_STYLE_PR, + LV_DDLIST_STYLE_SEL, + LV_DDLIST_STYLE_SB, +}; +typedef uint8_t lv_ddlist_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en); + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options); + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt); + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action); + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h); + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en); + +/** + * Set the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ddlist, mode); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time); + + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style); + +/** + * Set the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @param align alignment of labels + */ +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align); + +void lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist); + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist); + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist); + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf); + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist); + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist); + +/** + * Get the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist) +{ + return lv_page_get_sb_mode(ddlist); +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist); + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type); + +/** + * Get the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @return alignment of labels + */ +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en); + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_DDLIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DDLIST_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.c new file mode 100644 index 0000000..ad2ef8d --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.c @@ -0,0 +1,466 @@ +/** + * @file lv_gauge.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_gauge.h" +#if USE_LV_GAUGE != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_GAUGE_DEF_NEEDLE_COLOR LV_COLOR_RED +#define LV_GAUGE_DEF_LABEL_COUNT 6 +#define LV_GAUGE_DEF_LINE_COUNT 21 /*Should be: ((label_cnt - 1) * internal_lines) + 1*/ +#define LV_GAUGE_DEF_ANGLE 220 +#define LV_GAUGE_INTERPOLATE_SHIFT 5 /*Interpolate the needle drawing between to degrees*/ +#define LV_GAUGE_INTERPOLATE_MASK 0x1F + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param); +static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask); +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("gauge create started"); + + /*Create the ancestor gauge*/ + lv_obj_t * new_gauge = lv_lmeter_create(par, copy); + lv_mem_assert(new_gauge); + if(new_gauge == NULL) return NULL; + + /*Allocate the gauge type specific extended data*/ + lv_gauge_ext_t * ext = lv_obj_allocate_ext_attr(new_gauge, sizeof(lv_gauge_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->needle_count = 0; + ext->values = NULL; + ext->needle_colors = NULL; + ext->label_count = LV_GAUGE_DEF_LABEL_COUNT; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_gauge); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_gauge); + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_gauge, lv_gauge_signal); + lv_obj_set_design_func(new_gauge, lv_gauge_design); + + /*Init the new gauge gauge*/ + if(copy == NULL) { + lv_gauge_set_scale(new_gauge, LV_GAUGE_DEF_ANGLE, LV_GAUGE_DEF_LINE_COUNT, LV_GAUGE_DEF_LABEL_COUNT); + lv_gauge_set_needle_count(new_gauge, 1, NULL); + lv_gauge_set_critical_value(new_gauge, 80); + lv_obj_set_size(new_gauge, 2 * LV_DPI, 2 * LV_DPI); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_gauge_set_style(new_gauge, th->gauge); + } else { + lv_gauge_set_style(new_gauge, &lv_style_pretty_color); + } + } + /*Copy an existing gauge*/ + else { + lv_gauge_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_gauge_set_needle_count(new_gauge, copy_ext->needle_count, copy_ext->needle_colors); + + uint8_t i; + for(i = 0; i < ext->needle_count; i++) { + ext->values[i] = copy_ext->values[i]; + } + ext->label_count = copy_ext->label_count; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_gauge); + } + + LV_LOG_INFO("gauge created"); + + return new_gauge; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + if(ext->needle_count != needle_cnt) { + if(ext->values != NULL) { + lv_mem_free(ext->values); + ext->values = NULL; + } + + ext->values = lv_mem_realloc(ext->values, needle_cnt * sizeof(int16_t)); + lv_mem_assert(ext->values); + if(ext->values == NULL) return; + + int16_t min = lv_gauge_get_min_value(gauge); + uint8_t n; + for(n = ext->needle_count; n < needle_cnt; n++) { + ext->values[n] = min; + } + + ext->needle_count = needle_cnt; + } + + ext->needle_colors = colors; + lv_obj_invalidate(gauge); +} + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + if(needle_id >= ext->needle_count) return; + if(ext->values[needle_id] == value) return; + + + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + + if(value > max) value = max; + else if(value < min) value = min; + + ext->values[needle_id] = value; + + + lv_obj_invalidate(gauge); +} + + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt) +{ + /*TODO v6.0: change `line_cnt` to `subdiv_cnt`*/ + + lv_lmeter_set_scale(gauge, angle, line_cnt); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + ext->label_count = label_cnt; + lv_obj_invalidate(gauge); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + int16_t min = lv_gauge_get_min_value(gauge); + + if(needle >= ext->needle_count) return min; + + return ext->values[needle]; +} + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + return ext->needle_count; +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge) +{ + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + return ext->label_count; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the gauges + * @param gauge pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode) +{ + + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + /* Store the real pointer because of 'lv_group' + * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style + * and to the real object style. It is important because of style change tricks below*/ + lv_style_t * style_ori_p = gauge->style_p; + lv_style_t * style = lv_obj_get_style(gauge); + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + lv_gauge_draw_scale(gauge, mask); + + /*Draw the ancestor line meter with max value to show the rainbow like line colors*/ + uint16_t line_cnt_tmp = ext->lmeter.line_cnt; + ancestor_design(gauge, mask, mode); /*To draw lines*/ + + /*Temporally modify the line meter to draw thicker and longer lines where labels are*/ + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style); + ext->lmeter.line_cnt = ext->label_count; /*Only to labels*/ + style_tmp.line.width = style_tmp.line.width * 2; /*Ticker lines*/ + style_tmp.body.padding.hor = style_tmp.body.padding.hor * 2; /*Longer lines*/ + gauge->style_p = &style_tmp; + + ancestor_design(gauge, mask, mode); /*To draw lines*/ + + ext->lmeter.line_cnt = line_cnt_tmp; /*Restore the parameters*/ + gauge->style_p = style_ori_p; /*Restore the ORIGINAL style pointer*/ + + lv_gauge_draw_needle(gauge, mask); + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(gauge, mask, mode); + } + + return true; +} + +/** + * Signal function of the gauge + * @param gauge pointer to a gauge object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(gauge, sign, param); + if(res != LV_RES_OK) return res; + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + if(sign == LV_SIGNAL_CLEANUP) { + lv_mem_free(ext->values); + ext->values = NULL; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_gauge"; + } + + return res; +} + +/** + * Draw the scale on a gauge + * @param gauge pointer to gauge object + * @param mask mask of drawing + */ +static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask) +{ + char scale_txt[16]; + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + lv_style_t * style = lv_obj_get_style(gauge); + lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge); + lv_coord_t r = lv_obj_get_width(gauge) / 2 - (3 * style->body.padding.hor) - style->body.padding.inner; + lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1; + int16_t scale_angle = lv_lmeter_get_scale_angle(gauge); + uint16_t label_num = ext->label_count; + int16_t angle_ofs = 90 + (360 - scale_angle) / 2; + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + + uint8_t i; + for(i = 0; i < label_num; i++) { + /*Calculate the position a scale label*/ + int16_t angle = (i * scale_angle) / (label_num - 1) + angle_ofs; + + lv_coord_t y = (int32_t)((int32_t)lv_trigo_sin(angle) * r) / LV_TRIGO_SIN_MAX; + y += y_ofs; + + lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX; + x += x_ofs; + + int16_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1); + scale_act += min; + lv_math_num_to_str(scale_act, scale_txt); + + lv_area_t label_cord; + lv_point_t label_size; + lv_txt_get_size(&label_size, scale_txt, style->text.font, + style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + + /*Draw the label*/ + label_cord.x1 = x - label_size.x / 2; + label_cord.y1 = y - label_size.y / 2; + label_cord.x2 = label_cord.x1 + label_size.x; + label_cord.y2 = label_cord.y1 + label_size.y; + + lv_draw_label(&label_cord, mask, style, opa_scale, scale_txt, LV_TXT_FLAG_NONE, NULL); + } +} +/** + * Draw the needles of a gauge + * @param gauge pointer to gauge object + * @param mask mask of drawing + */ +static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask) +{ + lv_style_t style_needle; + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + lv_style_t * style = lv_gauge_get_style(gauge); + lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge); + + lv_coord_t r = lv_obj_get_width(gauge) / 2 - style->body.padding.hor; + lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1; + uint16_t angle = lv_lmeter_get_scale_angle(gauge); + int16_t angle_ofs = 90 + (360 - angle) / 2; + int16_t min = lv_gauge_get_min_value(gauge); + int16_t max = lv_gauge_get_max_value(gauge); + lv_point_t p_mid; + lv_point_t p_end; + lv_point_t p_end_low; + lv_point_t p_end_high; + uint8_t i; + + lv_style_copy(&style_needle, style); + + p_mid.x = x_ofs; + p_mid.y = y_ofs; + for(i = 0; i < ext->needle_count; i++) { + /*Calculate the end point of a needle*/ + int16_t needle_angle = (ext->values[i] - min) * angle * (1 << LV_GAUGE_INTERPOLATE_SHIFT) / (max - min); //+ angle_ofs; + + + int16_t needle_angle_low = (needle_angle >> LV_GAUGE_INTERPOLATE_SHIFT) + angle_ofs; + int16_t needle_angle_high = needle_angle_low + 1; + + + p_end_low.y = (lv_trigo_sin(needle_angle_low) * r) / LV_TRIGO_SIN_MAX + y_ofs; + p_end_low.x = (lv_trigo_sin(needle_angle_low + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + + p_end_high.y = (lv_trigo_sin(needle_angle_high) * r) / LV_TRIGO_SIN_MAX + y_ofs; + p_end_high.x = (lv_trigo_sin(needle_angle_high + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs; + + uint16_t rem = needle_angle & ((1 << LV_GAUGE_INTERPOLATE_SHIFT) - 1); + int16_t x_mod = ((LV_MATH_ABS(p_end_high.x - p_end_low.x)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; + int16_t y_mod = ((LV_MATH_ABS(p_end_high.y - p_end_low.y)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT; + + if(p_end_high.x < p_end_low.x) x_mod = -x_mod; + if(p_end_high.y < p_end_low.y) y_mod = -y_mod; + + p_end.x = p_end_low.x + x_mod; + p_end.y = p_end_low.y + y_mod; + + /*Draw the needle with the corresponding color*/ + if(ext->needle_colors == NULL) style_needle.line.color = LV_GAUGE_DEF_NEEDLE_COLOR; + else style_needle.line.color = ext->needle_colors[i]; + + lv_draw_line(&p_mid, &p_end, mask, &style_needle, opa_scale); + } + + /*Draw the needle middle area*/ + lv_style_t style_neddle_mid; + lv_style_copy(&style_neddle_mid, &lv_style_plain); + style_neddle_mid.body.main_color = style->body.border.color; + style_neddle_mid.body.grad_color = style->body.border.color; + style_neddle_mid.body.radius = LV_RADIUS_CIRCLE; + + lv_area_t nm_cord; + nm_cord.x1 = x_ofs - style->body.padding.ver; + nm_cord.y1 = y_ofs - style->body.padding.ver; + nm_cord.x2 = x_ofs + style->body.padding.ver; + nm_cord.y2 = y_ofs + style->body.padding.ver; + + lv_draw_rect(&nm_cord, mask, &style_neddle_mid, lv_obj_get_opa_scale(gauge)); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.h new file mode 100644 index 0000000..beef9dc --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_gauge.h @@ -0,0 +1,222 @@ +/** + * @file lv_gauge.h + * + */ + +#ifndef LV_GAUGE_H +#define LV_GAUGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_GAUGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LMETER == 0 +#error "lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_lmeter.h" +#include "lv_label.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of gauge*/ +typedef struct +{ + lv_lmeter_ext_t lmeter; /*Ext. of ancestor*/ + /*New data for this type */ + int16_t * values; /*Array of the set values (for needles) */ + const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + uint8_t needle_count; /*Number of needles*/ + uint8_t label_count; /*Number of labels on the scale*/ +} lv_gauge_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors); + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); + +/** + * Set minimum and the maximum values of a gauge + * @param gauge pointer to he gauge object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max) +{ + lv_lmeter_set_range(gauge, min, max); +} + +/** + * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn + * @param gauge pointer to a gauge object + * @param value the critical value + */ +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +{ + lv_lmeter_set_value(gauge, value); +} + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); + +/** + * Set the styles of a gauge + * @param gauge pointer to a gauge object + * @param bg set the style of the gauge + * */ +static inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg) +{ + lv_obj_set_style(gauge, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); + +/** + * Get the minimum value of a gauge + * @param gauge pointer to a gauge object + * @return the minimum value of the gauge + */ +static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_min_value(lmeter); +} + +/** + * Get the maximum value of a gauge + * @param gauge pointer to a gauge object + * @return the maximum value of the gauge + */ +static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_max_value(lmeter); +} + +/** + * Get a critical value on the scale. + * @param gauge pointer to a gauge object + * @return the critical value + */ +static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +{ + return lv_lmeter_get_value(gauge); +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge); + +/** + * Get the scale number of a gauge + * @param gauge pointer to a gauge object + * @return number of the scale units + */ +static inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge) +{ + return lv_lmeter_get_line_count(gauge); +} + +/** + * Get the scale angle of a gauge + * @param gauge pointer to a gauge object + * @return angle of the scale + */ +static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) +{ + return lv_lmeter_get_scale_angle(gauge); +} + +/** + * Get the style of a gauge + * @param gauge pointer to a gauge object + * @return pointer to the gauge's style + */ +static inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge) +{ + return lv_obj_get_style(gauge); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GAUGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GAUGE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.c new file mode 100644 index 0000000..c9fb428 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.c @@ -0,0 +1,408 @@ +/** + * @file lv_img.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_img.h" +#if USE_LV_IMG != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_img: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_lang.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_ufs.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("image create started"); + + lv_obj_t * new_img = NULL; + + /*Create a basic object*/ + new_img = lv_obj_create(par, copy); + lv_mem_assert(new_img); + if(new_img == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_img); + + /*Extend the basic object to image object*/ + lv_img_ext_t * ext = lv_obj_allocate_ext_attr(new_img, sizeof(lv_img_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + ext->cf = LV_IMG_CF_UNKOWN; + ext->w = lv_obj_get_width(new_img); + ext->h = lv_obj_get_height(new_img); + ext->auto_size = 1; +#if USE_LV_MULTI_LANG + ext->lang_txt_id = LV_LANG_TXT_ID_NONE; +#endif + + /*Init the new object*/ + lv_obj_set_signal_func(new_img, lv_img_signal); + lv_obj_set_design_func(new_img, lv_img_design); + + if(copy == NULL) { + lv_obj_set_click(new_img, false); + /* Enable auto size for non screens + * because image screens are wallpapers + * and must be screen sized*/ + if(par != NULL) { + ext->auto_size = 1; + lv_obj_set_style(new_img, NULL); /*Inherit the style by default*/ + } else { + ext->auto_size = 0; + lv_obj_set_style(new_img, &lv_style_plain); /*Set a style for screens*/ + } + } else { + lv_img_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->auto_size = copy_ext->auto_size; + lv_img_set_src(new_img, copy_ext->src); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_img); + } + + + LV_LOG_INFO("image created"); + + return new_img; +} + + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img) +{ + lv_img_src_t src_type = lv_img_src_get_type(src_img); + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + +#if LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO + switch(src_type) { + case LV_IMG_SRC_FILE: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_FILE` type found"); + break; + case LV_IMG_SRC_VARIABLE: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found"); + break; + case LV_IMG_SRC_SYMBOL: + LV_LOG_TRACE("lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found"); + break; + default: + LV_LOG_WARN("lv_img_set_src: unknown type"); + } +#endif + + /*If the new source type is unknown free the memories of the old source*/ + if(src_type == LV_IMG_SRC_UNKNOWN) { + LV_LOG_WARN("lv_img_set_src: unknown image type"); + if(ext->src_type == LV_IMG_SRC_SYMBOL || ext->src_type == LV_IMG_SRC_FILE) { + lv_mem_free(ext->src); + } + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + return; + } + + lv_img_header_t header; + lv_img_dsc_get_info(src_img, &header); + + + + /*Save the source*/ + if(src_type == LV_IMG_SRC_VARIABLE) { + LV_LOG_INFO("lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found"); + + /*If memory was allocated because of the previous `src_type` then free it*/ + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + } + ext->src = src_img; + } else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) { + /* If the new and the old src are the same then it was only a refresh.*/ + if(ext->src != src_img) { + /*If memory was allocated because of the previous `src_type` then free it*/ + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + } + char * new_str = lv_mem_alloc(strlen(src_img) + 1); + lv_mem_assert(new_str); + if(new_str == NULL) return; + strcpy(new_str, src_img); + ext->src = new_str; + } + } + + if(src_type == LV_IMG_SRC_SYMBOL) { + /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/ + lv_style_t * style = lv_img_get_style(img); + lv_point_t size; + lv_txt_get_size(&size, src_img, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + header.w = size.x; + header.h = size.y; + } + + ext->src_type = src_type; + ext->w = header.w; + ext->h = header.h; + ext->cf = header.cf; + + if(lv_img_get_auto_size(img) != false) { + lv_obj_set_size(img, ext->w, ext->h); + } + + lv_obj_invalidate(img); +} + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but in different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t src_id) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + ext->lang_txt_id = src_id; + + /*Apply the new language*/ + img->signal_func(img, LV_SIGNAL_LANG_CHG, NULL); +} +#endif + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool en) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + ext->auto_size = (en == false ? 0 : 1); +} + + +/*===================== + * Getter functions + *====================*/ + + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + return ext->src; +} + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + if(ext->src_type == LV_IMG_SRC_FILE) return ext->src; + else return ""; +} + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + return ext->lang_txt_id; +} +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img) +{ + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + return ext->auto_size == 0 ? false : true; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the images + * @param img pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode) +{ + lv_style_t * style = lv_obj_get_style(img); + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + + if(mode == LV_DESIGN_COVER_CHK) { + bool cover = false; + if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL) return false; + + if(ext->cf == LV_IMG_CF_TRUE_COLOR || ext->cf == LV_IMG_CF_RAW) cover = lv_area_is_in(mask, &img->coords); + + return cover; + } else if(mode == LV_DESIGN_DRAW_MAIN) { + if(ext->h == 0 || ext->w == 0) return true; + lv_area_t coords; + lv_opa_t opa_scale = lv_obj_get_opa_scale(img); + + lv_obj_get_coords(img, &coords); + + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_VARIABLE) { + LV_LOG_TRACE("lv_img_design: start to draw image"); + lv_area_t cords_tmp; + cords_tmp.y1 = coords.y1; + cords_tmp.y2 = coords.y1 + ext->h - 1; + + for(; cords_tmp.y1 < coords.y2; cords_tmp.y1 += ext->h, cords_tmp.y2 += ext->h) { + cords_tmp.x1 = coords.x1; + cords_tmp.x2 = coords.x1 + ext->w - 1; + for(; cords_tmp.x1 < coords.x2; cords_tmp.x1 += ext->w, cords_tmp.x2 += ext->w) { + lv_draw_img(&cords_tmp, mask, ext->src, style, opa_scale); + } + } + } else if(ext->src_type == LV_IMG_SRC_SYMBOL) { + LV_LOG_TRACE("lv_img_design: start to draw symbol"); + lv_style_t style_mod; + lv_style_copy(&style_mod, style); + style_mod.text.color = style->image.color; + lv_draw_label(&coords, mask, &style_mod, opa_scale, ext->src, LV_TXT_FLAG_NONE, NULL); + } else { + /*Trigger the error handler of image drawer*/ + LV_LOG_WARN("lv_img_design: image source type is unknown"); + lv_draw_img(&img->coords, mask, NULL, style, opa_scale); + } + } + + return true; +} + + +/** + * Signal function of the image + * @param img pointer to an image object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(img, sign, param); + if(res != LV_RES_OK) return res; + + lv_img_ext_t * ext = lv_obj_get_ext_attr(img); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_mem_free(ext->src); + ext->src = NULL; + ext->src_type = LV_IMG_SRC_UNKNOWN; + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Refresh the file name to refresh the symbol text size*/ + if(ext->src_type == LV_IMG_SRC_SYMBOL) { + lv_img_set_src(img, ext->src); + + } + } else if(sign == LV_SIGNAL_LANG_CHG) { +#if USE_LV_MULTI_LANG + if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) { + const char * lang_src = lv_lang_get_text(ext->lang_txt_id); + if(lang_src) { + lv_img_set_src(img, lang_src); + } else { + LV_LOG_WARN("lv_lang_get_text return NULL for an image's source"); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_img"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.h new file mode 100644 index 0000000..8ee8616 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_img.h @@ -0,0 +1,195 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_IMG != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_symbol_def.h" +#include "lv_label.h" +#include "../lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image*/ +typedef struct +{ + /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/ + /*New data for this type */ + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the image to display. */ +#endif + uint8_t src_type :2; /*See: lv_img_src_t*/ + uint8_t auto_size :1; /*1: automatically set the object size to the image size*/ + uint8_t cf :5; /*Color format from `lv_img_color_format_t`*/ +} lv_img_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img); + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but on different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id); +#endif + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0. + * Use 'lv_img_set_src()' instead. + * @param img - + * @param fn - + */ +static inline void lv_img_set_file(lv_obj_t * img, const char * fn) +{ + (void) img; + (void) fn; +} + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en); + +/** + * Set the style of an image + * @param img pointer to an image object + * @param style pointer to a style + */ +static inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style) +{ + lv_obj_set_style(img, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @param upscale - + */ +static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale) +{ + (void) img; + (void) upcale; +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img); + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img); + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img); +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img); + +/** + * Get the style of an image object + * @param img pointer to an image object + * @return pointer to the image's style + */ +static inline lv_style_t* lv_img_get_style(const lv_obj_t *img) +{ + return lv_obj_get_style(img); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @return false + */ +static inline bool lv_img_get_upscale(const lv_obj_t * img) +{ + (void)img; + return false; +} + +/********************** + * MACROS + **********************/ + +/*Use this macro to declare an image in a c file*/ +#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; + +#endif /*USE_LV_IMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c new file mode 100644 index 0000000..ed1d72b --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.c @@ -0,0 +1,391 @@ +/** + * @file lv_imgbtn.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_imgbtn.h" +#if USE_LV_IMGBTN != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param); +static void refr_img(lv_obj_t * imgbtn); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a image button object + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("image button create started"); + + /*Create the ancestor of image button*/ + lv_obj_t * new_imgbtn = lv_btn_create(par, copy); + lv_mem_assert(new_imgbtn); + if(new_imgbtn == NULL) return NULL; + + /*Allocate the image button type specific extended data*/ + lv_imgbtn_ext_t * ext = lv_obj_allocate_ext_attr(new_imgbtn, sizeof(lv_imgbtn_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_imgbtn); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_imgbtn); + + /*Initialize the allocated 'ext' */ +#if LV_IMGBTN_TILED == 0 + memset(ext->img_src, 0, sizeof(ext->img_src)); +#else + memset(ext->img_src_left, 0, sizeof(ext->img_src_left)); + memset(ext->img_src_mid, 0, sizeof(ext->img_src_mid)); + memset(ext->img_src_right, 0, sizeof(ext->img_src_right)); +#endif + + ext->act_cf = LV_IMG_CF_UNKOWN; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_imgbtn, lv_imgbtn_signal); + lv_obj_set_design_func(new_imgbtn, lv_imgbtn_design); + + /*Init the new image button image button*/ + if(copy == NULL) { + + } + /*Copy an existing image button*/ + else { + lv_imgbtn_ext_t * copy_ext = lv_obj_get_ext_attr(copy); +#if LV_IMGBTN_TILED == 0 + memcpy(ext->img_src, copy_ext->img_src, sizeof(ext->img_src)); +#else + memcpy(ext->img_src_left, copy_ext->img_src_left, sizeof(ext->img_src_left)); + memcpy(ext->img_src_mid, copy_ext->img_src_mid, sizeof(ext->img_src_mid)); + memcpy(ext->img_src_right, copy_ext->img_src_right, sizeof(ext->img_src_right)); +#endif + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_imgbtn); + } + + LV_LOG_INFO("image button created"); + + return new_imgbtn; +} + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + ext->img_src[state] = src; + + refr_img(imgbtn); +} + +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + ext->img_src_left[state] = src_left; + ext->img_src_mid[state] = src_mid; + ext->img_src_right[state] = src_right; + + refr_img(imgbtn); +} + +#endif + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t * style) +{ + lv_btn_set_style(imgbtn, type, style); +} + +/*===================== + * Getter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src[state]; +} +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_left[state]; +} + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_mid[state]; +} + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + + return ext->img_src_right[state]; +} + +#endif + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type) +{ + return lv_btn_get_style(imgbtn, type); +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the image buttons + * @param imgbtn pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + bool cover = false; + if(ext->act_cf == LV_IMG_CF_TRUE_COLOR || ext->act_cf == LV_IMG_CF_RAW) { + cover = lv_area_is_in(mask, &imgbtn->coords); + } + + return cover; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Just draw an image*/ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + lv_btn_state_t state = lv_imgbtn_get_state(imgbtn); + lv_style_t * style = lv_imgbtn_get_style(imgbtn, state); + lv_opa_t opa_scale = lv_obj_get_opa_scale(imgbtn); + +#if LV_IMGBTN_TILED == 0 + const void * src = ext->img_src[state]; + lv_draw_img(&imgbtn->coords, mask, src, style, opa_scale); +#else + const void * src; + lv_img_header_t header; + lv_area_t coords; + lv_coord_t left_w = 0; + lv_coord_t right_w = 0; + + src = ext->img_src_left[state]; + if(src) { + lv_img_dsc_get_info(src, &header); + left_w = header.w; + coords.x1 = imgbtn->coords.x1; + coords.y1 = imgbtn->coords.y1; + coords.x2 = coords.x1 + header.w - 1; + coords.y2 = coords.y1 + header.h - 1; + lv_draw_img(&coords, mask, src, style, opa_scale); + } + + src = ext->img_src_right[state]; + if(src) { + lv_img_dsc_get_info(src, &header); + right_w = header.w; + coords.x1 = imgbtn->coords.x2 - header.w + 1; + coords.y1 = imgbtn->coords.y1; + coords.x2 = imgbtn->coords.x2; + coords.y2 = imgbtn->coords.y1 + header.h - 1; + lv_draw_img(&coords, mask, src, style, opa_scale); + } + + src = ext->img_src_mid[state]; + if(src) { + lv_coord_t obj_w = lv_obj_get_width(imgbtn); + lv_coord_t i; + lv_img_dsc_get_info(src, &header); + + coords.x1 = imgbtn->coords.x1 + left_w ; + coords.y1 = imgbtn->coords.y1; + coords.x2 = coords.x1 + header.w - 1; + coords.y2 = imgbtn->coords.y1 + header.h - 1; + + for(i = 0; i < obj_w - right_w - left_w; i += header.w) { + lv_draw_img(&coords, mask, src, style, opa_scale); + coords.x1 = coords.x2 + 1; + coords.x2 += header.w; + } + } + + +#endif + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the image button + * @param imgbtn pointer to a image button object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(imgbtn, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_STYLE_CHG) { + /* If the style changed then the button was clicked, released etc. so probably the state was changed as well + * Set the new image for the new state.*/ + refr_img(imgbtn); + } else if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_imgbtn"; + } + + return res; +} + + +static void refr_img(lv_obj_t * imgbtn) +{ + lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn); + lv_btn_state_t state = lv_imgbtn_get_state(imgbtn); + lv_img_header_t header; + +#if LV_IMGBTN_TILED == 0 + const void * src = ext->img_src[state]; +#else + const void * src = ext->img_src_mid[state]; +#endif + + lv_res_t info_res; + info_res = lv_img_dsc_get_info(src, &header); + if(info_res == LV_RES_OK) { + ext->act_cf = header.cf; +#if LV_IMGBTN_TILED == 0 + lv_obj_set_size(imgbtn, header.w, header.h); +#else + lv_obj_set_height(imgbtn, header.h); +#endif + } else { + ext->act_cf = LV_IMG_CF_UNKOWN; + } + + lv_obj_invalidate(imgbtn); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h new file mode 100644 index 0000000..300e7b8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_imgbtn.h @@ -0,0 +1,249 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_IMGBTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btn.h" +#include "../lv_draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_btn_ext_t btn; /*Ext. of ancestor*/ + /*New data for this type */ + int idx; +#if LV_IMGBTN_TILED == 0 + const void * img_src[LV_BTN_STATE_NUM]; /*Store images to each state*/ +#else + const void * img_src_left[LV_BTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_mid[LV_BTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_right[LV_BTN_STATE_NUM]; /*Store right side images to each state*/ +#endif + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_ext_t; + + +/*Styles*/ +enum { + LV_IMGBTN_STYLE_REL, + LV_IMGBTN_STYLE_PR, + LV_IMGBTN_STYLE_TGL_REL, + LV_IMGBTN_STYLE_TGL_PR, + LV_IMGBTN_STYLE_INA, +}; +typedef uint8_t lv_imgbtn_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a image button objects + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src); +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right); + +#endif + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param imgbtn pointer to an image button object + * @param tgl true: enable toggled states, false: disable + */ +static inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl) +{ + lv_btn_set_toggle(imgbtn, tgl); +} + +/** + * Set the state of the image button + * @param imgbtn pointer to an image button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +static inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_btn_set_state(imgbtn, state); +} + +/** + * Toggle the state of the image button (ON->OFF, OFF->ON) + * @param imgbtn pointer to a image button object + */ +static inline void lv_imgbtn_toggle(lv_obj_t * imgbtn) +{ + lv_btn_toggle(imgbtn); +} + +/** + * Set a function to call when a button event happens + * @param imgbtn pointer to an image button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +static inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action) +{ + lv_btn_set_action(imgbtn, type, action); +} + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state); + +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state); + +#endif +/** + * Get the current state of the image button + * @param imgbtn pointer to a image button object + * @return the state of the button (from lv_btn_state_t enum) + */ +static inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn) +{ + return lv_btn_get_state(imgbtn); +} + +/** + * Get the toggle enable attribute of the image button + * @param imgbtn pointer to a image button object + * @return ture: toggle enabled, false: disabled + */ +static inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn) +{ + return lv_btn_get_toggle(imgbtn); +} + +/** + * Get the release action of a image button + * @param imgbtn pointer to a image button object + * @return pointer to the release action function + */ +static inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type) +{ + return lv_btn_get_action(imgbtn, type); +} + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_IMGBTN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.c new file mode 100644 index 0000000..8548d55 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_kb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_kb.h" +#if USE_LV_KB != 0 + +#include "lv_ta.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param); +static lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +static const char * kb_map_lc[] = { + "\2051#", "\204q", "\204w", "\204e", "\204r", "\204t", "\204y", "\204u", "\204i", "\204o", "\204p", "\207Bksp", "\n", + "\226ABC", "\203a", "\203s", "\203d", "\203f", "\203g", "\203h", "\203j", "\203k", "\203l", "\207Enter", "\n", + "_", "-", "z", "x", "c", "v", "b", "n", "m", ".", ",", ":", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_uc[] = { + "\2051#", "\204Q", "\204W", "\204E", "\204R", "\204T", "\204Y", "\204U", "\204I", "\204O", "\204P", "\207Bksp", "\n", + "\226abc", "\203A", "\203S", "\203D", "\203F", "\203G", "\203H", "\203J", "\203K", "\203L", "\207Enter", "\n", + "_", "-", "Z", "X", "C", "V", "B", "N", "M", ".", ",", ":", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_spec[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "\202Bksp", "\n", + "\222abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">", "\n", + "\\", "@", "$", "(", ")", "{", "}", "[", "]", ";", "\"", "'", "\n", + "\202"SYMBOL_CLOSE, "\202"SYMBOL_LEFT, "\206 ", "\202"SYMBOL_RIGHT, "\202"SYMBOL_OK, "" +}; + +static const char * kb_map_num[] = { + "1", "2", "3", "\202"SYMBOL_CLOSE, "\n", + "4", "5", "6", "\202"SYMBOL_OK, "\n", + "7", "8", "9", "\202Bksp", "\n", + "+/-", "0", ".", SYMBOL_LEFT, SYMBOL_RIGHT, "" +}; + +static const char * kb_map_hex[] = { + "1", "2", "3", "A", "D", "\212", "\n", + "4", "5", "6", "B", "E", "\202Bksp", "\n", + "7", "8", "9", "C", "F", "\202"SYMBOL_OK, "\n", + "\211", "0", "\213", SYMBOL_LEFT, SYMBOL_RIGHT, "" +}; +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("keyboard create started"); + + /*Create the ancestor of keyboard*/ + lv_obj_t * new_kb = lv_btnm_create(par, copy); + lv_mem_assert(new_kb); + if(new_kb == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_kb); + + /*Allocate the keyboard type specific extended data*/ + lv_kb_ext_t * ext = lv_obj_allocate_ext_attr(new_kb, sizeof(lv_kb_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + + ext->ta = NULL; + ext->mode = LV_KB_MODE_TEXT; + ext->cursor_mng = 0; + ext->hide_action = NULL; + ext->ok_action = NULL; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_kb, lv_kb_signal); + + /*Init the new keyboard keyboard*/ + if(copy == NULL) { + lv_obj_set_size(new_kb, LV_HOR_RES, LV_VER_RES / 2); + lv_obj_align(new_kb, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_btnm_set_action(new_kb, lv_kb_def_action); + lv_btnm_set_map(new_kb, kb_map_lc); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_kb_set_style(new_kb, LV_KB_STYLE_BG, th->kb.bg); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_REL, th->kb.btn.rel); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_PR, th->kb.btn.pr); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_REL, th->kb.btn.tgl_rel); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_PR, th->kb.btn.tgl_pr); + lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_INA, th->kb.btn.ina); + } else { + /*Let the button matrix's styles*/ + } + } + /*Copy an existing keyboard*/ + else { + lv_kb_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->ta = NULL; + ext->ta = copy_ext->ta; + ext->mode = copy_ext->mode; + ext->cursor_mng = copy_ext->cursor_mng; + ext->hide_action = copy_ext->hide_action; + ext->ok_action = copy_ext->ok_action; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_kb); + } + + + LV_LOG_INFO("keyboard created"); + + + return new_kb; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + lv_cursor_type_t cur_type; + + /*Hide the cursor of the old Text area if cursor management is enabled*/ + if(ext->ta && ext->cursor_mng) { + cur_type = lv_ta_get_cursor_type(ext->ta); + lv_ta_set_cursor_type(ext->ta, cur_type | LV_CURSOR_HIDDEN); + } + + ext->ta = ta; + + /*Show the cursor of the new Text area if cursor management is enabled*/ + if(ext->ta && ext->cursor_mng) { + cur_type = lv_ta_get_cursor_type(ext->ta); + lv_ta_set_cursor_type(ext->ta, cur_type & (~LV_CURSOR_HIDDEN)); + } +} + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + if(ext->mode == mode) return; + + ext->mode = mode; + if(mode == LV_KB_MODE_TEXT) lv_btnm_set_map(kb, kb_map_lc); + else if(mode == LV_KB_MODE_NUM) lv_btnm_set_map(kb, kb_map_num); + else if (mode == LV_KB_MODE_HEX) lv_btnm_set_map(kb, kb_map_hex); +} + + +/** + * Automatically hide or show the cursor of Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + if(ext->cursor_mng == en) return; + + ext->cursor_mng = en == false ? 0 : 1; + + if(ext->ta) { + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ext->ta); + + if(ext->cursor_mng) { + lv_ta_set_cursor_type(ext->ta, cur_type & (~LV_CURSOR_HIDDEN)); + } else { + lv_ta_set_cursor_type(ext->ta, cur_type | LV_CURSOR_HIDDEN); + } + } +} + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + ext->ok_action = action; +} + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + ext->hide_action = action; +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t * kb, lv_kb_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_KB_STYLE_BG: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BG, style); + break; + case LV_KB_STYLE_BTN_REL: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_REL, style); + break; + case LV_KB_STYLE_BTN_PR: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_KB_STYLE_BTN_TGL_REL: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_KB_STYLE_BTN_TGL_PR: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_KB_STYLE_BTN_INA: + lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_INA, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->ta; +} + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->mode; +} + + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->cursor_mng == 0 ? false : true; +} + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->ok_action; +} + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + return ext->hide_action; +} + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t * kb, lv_kb_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_KB_STYLE_BG: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BG); + break; + case LV_KB_STYLE_BTN_REL: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_REL); + break; + case LV_KB_STYLE_BTN_PR: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_PR); + break; + case LV_KB_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_KB_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_PR); + break; + case LV_KB_STYLE_BTN_INA: + style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the keyboard + * @param kb pointer to a keyboard object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(kb, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_kb"; + } + + return res; +} + +/** + * Called when a button of 'kb_btnm' is released + * @param btnm pointer to 'kb_btnm' + * @param i the index of the released button from the current btnm map + * @return LV_ACTION_RES_INV if the btnm is deleted else LV_ACTION_RES_OK + */ +static lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt) +{ + lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb); + lv_res_t res = LV_RES_OK; + + /*Do the corresponding action according to the text of the button*/ + if(strcmp(txt, "abc") == 0) { + lv_btnm_set_map(kb, kb_map_lc); + return LV_RES_OK; + } else if(strcmp(txt, "ABC") == 0) { + lv_btnm_set_map(kb, kb_map_uc); + return LV_RES_OK; + } else if(strcmp(txt, "1#") == 0) { + lv_btnm_set_map(kb, kb_map_spec); + return LV_RES_OK; + } else if(strcmp(txt, SYMBOL_CLOSE) == 0) { + if(ext->hide_action) res = ext->hide_action(kb); + else { + lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/ + lv_obj_del(kb); + } + return res; + } else if(strcmp(txt, SYMBOL_OK) == 0) { + if(ext->ok_action) res = ext->ok_action(kb); + else { + lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/ + res = lv_obj_del(kb); + } + return res; + } + + if(res != LV_RES_OK) return res; /*The keyboard might be deleted in the actions*/ + + /*Add the characters to the text area if set*/ + if(ext->ta == NULL) return res; + + if(strcmp(txt, "Enter") == 0)lv_ta_add_char(ext->ta, '\n'); + else if(strcmp(txt, SYMBOL_LEFT) == 0) lv_ta_cursor_left(ext->ta); + else if(strcmp(txt, SYMBOL_RIGHT) == 0) lv_ta_cursor_right(ext->ta); + else if(strcmp(txt, "Bksp") == 0) lv_ta_del_char(ext->ta); + else if(strcmp(txt, "+/-") == 0) { + uint16_t cur = lv_ta_get_cursor_pos(ext->ta); + const char * ta_txt = lv_ta_get_text(ext->ta); + if(ta_txt[0] == '-') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '+'); + lv_ta_set_cursor_pos(ext->ta, cur); + } else if(ta_txt[0] == '+') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur); + } else { + lv_ta_set_cursor_pos(ext->ta, 0); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur + 1); + } + } else { + lv_ta_add_text(ext->ta, txt); + } + return LV_RES_OK; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.h new file mode 100644 index 0000000..027b121 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_kb.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_kb.h + * + */ + +#ifndef LV_KB_H +#define LV_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_KB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_TA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_btnm.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_KB_MODE_TEXT, + LV_KB_MODE_NUM, + LV_KB_MODE_HEX +}; +typedef uint8_t lv_kb_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnm_ext_t btnm; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *ta; /*Pointer to the assigned text area*/ + lv_kb_mode_t mode; /*Key map type*/ + uint8_t cursor_mng :1; /*1: automatically show/hide cursor when a text area is assigned or left*/ + lv_action_t ok_action; /*Called when the "Ok" button is clicked*/ + lv_action_t hide_action; /*Called when the "Hide" button is clicked*/ +} lv_kb_ext_t; + +enum { + LV_KB_STYLE_BG, + LV_KB_STYLE_BTN_REL, + LV_KB_STYLE_BTN_PR, + LV_KB_STYLE_BTN_TGL_REL, + LV_KB_STYLE_BTN_TGL_PR, + LV_KB_STYLE_BTN_INA, +}; +typedef uint8_t lv_kb_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode); + +/** + * Automatically hide or show the cursor of the current Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en); + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param map pointer to a string array to describe the map. + * See 'lv_btnm_set_map()' for more info. + */ +static inline void lv_kb_set_map(lv_obj_t *kb, const char ** map) +{ + lv_btnm_set_map(kb, map); +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb); + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb); + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_KB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_KB_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.c new file mode 100644 index 0000000..57ac2d0 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.c @@ -0,0 +1,987 @@ +/** + * @file lv_rect.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_label.h" +#if USE_LV_LABEL != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_lang.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +/*Test configurations*/ +#ifndef LV_LABEL_SCROLL_SPEED +#define LV_LABEL_SCROLL_SPEED (25) /*Hor, or ver. scroll speed (px/sec) in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif + +#define ANIM_WAIT_CHAR_COUNT 3 + +#define LV_LABEL_DOT_END_INV 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param); +static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode); +static void lv_label_refr_text(lv_obj_t * label); +static void lv_label_revert_dots(lv_obj_t * label); + +#if USE_LV_ANIMATION +static void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x); +static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y); +#endif +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("label create started"); + + /*Create a basic object*/ + lv_obj_t * new_label = lv_obj_create(par, copy); + lv_mem_assert(new_label); + if(new_label == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_label); + + /*Extend the basic object to a label object*/ + lv_obj_allocate_ext_attr(new_label, sizeof(lv_label_ext_t)); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(new_label); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->text = NULL; + ext->static_txt = 0; + ext->recolor = 0; + ext->body_draw = 0; + ext->align = LV_LABEL_ALIGN_LEFT; + ext->dot_end = LV_LABEL_DOT_END_INV; + ext->long_mode = LV_LABEL_LONG_EXPAND; + ext->anim_speed = LV_LABEL_SCROLL_SPEED; + ext->offset.x = 0; + ext->offset.y = 0; +#if USE_LV_MULTI_LANG + ext->lang_txt_id = LV_LANG_TXT_ID_NONE; +#endif + lv_obj_set_design_func(new_label, lv_label_design); + lv_obj_set_signal_func(new_label, lv_label_signal); + + /*Init the new label*/ + if(copy == NULL) { + lv_obj_set_click(new_label, false); + lv_label_set_long_mode(new_label, LV_LABEL_LONG_EXPAND); + lv_label_set_text(new_label, "Text"); + lv_label_set_style(new_label, NULL); /*Inherit parent's style*/ + } + /*Copy 'copy' if not NULL*/ + else { + lv_label_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_label_set_long_mode(new_label, lv_label_get_long_mode(copy)); + lv_label_set_recolor(new_label, lv_label_get_recolor(copy)); + lv_label_set_body_draw(new_label, lv_label_get_body_draw(copy)); + lv_label_set_align(new_label, lv_label_get_align(copy)); + if(copy_ext->static_txt == 0) lv_label_set_text(new_label, lv_label_get_text(copy)); + else lv_label_set_static_text(new_label, lv_label_get_text(copy)); + + /*In DOT mode save the text byte-to-byte because a '\0' can be in the middle*/ + if(copy_ext->long_mode == LV_LABEL_LONG_DOT) { + ext->text = lv_mem_realloc(ext->text, lv_mem_get_size(copy_ext->text)); + lv_mem_assert(ext->text); + if(ext->text == NULL) return NULL; + memcpy(ext->text, copy_ext->text, lv_mem_get_size(copy_ext->text)); + } + + memcpy(ext->dot_tmp, copy_ext->dot_tmp, sizeof(ext->dot_tmp)); + ext->dot_end = copy_ext->dot_end; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_label); + } + + + LV_LOG_INFO("label created"); + + return new_label; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text) +{ + lv_obj_invalidate(label); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*If text is NULL then refresh */ + if(text == NULL) { + lv_label_refr_text(label); + return; + } + + if(ext->text == text && ext->static_txt == 0) { + /*If set its own text then reallocate it (maybe its size changed)*/ + ext->text = lv_mem_realloc(ext->text, strlen(ext->text) + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + } else { + /*Allocate space for the new text*/ + uint32_t len = strlen(text) + 1; + if(ext->text != NULL && ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + + ext->text = lv_mem_alloc(len); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + strcpy(ext->text, text); + ext->static_txt = 0; /*Now the text is dynamically allocated*/ + } + + lv_label_refr_text(label); +} + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size) +{ + lv_obj_invalidate(label); + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*If trying to set its own text or the array is NULL then refresh */ + if(array == ext->text || array == NULL) { + lv_label_refr_text(label); + return; + } + + /*Allocate space for the new text*/ + if(ext->text != NULL && ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + ext->text = lv_mem_alloc(size + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + memcpy(ext->text, array, size); + ext->text[size] = '\0'; + ext->static_txt = 0; /*Now the text is dynamically allocated*/ + + lv_label_refr_text(label); +} + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->static_txt == 0 && ext->text != NULL) { + lv_mem_free(ext->text); + ext->text = NULL; + } + + if(text != NULL) { + ext->static_txt = 1; + ext->text = (char *) text; + } + + lv_label_refr_text(label); +} + +#if USE_LV_MULTI_LANG +/** + *Set a text ID which refers a the same text but in a different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->lang_txt_id = txt_id; + + /*Apply the new language*/ + label->signal_func(label, LV_SIGNAL_LANG_CHG, NULL); +} +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + +#if USE_LV_ANIMATION + /*Delete the old animation (if exists)*/ + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x); + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y); + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x); + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y); +#endif + ext->offset.x = 0; + ext->offset.y = 0; + + if(long_mode == LV_LABEL_LONG_ROLL || long_mode == LV_LABEL_LONG_CROP) ext->expand = 1; + else ext->expand = 0; + + /*Restore the character under the dots*/ + if(ext->long_mode == LV_LABEL_LONG_DOT && ext->dot_end != LV_LABEL_DOT_END_INV) { + lv_label_revert_dots(label); + } + + ext->long_mode = long_mode; + lv_label_refr_text(label); +} + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t * label, lv_label_align_t align) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->align == align) return; + + ext->align = align; + + lv_obj_invalidate(label); /*Enough to invalidate because alignment is only drawing related (lv_refr_label_text() not required)*/ +} + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->recolor == en) return; + + ext->recolor = en == false ? 0 : 1; + + lv_label_refr_text(label); /*Refresh the text because the potential colo codes in text needs to be hided or revealed*/ +} + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t * label, bool en) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->body_draw == en) return; + + ext->body_draw = en == false ? 0 : 1; + + lv_obj_refresh_ext_size(label); + + lv_obj_invalidate(label); +} + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->anim_speed == anim_speed) return; + + ext->anim_speed = anim_speed; + + if(ext->long_mode == LV_LABEL_LONG_ROLL || ext->long_mode == LV_LABEL_LONG_SCROLL) { + lv_label_refr_text(label); + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + return ext->text; +} + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->lang_txt_id; +} +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->long_mode; +} + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->align; +} + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->recolor == 0 ? false : true; +} + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->body_draw == 0 ? false : true; +} + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + return ext->anim_speed; +} + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos) +{ + const char * txt = lv_label_get_text(label); + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + uint8_t letter_height = lv_font_get_height(font); + lv_coord_t y = 0; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + /*If the width will be expanded the set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + index = lv_txt_encoded_get_byte_id(txt, index); + + /*Search the line of the index letter */; + while(txt[new_line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + if(index < new_line_start || txt[new_line_start] == '\0') break; /*The line of 'index' letter begins at 'line_start'*/ + + y += letter_height + style->text.line_space; + line_start = new_line_start; + } + + /*If the last character is line break then go to the next line*/ + if(index > 0) { + if((txt[index - 1] == '\n' || txt[index - 1] == '\r') && txt[index] == '\0') { + y += letter_height + style->text.line_space; + line_start = index; + } + } + + /*Calculate the x coordinate*/ + lv_coord_t x = lv_txt_get_width(&txt[line_start], index - line_start, + font, style->text.letter_space, flag); + + if(index != line_start) x += style->text.letter_space; + + if(ext->align == LV_LABEL_ALIGN_CENTER) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + x += lv_obj_get_width(label) / 2 - line_w / 2; + + } else if(ext->align == LV_LABEL_ALIGN_RIGHT) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + + x += lv_obj_get_width(label) - line_w; + } + pos->x = x; + pos->y = y; +} + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) +{ + const char * txt = lv_label_get_text(label); + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + uint32_t line_start = 0; + uint32_t new_line_start = 0; + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + uint8_t letter_height = lv_font_get_height(font); + lv_coord_t y = 0; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + /*If the width will be expanded set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + /*Search the line of the index letter */; + while(txt[line_start] != '\0') { + new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + + if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/ + y += letter_height + style->text.line_space; + + line_start = new_line_start; + } + + /*Calculate the x coordinate*/ + lv_coord_t x = 0; + if(ext->align == LV_LABEL_ALIGN_CENTER) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, + font, style->text.letter_space, flag); + x += lv_obj_get_width(label) / 2 - line_w / 2; + } + + lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; + uint32_t i = line_start; + uint32_t i_current = i; + uint32_t letter; + while(i < new_line_start - 1) { + letter = lv_txt_encoded_next(txt, &i); /*Be careful 'i' already points to the next character*/ + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) { + continue; /*Skip the letter is it is part of a command*/ + } + } + + x += lv_font_get_width(font, letter); + if(pos->x < x) { + i = i_current; + break; + } + x += style->text.letter_space; + i_current = i; + } + + return lv_encoded_get_char_id(txt, i); +} + + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*Can not append to static text*/ + if(ext->static_txt != 0) return; + + lv_obj_invalidate(label); + + /*Allocate space for the new text*/ + uint32_t old_len = strlen(ext->text); + uint32_t ins_len = strlen(txt); + uint32_t new_len = ins_len + old_len; + ext->text = lv_mem_realloc(ext->text, new_len + 1); + lv_mem_assert(ext->text); + if(ext->text == NULL) return; + + if(pos == LV_LABEL_POS_LAST) { +#if LV_TXT_UTF8 == 0 + pos = old_len; +#else + pos = lv_txt_get_encoded_length(ext->text); +#endif + } + + lv_txt_ins(ext->text, pos, txt); + + lv_label_refr_text(label); +} + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + /*Can not append to static text*/ + if(ext->static_txt != 0) return; + + lv_obj_invalidate(label); + + char * label_txt = lv_label_get_text(label); + /*Delete the characters*/ + lv_txt_cut(label_txt, pos, cnt); + + /*Refresh the label*/ + lv_label_refr_text(label); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the labels + * @param label pointer to a label object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode) +{ + /* A label never covers an area */ + if(mode == LV_DESIGN_COVER_CHK) return false; + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_area_t coords; + lv_style_t * style = lv_obj_get_style(label); + lv_opa_t opa_scale = lv_obj_get_opa_scale(label); + lv_obj_get_coords(label, &coords); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(label); + if(lv_group_get_focused(g) == label) { + lv_draw_rect(&coords, mask, style, opa_scale); + } +#endif + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + if(ext->body_draw) { + lv_area_t bg; + lv_obj_get_coords(label, &bg); + bg.x1 -= style->body.padding.hor; + bg.x2 += style->body.padding.hor; + bg.y1 -= style->body.padding.ver; + bg.y2 += style->body.padding.ver; + + lv_draw_rect(&bg, mask, style, lv_obj_get_opa_scale(label)); + } + + /*TEST: draw a background for the label*/ + //lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER); + + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(ext->align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; + + /* In ROLL mode the CENTER and RIGHT are pointless so remove them. + * (In addition they will result mis-alignment is this case)*/ + if((ext->long_mode == LV_LABEL_LONG_ROLL) && + (ext->align == LV_LABEL_ALIGN_CENTER || ext->align == LV_LABEL_ALIGN_RIGHT)) { + lv_point_t size; + lv_txt_get_size(&size, ext->text, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); + if(size.x > lv_obj_get_width(label)) { + flag &= ~LV_TXT_FLAG_RIGHT; + flag &= ~LV_TXT_FLAG_CENTER; + } + } + + lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset); + } + return true; +} + + + +/** + * Signal function of the label + * @param label pointer to a label object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(label, sign, param); + if(res != LV_RES_OK) return res; + + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->static_txt == 0) { + lv_mem_free(ext->text); + ext->text = NULL; + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Revert dots for proper refresh*/ + lv_label_revert_dots(label); + + lv_label_refr_text(label); + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_area_get_width(&label->coords) != lv_area_get_width(param) || + lv_area_get_height(&label->coords) != lv_area_get_height(param)) { + lv_label_revert_dots(label); + lv_label_refr_text(label); + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + if(ext->body_draw) { + lv_style_t * style = lv_label_get_style(label); + label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.hor); + label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.ver); + } + } else if(sign == LV_SIGNAL_LANG_CHG) { +#if USE_LV_MULTI_LANG + if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) { + const char * lang_txt = lv_lang_get_text(ext->lang_txt_id); + if(lang_txt) { + lv_label_set_text(label, lang_txt); + } else { + LV_LOG_WARN("lv_lang_get_text return NULL for a label's text"); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_label"; + } + + return res; +} + +/** + * Refresh the label with its text stored in its extended data + * @param label pointer to a label object + */ +static void lv_label_refr_text(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + + if(ext->text == NULL) return; + + lv_coord_t max_w = lv_obj_get_width(label); + lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = style->text.font; + + /*If the width will be expanded set the max length to very big */ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || + ext->long_mode == LV_LABEL_LONG_SCROLL) { + max_w = LV_COORD_MAX; + } + + /*Calc. the height and longest line*/ + lv_point_t size; + lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; + if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; + lv_txt_get_size(&size, ext->text, font, style->text.letter_space, style->text.line_space, max_w, flag); + + /*Set the full size in expand mode*/ + if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) { + lv_obj_set_size(label, size.x, size.y); + + /*Start scrolling if the label is greater then its parent*/ + if(ext->long_mode == LV_LABEL_LONG_SCROLL) { +#if USE_LV_ANIMATION + lv_obj_t * parent = lv_obj_get_parent(label); + + /*Delete the potential previous scroller animations*/ + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x); + lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y); + + lv_anim_t anim; + anim.var = label; + anim.repeat = 1; + anim.playback = 1; + anim.start = 0; + anim.act_time = 0; + anim.end_cb = NULL; + anim.path = lv_anim_path_linear; + + anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') + + style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT; + anim.repeat_pause = anim.playback_pause; + + if(lv_obj_get_width(label) > lv_obj_get_width(parent)) { + anim.end = lv_obj_get_width(parent) - lv_obj_get_width(label); + anim.fp = (lv_anim_fp_t) lv_obj_set_x; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } else if(lv_obj_get_height(label) > lv_obj_get_height(parent)) { + anim.end = lv_obj_get_height(parent) - lv_obj_get_height(label) - lv_font_get_height(font); + anim.fp = (lv_anim_fp_t)lv_obj_set_y; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } +#endif + } + } + /*In roll mode keep the size but start offset animations*/ + else if(ext->long_mode == LV_LABEL_LONG_ROLL) { +#if USE_LV_ANIMATION + lv_anim_t anim; + anim.var = label; + anim.repeat = 1; + anim.playback = 1; + anim.start = 0; + anim.act_time = 0; + anim.end_cb = NULL; + anim.path = lv_anim_path_linear; + anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') + style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT; + anim.repeat_pause = anim.playback_pause; + + bool hor_anim = false; + if(size.x > lv_obj_get_width(label)) { + anim.end = lv_obj_get_width(label) - size.x; + anim.fp = (lv_anim_fp_t) lv_label_set_offset_x; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + hor_anim = true; + } else { + /*Delete the offset animation if not required*/ + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x); + ext->offset.x = 0; + } + + if(size.y > lv_obj_get_height(label) && hor_anim == false) { + anim.end = lv_obj_get_height(label) - size.y - (lv_font_get_height(font)); + anim.fp = (lv_anim_fp_t)lv_label_set_offset_y; + anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); + lv_anim_create(&anim); + } else { + /*Delete the offset animation if not required*/ + lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y); + ext->offset.y = 0; + } +#endif + } else if(ext->long_mode == LV_LABEL_LONG_DOT) { + if(size.y <= lv_obj_get_height(label)) { /*No dots are required, the text is short enough*/ + ext->dot_end = LV_LABEL_DOT_END_INV; + } else if(lv_txt_get_encoded_length(ext->text) <= LV_LABEL_DOT_NUM) { /*Don't turn to dots all the characters*/ + ext->dot_end = LV_LABEL_DOT_END_INV; + } else { + lv_point_t p; + p.x = lv_obj_get_width(label) - (lv_font_get_width(style->text.font, '.') + style->text.letter_space) * LV_LABEL_DOT_NUM; /*Shrink with dots*/ + p.y = lv_obj_get_height(label); + p.y -= p.y % (lv_font_get_height(style->text.font) + style->text.line_space); /*Round down to the last line*/ + p.y -= style->text.line_space; /*Trim the last line space*/ + uint32_t letter_id = lv_label_get_letter_on(label, &p); + + +#if LV_TXT_UTF8 == 0 + /*Save letters under the dots and replace them with dots*/ + uint8_t i; + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->dot_tmp[i] = ext->text[letter_id + i]; + ext->text[letter_id + i] = '.'; + } + + ext->dot_tmp[LV_LABEL_DOT_NUM] = ext->text[letter_id + LV_LABEL_DOT_NUM]; + ext->text[letter_id + LV_LABEL_DOT_NUM] = '\0'; + + ext->dot_end = letter_id + LV_LABEL_DOT_NUM; +#else + /*Save letters under the dots and replace them with dots*/ + uint32_t i; + uint32_t byte_id = lv_txt_encoded_get_byte_id(ext->text, letter_id); + uint32_t byte_id_ori = byte_id; + uint8_t len = 0; + for(i = 0; i <= LV_LABEL_DOT_NUM; i++) { + len += lv_txt_encoded_size(&ext->text[byte_id]); + lv_txt_encoded_next(ext->text, &byte_id); + } + + memcpy(ext->dot_tmp, &ext->text[byte_id_ori], len); + ext->dot_tmp[len] = '\0'; /*Close with a zero*/ + + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->text[byte_id_ori + i] = '.'; + } + ext->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0'; + + ext->dot_end = letter_id + LV_LABEL_DOT_NUM; +#endif + + } + } + /*In break mode only the height can change*/ + else if(ext->long_mode == LV_LABEL_LONG_BREAK) { + lv_obj_set_height(label, size.y); + } + /*Do not set the size in Clip mode*/ + else if(ext->long_mode == LV_LABEL_LONG_CROP) { + /*Do nothing*/ + } + + + lv_obj_invalidate(label); +} + +static void lv_label_revert_dots(lv_obj_t * label) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + if(ext->long_mode != LV_LABEL_LONG_DOT) return; + if(ext->dot_end == LV_LABEL_DOT_END_INV) return; +#if LV_TXT_UTF8 == 0 + uint32_t i; + for(i = 0; i <= LV_LABEL_DOT_NUM; i++) { + ext->text[ext->dot_end - i] = ext->dot_tmp[LV_LABEL_DOT_NUM - i]; + } +#else + uint32_t letter_i = ext->dot_end - LV_LABEL_DOT_NUM; + uint32_t byte_i = lv_txt_encoded_get_byte_id(ext->text, letter_i); + + /*Restore the characters*/ + uint8_t i = 0; + while(ext->dot_tmp[i] != '\0') { + ext->text[byte_i + i] = ext->dot_tmp[i]; + i++; + } +#endif + + ext->dot_end = LV_LABEL_DOT_END_INV; +} + +#if USE_LV_ANIMATION +static void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->offset.x = x; + lv_obj_invalidate(label); +} + +static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y) +{ + lv_label_ext_t * ext = lv_obj_get_ext_attr(label); + ext->offset.y = y; + lv_obj_invalidate(label); +} +#endif +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.h new file mode 100644 index 0000000..a2ee126 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_label.h @@ -0,0 +1,295 @@ +/** + * @file lv_rect.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LABEL != 0 + +#include "../lv_core/lv_obj.h" +#include "../lv_misc/lv_font.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/*Long mode behaviors. Used in 'lv_label_ext_t' */ +enum +{ + LV_LABEL_LONG_EXPAND, /*Expand the object size to the text size*/ + LV_LABEL_LONG_BREAK, /*Keep the object width, break the too long lines and expand the object height*/ + LV_LABEL_LONG_SCROLL, /*Expand the object size and scroll the text on the parent (move the label object)*/ + LV_LABEL_LONG_DOT, /*Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_ROLL, /*Keep the size and roll the text infinitely*/ + LV_LABEL_LONG_CROP, /*Keep the size and crop the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +/*Label align policy*/ +enum { + LV_LABEL_ALIGN_LEFT, + LV_LABEL_ALIGN_CENTER, + LV_LABEL_ALIGN_RIGHT, +}; +typedef uint8_t lv_label_align_t; + +/*Data of label*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + char * text; /*Text of the label*/ + lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/ +#if LV_TXT_UTF8 == 0 + char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#else + char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#endif + +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the text to display*/ +#endif + uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ + uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/ + lv_point_t offset; /*Text draw position offset*/ + uint8_t static_txt :1; /*Flag to indicate the text is static*/ + uint8_t align :2; /*Align type from 'lv_label_align_t'*/ + uint8_t recolor :1; /*Enable in-line letter re-coloring*/ + uint8_t expand :1; /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/ + uint8_t body_draw :1; /*Draw background body*/ +} lv_label_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text); + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text); + +/** + *Set a text ID which means a the same text but on different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +#if USE_LV_MULTI_LANG +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id); +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t *label, lv_label_align_t align); + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en); + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t *label, bool en); + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed); + +/** + * Set the style of an label + * @param label pointer to an label object + * @param style pointer to a style + */ +static inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style) +{ + lv_obj_set_style(label, style); +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label); + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label); +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label); + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label); + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label); + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t *label); + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t *label); + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); + +/** + * Get the style of an label object + * @param label pointer to an label object + * @return pointer to the label's style + */ +static inline lv_style_t* lv_label_get_style(const lv_obj_t *label) +{ + return lv_obj_get_style(label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LABEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.c new file mode 100644 index 0000000..29fc967 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.c @@ -0,0 +1,244 @@ +/** + * @file lv_led.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_led.h" +#if USE_LV_LED != 0 + +#include "../lv_themes/lv_theme.h" +#include "../lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ +#define LV_LED_WIDTH_DEF (LV_DPI / 3) +#define LV_LED_HEIGHT_DEF (LV_DPI / 3) +#define LV_LED_BRIGHT_OFF 100 +#define LV_LED_BRIGHT_ON 255 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("led create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_led = lv_obj_create(par, copy); + lv_mem_assert(new_led); + if(new_led == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_led); + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_led); + + /*Allocate the object type specific extended data*/ + lv_led_ext_t * ext = lv_obj_allocate_ext_attr(new_led, sizeof(lv_led_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->bright = LV_LED_BRIGHT_ON; + + lv_obj_set_signal_func(new_led, lv_led_signal); + lv_obj_set_design_func(new_led, lv_led_design); + + /*Init the new led object*/ + if(copy == NULL) { + lv_obj_set_size(new_led, LV_LED_WIDTH_DEF, LV_LED_HEIGHT_DEF); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_led_set_style(new_led, th->led); + } else { + lv_led_set_style(new_led, &lv_style_pretty_color); + } + } + /*Copy an existing object*/ + else { + lv_led_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->bright = copy_ext->bright; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_led); + } + + + LV_LOG_INFO("led created"); + + return new_led; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright) +{ + /*Set the brightness*/ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + if(ext->bright == bright) return; + + ext->bright = bright; + + /*Invalidate the object there fore it will be redrawn*/ + lv_obj_invalidate(led); +} + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led) +{ + lv_led_set_bright(led, LV_LED_BRIGHT_ON); +} + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led) +{ + lv_led_set_bright(led, LV_LED_BRIGHT_OFF); +} + + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led) +{ + uint8_t bright = lv_led_get_bright(led); + if(bright > (LV_LED_BRIGHT_OFF + LV_LED_BRIGHT_ON) >> 1) lv_led_off(led); + else lv_led_on(led); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led) +{ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + return ext->bright; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the leds + * @param led pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask area*/ + return ancestor_design_f(led, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Make darker colors in a temporary style according to the brightness*/ + lv_led_ext_t * ext = lv_obj_get_ext_attr(led); + lv_style_t * style = lv_obj_get_style(led); + + /* Store the real pointer because of 'lv_group' + * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style + * and to the real object style. It is important because of style change tricks below*/ + lv_style_t * style_ori_p = led->style_p; + + /*Create a temporal style*/ + lv_style_t leds_tmp; + memcpy(&leds_tmp, style, sizeof(leds_tmp)); + + /*Mix. the color with black proportionally with brightness*/ + leds_tmp.body.main_color = lv_color_mix(leds_tmp.body.main_color, LV_COLOR_BLACK, ext->bright); + leds_tmp.body.grad_color = lv_color_mix(leds_tmp.body.grad_color, LV_COLOR_BLACK, ext->bright); + leds_tmp.body.border.color = lv_color_mix(leds_tmp.body.border.color, LV_COLOR_BLACK, ext->bright); + + /*Set the current swidth according to brightness proportionally between LV_LED_BRIGHT_OFF and LV_LED_BRIGHT_ON*/ + uint16_t bright_tmp = ext->bright; + leds_tmp.body.shadow.width = ((bright_tmp - LV_LED_BRIGHT_OFF) * style->body.shadow.width) / (LV_LED_BRIGHT_ON - LV_LED_BRIGHT_OFF); + + led->style_p = &leds_tmp; + ancestor_design_f(led, mask, mode); + led->style_p = style_ori_p; /*Restore the ORIGINAL style pointer*/ + } + return true; +} + +/** + * Signal function of the led + * @param led pointer to a led object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(led, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_led"; + } + + return res; +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.h new file mode 100644 index 0000000..25e48a7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_led.h @@ -0,0 +1,116 @@ +/** + * @file lv_led.h + * + */ + +#ifndef LV_LED_H +#define LV_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LED != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct +{ + /*No inherited ext.*/ + /*New data for this type */ + uint8_t bright; /*Current brightness of the LED (0..255)*/ +} lv_led_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright); + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led); + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led); + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led); + +/** + * Set the style of a led + * @param led pointer to a led object + * @param style pointer to a style + */ +static inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style) +{ + lv_obj_set_style(led, style); +} + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led); + +/** + * Get the style of an led object + * @param led pointer to an led object + * @return pointer to the led's style + */ +static inline lv_style_t* lv_led_get_style(const lv_obj_t *led) +{ + return lv_obj_get_style(led); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LED*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LED_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.c new file mode 100644 index 0000000..0e16337 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.c @@ -0,0 +1,301 @@ +/** + * @file lv_line.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_line.h" + +#if USE_LV_LINE != 0 +#include "../lv_draw/lv_draw.h" +#include "../lv_misc/lv_math.h" +#include +#include + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("line create started"); + + /*Create a basic object*/ + lv_obj_t * new_line = lv_obj_create(par, copy); + lv_mem_assert(new_line); + if(new_line == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_line); + + /*Extend the basic object to line object*/ + lv_line_ext_t * ext = lv_obj_allocate_ext_attr(new_line, sizeof(lv_line_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->point_num = 0; + ext->point_array = NULL; + ext->auto_size = 1; + ext->y_inv = 0; + + lv_obj_set_design_func(new_line, lv_line_design); + lv_obj_set_signal_func(new_line, lv_line_signal); + + /*Init the new line*/ + if(copy == NULL) { + lv_obj_set_size(new_line, LV_DPI, LV_DPI); /*Auto size is enables, but set default size until no points are added*/ + lv_obj_set_style(new_line, NULL); /*Inherit parent's style*/ + lv_obj_set_click(new_line, false); + } + /*Copy an existing object*/ + else { + lv_line_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy)); + lv_line_set_y_invert(new_line, lv_line_get_y_invert(copy)); + lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy)); + lv_line_set_points(new_line, copy_ext->point_array, copy_ext->point_num); + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_line); + } + + + LV_LOG_INFO("line created"); + + return new_line; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + ext->point_array = point_a; + ext->point_num = point_num; + + if(point_num > 0 && ext->auto_size != 0) { + uint16_t i; + lv_coord_t xmax = LV_COORD_MIN; + lv_coord_t ymax = LV_COORD_MIN; + for(i = 0; i < point_num; i++) { + xmax = LV_MATH_MAX(point_a[i].x, xmax); + ymax = LV_MATH_MAX(point_a[i].y, ymax); + } + + lv_style_t * style = lv_line_get_style(line); + lv_obj_set_size(line, xmax + style->line.width, ymax + style->line.width); + } + + lv_obj_invalidate(line); +} + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + if(ext->auto_size == en) return; + + ext->auto_size = en == false ? 0 : 1; + + /*Refresh the object*/ + if(en) lv_line_set_points(line, ext->point_array, ext->point_num); +} + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + if(ext->y_inv == en) return; + + ext->y_inv = en == false ? 0 : 1; + + lv_obj_invalidate(line); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + return ext->auto_size == 0 ? false : true; +} + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line) +{ + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + return ext->y_inv == 0 ? false : true; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the lines + * @param line pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*A line never covers an area*/ + if(mode == LV_DESIGN_COVER_CHK) return false; + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_line_ext_t * ext = lv_obj_get_ext_attr(line); + + if(ext->point_num == 0 || ext->point_array == NULL) return false; + + lv_style_t * style = lv_obj_get_style(line); + lv_opa_t opa_scale = lv_obj_get_opa_scale(line); + lv_area_t area; + lv_obj_get_coords(line, &area); + lv_coord_t x_ofs = area.x1; + lv_coord_t y_ofs = area.y1; + lv_point_t p1; + lv_point_t p2; + lv_coord_t h = lv_obj_get_height(line); + uint16_t i; + + lv_style_t circle_style; /*If rounded...*/ + lv_style_copy(&circle_style, style); + circle_style.body.radius = LV_RADIUS_CIRCLE; + circle_style.body.main_color = style->line.color; + circle_style.body.grad_color = style->line.color; + circle_style.body.opa = style->line.opa; + lv_area_t circle_area; + + /*Read all points and draw the lines*/ + for(i = 0; i < ext->point_num - 1; i++) { + + p1.x = ext->point_array[i].x + x_ofs; + p2.x = ext->point_array[i + 1].x + x_ofs; + + if(ext->y_inv == 0) { + p1.y = ext->point_array[i].y + y_ofs; + p2.y = ext->point_array[i + 1].y + y_ofs; + } else { + p1.y = h - ext->point_array[i].y + y_ofs; + p2.y = h - ext->point_array[i + 1].y + y_ofs; + } + lv_draw_line(&p1, &p2, mask, style, opa_scale); + + /*Draw circle on the joints if enabled*/ + if(style->line.rounded) { + circle_area.x1 = p1.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.y1 = p1.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.x2 = p1.x + ((style->line.width - 1) >> 1); + circle_area.y2 = p1.y + ((style->line.width - 1) >> 1); + lv_draw_rect(&circle_area, mask, &circle_style, opa_scale); + } + } + + /*Draw circle on the last point too if enabled*/ + if(style->line.rounded) { + circle_area.x1 = p2.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.y1 = p2.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1); + circle_area.x2 = p2.x + ((style->line.width - 1) >> 1); + circle_area.y2 = p2.y + ((style->line.width - 1) >> 1); + lv_draw_rect(&circle_area, mask, &circle_style, opa_scale); + } + } + return true; +} + +/** + * Signal function of the line + * @param line pointer to a line object + * @param sign a signal type from lv_signal_t enum + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(line, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_line"; + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_line_get_style(line); + if(line->ext_size < style->line.width) line->ext_size = style->line.width; + } + + + return res; +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.h new file mode 100644 index 0000000..377d399 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_line.h @@ -0,0 +1,158 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LINE != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + const lv_point_t * point_array; /*Pointer to an array with the points of the line*/ + uint16_t point_num; /*Number of points in 'point_array' */ + uint8_t auto_size :1; /*1: set obj. width to x max and obj. height to y max */ + uint8_t y_inv :1; /*1: y == 0 will be on the bottom*/ +} lv_line_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num); + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en); + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en); + +#define lv_line_set_y_inv lv_line_set_y_invert /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */ + +/** + * Set the style of a line + * @param line pointer to a line object + * @param style pointer to a style + */ +static inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style) +{ + lv_obj_set_style(line, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @param upscale - + */ +static inline void lv_line_set_upscale(lv_obj_t * line, bool upcale) +{ + (void) line; + (void) upcale; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line); + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line); + +/** + * Get the style of an line object + * @param line pointer to an line object + * @return pointer to the line's style + */ +static inline lv_style_t* lv_line_get_style(const lv_obj_t *line) +{ + return lv_obj_get_style(line); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @return false + */ +static inline bool lv_line_get_upscale(const lv_obj_t * line) +{ + (void) line; + return false; +} + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LINE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LINE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.c new file mode 100644 index 0000000..b01172f --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.c @@ -0,0 +1,1052 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_list.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_list.h" +#if USE_LV_LIST != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_LIST_LAYOUT_DEF LV_LAYOUT_COL_M + +#if USE_LV_ANIMATION +# ifndef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 100 /*Animation time of focusing to the a list element [ms] (0: no animation) */ +# endif +#else +# undef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param); +static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param); +static void refr_btn_width(lv_obj_t * list); +static void lv_list_btn_single_selected(lv_obj_t *btn); +static bool lv_list_is_list_btn(lv_obj_t * list_btn); +static bool lv_list_is_list_img(lv_obj_t * list_btn); +static bool lv_list_is_list_label(lv_obj_t * list_btn); + +/********************** + * STATIC VARIABLES + **********************/ +#if USE_LV_IMG +static lv_signal_func_t img_signal; +#endif +static lv_signal_func_t label_signal; +static lv_signal_func_t ancestor_page_signal; +static lv_signal_func_t ancestor_btn_signal; +#if USE_LV_GROUP +/*Used to make the last clicked button pressed (selected) when the list become focused and `click_focus == 1`*/ +static lv_obj_t * last_clicked_btn; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("list create started"); + + /*Create the ancestor basic object*/ + lv_obj_t * new_list = lv_page_create(par, copy); + lv_mem_assert(new_list); + if(new_list == NULL) return NULL; + + if(ancestor_page_signal == NULL) ancestor_page_signal = lv_obj_get_signal_func(new_list); + + lv_list_ext_t * ext = lv_obj_allocate_ext_attr(new_list, sizeof(lv_list_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + // Important! + static lv_style_t img_btn_color; + lv_style_copy( &img_btn_color, &lv_style_plain); + img_btn_color.image.color = LV_COLOR_HEX(0xDDDDDD); + img_btn_color.image.intense = LV_OPA_50; + ext->style_img = &img_btn_color; + ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel; + ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr; + ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel; + ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr; + ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina; + ext->anim_time = LV_LIST_FOCUS_TIME; + ext->single_mode = false; + ext->size = 0; + +#if USE_LV_GROUP + ext->last_sel = NULL; + ext->selected_btn = NULL; +#endif + + lv_obj_set_signal_func(new_list, lv_list_signal); + + /*Init the new list object*/ + if(copy == NULL) { + lv_obj_set_size(new_list, 2 * LV_DPI, 3 * LV_DPI); + lv_page_set_scrl_layout(new_list, LV_LIST_LAYOUT_DEF); + lv_list_set_sb_mode(new_list, LV_SB_MODE_DRAG); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_list_set_style(new_list, LV_LIST_STYLE_BG, th->list.bg); + lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, th->list.scrl); + lv_list_set_style(new_list, LV_LIST_STYLE_SB, th->list.sb); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, th->list.btn.rel); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, th->list.btn.pr); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, th->list.btn.tgl_rel); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, th->list.btn.tgl_pr); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, th->list.btn.ina); + } else { + lv_list_set_style(new_list, LV_LIST_STYLE_BG, &lv_style_transp_fit); + lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, &lv_style_pretty); + } + } else { + lv_list_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + lv_obj_t * copy_btn = lv_list_get_next_btn(copy, NULL); + while(copy_btn) { + const void * img_src = NULL; +#if USE_LV_IMG + lv_obj_t * copy_img = lv_list_get_btn_img(copy_btn); + if(copy_img) img_src = lv_img_get_src(copy_img); +#endif + lv_list_add(new_list, img_src, lv_list_get_btn_text(copy_btn), lv_btn_get_action(copy_btn, LV_BTN_ACTION_CLICK)); + copy_btn = lv_list_get_next_btn(copy, copy_btn); + } + + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, copy_ext->styles_btn[LV_BTN_STATE_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, copy_ext->styles_btn[LV_BTN_STATE_PR]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, copy_ext->styles_btn[LV_BTN_STATE_INA]); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_list); + } + + + LV_LOG_INFO("list created"); + + + return new_list; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); + lv_list_ext_t * ext = lv_obj_get_ext_attr(obj); + ext->size = 0; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action) +{ + lv_style_t * style = lv_obj_get_style(list); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->size ++; + /*Create a list element with the image an the text*/ + lv_obj_t * liste; + liste = lv_btn_create(list, NULL); + + /*Save the original signal function because it will be required in `lv_list_btn_signal`*/ + if(ancestor_btn_signal == NULL) ancestor_btn_signal = lv_obj_get_signal_func(liste); + + /*Set the default styles*/ + lv_btn_set_style(liste, LV_BTN_STYLE_REL, ext->styles_btn[LV_BTN_STATE_REL]); + lv_btn_set_style(liste, LV_BTN_STYLE_PR, ext->styles_btn[LV_BTN_STATE_PR]); + lv_btn_set_style(liste, LV_BTN_STYLE_TGL_REL, ext->styles_btn[LV_BTN_STATE_TGL_REL]); + lv_btn_set_style(liste, LV_BTN_STYLE_TGL_PR, ext->styles_btn[LV_BTN_STATE_TGL_PR]); + lv_btn_set_style(liste, LV_BTN_STYLE_INA, ext->styles_btn[LV_BTN_STATE_INA]); + + lv_btn_set_action(liste, LV_BTN_ACTION_CLICK, rel_action); + lv_page_glue_obj(liste, true); + lv_btn_set_layout(liste, LV_LAYOUT_ROW_M); + lv_btn_set_fit(liste, false, true); + lv_obj_set_protect(liste, LV_PROTECT_PRESS_LOST); + lv_obj_set_signal_func(liste, lv_list_btn_signal); + + /*Make the size adjustment*/ + lv_coord_t w = lv_obj_get_width(list); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(list)); + lv_coord_t pad_hor_tot = style->body.padding.hor + style_scrl->body.padding.hor; + w -= pad_hor_tot * 2; + + lv_obj_set_width(liste, w); +#if USE_LV_IMG != 0 + lv_obj_t * img = NULL; + if(img_src) { + img = lv_img_create(liste, NULL); + lv_img_set_src(img, img_src); + lv_obj_set_style(img, ext->style_img); + lv_obj_set_click(img, false); + if(img_signal == NULL) img_signal = lv_obj_get_signal_func(img); + } +#endif + if(txt != NULL) { + lv_coord_t btn_hor_pad = ext->styles_btn[LV_BTN_STYLE_REL]->body.padding.hor; + lv_obj_t * label = lv_label_create(liste, NULL); + lv_label_set_text(label, txt); + lv_obj_set_click(label, false); + lv_label_set_long_mode(label, LV_LABEL_LONG_ROLL); + lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad); + if(label_signal == NULL) label_signal = lv_obj_get_signal_func(label); + } +#if USE_LV_GROUP + /* If this is the first item to be added to the list and the list is + * focussed, select it */ + { + lv_group_t *g = lv_obj_get_group(list); + if(ext->size == 1 && lv_group_get_focused(g) == list) { + lv_list_set_btn_selected(list, liste); + } + } +#endif + + return liste; +} + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(index >= ext->size) return false; + uint32_t count = 0; + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + while(e != NULL) { + if(count == index) { + lv_obj_del(e); + ext->size --; + return true; + } + e = lv_list_get_next_btn(list, e); + count ++; + } + return false; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + ext->single_mode = mode; +} + +#if USE_LV_GROUP + +/** + * Make a button selected + * @param list pointer to a list object + * @param btn pointer to a button to selectthe + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + if(ext->selected_btn) { + lv_btn_state_t s = lv_btn_get_state(ext->selected_btn); + if(s == LV_BTN_STATE_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_REL); + else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_REL); + } + + ext->selected_btn = btn; + if( btn != NULL ) { + ext->last_sel = btn; + } + + if(ext->selected_btn) { + lv_btn_state_t s = lv_btn_get_state(ext->selected_btn); + if(s == LV_BTN_STATE_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_PR); + else if(s == LV_BTN_STATE_TGL_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_PR); + + lv_page_focus(list, ext->selected_btn, ext->anim_time); + } +} + +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t * list, uint16_t anim_time) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + if(ext->anim_time == anim_time) return; + ext->anim_time = anim_time; +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t * list, lv_list_style_t type, lv_style_t * style) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + lv_btn_style_t btn_style_refr = LV_BTN_STYLE_REL; + lv_obj_t * btn; + + switch(type) { + case LV_LIST_STYLE_BG: + lv_page_set_style(list, LV_PAGE_STYLE_BG, style); + /*style change signal will call 'refr_btn_width' */ + break; + case LV_LIST_STYLE_SCRL: + lv_page_set_style(list, LV_PAGE_STYLE_SCRL, style); + refr_btn_width(list); + break; + case LV_LIST_STYLE_SB: + lv_page_set_style(list, LV_PAGE_STYLE_SB, style); + break; + case LV_LIST_STYLE_EDGE_FLASH: + lv_page_set_style(list, LV_PAGE_STYLE_EDGE_FLASH, style); + break; + case LV_LIST_STYLE_BTN_REL: + ext->styles_btn[LV_BTN_STATE_REL] = style; + btn_style_refr = LV_BTN_STYLE_REL; + break; + case LV_LIST_STYLE_BTN_PR: + ext->styles_btn[LV_BTN_STATE_PR] = style; + btn_style_refr = LV_BTN_STYLE_PR; + break; + case LV_LIST_STYLE_BTN_TGL_REL: + ext->styles_btn[LV_BTN_STATE_TGL_REL] = style; + btn_style_refr = LV_BTN_STYLE_TGL_REL; + break; + case LV_LIST_STYLE_BTN_TGL_PR: + ext->styles_btn[LV_BTN_STATE_TGL_PR] = style; + btn_style_refr = LV_BTN_STYLE_TGL_PR; + break; + case LV_LIST_STYLE_BTN_INA: + ext->styles_btn[LV_BTN_STATE_INA] = style; + btn_style_refr = LV_BTN_STYLE_INA; + break; + } + + + /*Refresh existing buttons' style*/ + if(type == LV_LIST_STYLE_BTN_PR || type == LV_LIST_STYLE_BTN_REL || + type == LV_LIST_STYLE_BTN_TGL_REL || type == LV_LIST_STYLE_BTN_TGL_PR || + type == LV_LIST_STYLE_BTN_INA) { + btn = lv_list_get_prev_btn(list, NULL); + while(btn != NULL) { + lv_btn_set_style(btn, btn_style_refr, ext->styles_btn[btn_style_refr]); + btn = lv_list_get_prev_btn(list, btn); + } + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + return (ext->single_mode); +} + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn) +{ + lv_obj_t * label = lv_list_get_btn_label(btn); + if(label == NULL) return ""; + return lv_label_get_text(label); +} + +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn) +{ + lv_obj_t * label = lv_obj_get_child(btn, NULL); + if(label == NULL) return NULL; + + while(lv_list_is_list_label(label) == false) { + label = lv_obj_get_child(btn, label); + if(label == NULL) break; + } + + return label; +} + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn) +{ +#if USE_LV_IMG != 0 + lv_obj_t * img = lv_obj_get_child(btn, NULL); + if(img == NULL) return NULL; + + while(lv_list_is_list_img(img) == false) { + img = lv_obj_get_child(btn, img); + if(img == NULL) break; + } + + return img; +#else + return NULL; +#endif +} + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn) +{ + /* Not a good practice but user can add/create objects to the lists manually. + * When getting the next button try to be sure that it is at least a button */ + + lv_obj_t * btn ; + lv_obj_t * scrl = lv_page_get_scrl(list); + + btn = lv_obj_get_child(scrl, prev_btn); + if(btn == NULL) return NULL; + + while(lv_list_is_list_btn(btn) == false) { + btn = lv_obj_get_child(scrl, btn); + if(btn == NULL) break; + } + + return btn; +} + + + + /** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn) +{ + /* Not a good practice but user can add/create objects to the lists manually. + * When getting the next button try to be sure that it is at least a button */ + + lv_obj_t * btn ; + lv_obj_t * scrl = lv_page_get_scrl(list); + + btn = lv_obj_get_child_back(scrl, prev_btn); + if(btn == NULL) return NULL; + + while(lv_list_is_list_btn(btn) == false) { + btn = lv_obj_get_child_back(scrl, btn); + if(btn == NULL) break; + } + + return btn; +} + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn) +{ + int index = 0; + if( list == NULL ){ + /* no list provided, assuming btn is part of a list */ + list = lv_obj_get_parent(lv_obj_get_parent(btn)); + } + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + while(e != NULL) { + if(e == btn) { + return index; + } + index ++; + e = lv_list_get_next_btn(list, e); + } + return -1; +} + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->size; +} + +#if USE_LV_GROUP +/** + * Get the currently selected button + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->selected_btn; +} + +#endif + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t * list) +{ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + return ext->anim_time; +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type) +{ + lv_style_t * style = NULL; + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + + switch(type) { + case LV_LIST_STYLE_BG: + style = lv_page_get_style(list, LV_PAGE_STYLE_BG); + break; + case LV_LIST_STYLE_SCRL: + style = lv_page_get_style(list, LV_PAGE_STYLE_SB); + break; + case LV_LIST_STYLE_SB: + style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); + break; + case LV_LIST_STYLE_EDGE_FLASH: + style = lv_page_get_style(list, LV_PAGE_STYLE_EDGE_FLASH); + break; + case LV_LIST_STYLE_BTN_REL: + style = ext->styles_btn[LV_BTN_STATE_REL]; + break; + case LV_LIST_STYLE_BTN_PR: + style = ext->styles_btn[LV_BTN_STATE_PR]; + break; + case LV_LIST_STYLE_BTN_TGL_REL: + style = ext->styles_btn[LV_BTN_STATE_TGL_REL]; + break; + case LV_LIST_STYLE_BTN_TGL_PR: + style = ext->styles_btn[LV_BTN_STATE_TGL_PR]; + break; + case LV_LIST_STYLE_BTN_INA: + style = ext->styles_btn[LV_BTN_STATE_INA]; + break; + default: + style = NULL; + break; + } + + return style; +} +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list) +{ + /*Search the first list element which 'y' coordinate is below the parent + * and position the list to show this element on the bottom*/ + lv_obj_t * scrl = lv_page_get_scrl(list); + lv_obj_t * e; + lv_obj_t * e_prev = NULL; + e = lv_list_get_prev_btn(list, NULL); + while(e != NULL) { + if(e->coords.y2 <= list->coords.y2) { + if(e_prev != NULL) { + lv_coord_t new_y = lv_obj_get_height(list) - (lv_obj_get_y(e_prev) + lv_obj_get_height(e_prev)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->anim_time == 0) { + lv_obj_set_y(scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_LIST_FOCUS_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + } + break; + } + e_prev = e; + e = lv_list_get_prev_btn(list, e); + } +} + +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list) +{ + /*Search the first list element which 'y' coordinate is above the parent + * and position the list to show this element on the top*/ + lv_obj_t * scrl = lv_page_get_scrl(list); + lv_obj_t * e; + e = lv_list_get_prev_btn(list, NULL); + while(e != NULL) { + if(e->coords.y1 < list->coords.y1) { + lv_coord_t new_y = -lv_obj_get_y(e); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->anim_time == 0) { + lv_obj_set_y(scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_LIST_FOCUS_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + +#endif + } + break; + } + e = lv_list_get_prev_btn(list, e); + } +} + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t * btn, bool anim_en) +{ + +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + + lv_page_focus(list, btn, anim_en == false ? 0 : lv_list_get_anim_time(list)); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the list + * @param list pointer to a list object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_page_signal(list, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CORD_CHG) { + /*Be sure the width of the buttons are correct*/ + lv_coord_t w = lv_obj_get_width(list); + if(w != lv_area_get_width(param)) { /*Width changed*/ + refr_btn_width(list); + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*Because of the possible change of horizontal and vertical padding refresh buttons width */ + refr_btn_width(list); + } else if(sign == LV_SIGNAL_FOCUS) { + +#if USE_LV_GROUP + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*With ENCODER select the first button only in edit mode*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + lv_group_t * g = lv_obj_get_group(list); + if(lv_group_get_editing(g)) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->last_sel) { + /* Select the last used button */ + lv_list_set_btn_selected(list, ext->last_sel); + } + else { + /*Get the first button and mark it as selected*/ + lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL)); + } + } else { + lv_list_set_btn_selected(list, NULL); + } + } + /*Else select the clicked button*/ + else { + /*Mark the last clicked button (if any) as selected because it triggered the focus*/ + if(last_clicked_btn) { + lv_list_set_btn_selected(list, last_clicked_btn); + } else { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->last_sel) { + /* Select the last used button */ + lv_list_set_btn_selected(list, ext->last_sel); + } + else { + /*Get the first button and mark it as selected*/ + lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL)); + } + } + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { + +#if USE_LV_GROUP + /*De-select the selected btn*/ + lv_list_set_btn_selected(list, NULL); + last_clicked_btn = NULL; /*button click will be set if click happens before focus*/ + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->selected_btn = NULL; +#endif + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_CONTROLL) { + +#if USE_LV_GROUP + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + /*If there is a valid selected button the make the previous selected*/ + if(ext->selected_btn) { + lv_obj_t * btn_prev = lv_list_get_next_btn(list, ext->selected_btn); + if(btn_prev) lv_list_set_btn_selected(list, btn_prev); + } + /*If there is no selected button the make the first selected*/ + else { + lv_obj_t * btn = lv_list_get_next_btn(list, NULL); + if(btn) lv_list_set_btn_selected(list, btn); /*If there are no buttons on the list then there is no first button*/ + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + /*If there is a valid selected button the make the next selected*/ + if(ext->selected_btn != NULL) { + lv_obj_t * btn_next = lv_list_get_prev_btn(list, ext->selected_btn); + if(btn_next) lv_list_set_btn_selected(list, btn_next); + } + /*If there is no selected button the make the first selected*/ + else { + lv_obj_t * btn = lv_list_get_next_btn(list, NULL); + if(btn) lv_list_set_btn_selected(list, btn); + } + } else if(c == LV_GROUP_KEY_ENTER) { + /*Get the 'pressed' button*/ + lv_obj_t * btn = NULL; + btn = lv_list_get_prev_btn(list, btn); + while(btn != NULL) { + if(lv_btn_get_state(btn) == LV_BTN_STATE_PR) break; + btn = lv_list_get_prev_btn(list, btn); + } + + if(btn != NULL) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->last_sel = btn; + lv_action_t rel_action; + rel_action = lv_btn_get_action(btn, LV_BTN_ACTION_CLICK); + if(rel_action != NULL) rel_action(btn); + } + } +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_list"; + } + return res; +} + + +/** + * Signal function of the list buttons + * @param btn pointer to a button on the list + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_btn_signal(btn, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_RELEASED) { + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->page.scroll_prop_ip = 0; + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(list); + if(lv_group_get_focused(g) == list && lv_indev_is_dragging(lv_indev_get_act()) == false) { + /* Is the list is focused then be sure only the button being released + * has a pressed state to indicate the selected state on the list*/ + lv_obj_t * btn_i = lv_list_get_prev_btn(list, NULL); + while(btn_i) { + lv_btn_state_t s = lv_btn_get_state(btn_i); + if(s == LV_BTN_STATE_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_REL); + else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_TGL_REL); + btn_i = lv_list_get_prev_btn(list, btn_i); + } + + /*Make the released button "selected"*/ + lv_list_set_btn_selected(list, btn); + } + + /* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus + * to mark it as selected (pressed state)*/ + last_clicked_btn = btn; +#endif + if(lv_indev_is_dragging(lv_indev_get_act()) == false && ext->single_mode) + { + lv_list_btn_single_selected(btn); + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + ext->page.scroll_prop_ip = 0; + } + else if(sign == LV_SIGNAL_CLEANUP) { + +#if USE_LV_GROUP + lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_obj_t * sel = lv_list_get_btn_selected(list); + if(sel == btn) lv_list_set_btn_selected(list, lv_list_get_next_btn(list, btn)); +#endif + } + + + return res; +} + +static void refr_btn_width(lv_obj_t * list) +{ + lv_style_t * style = lv_list_get_style(list, LV_LIST_STYLE_BG); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(list)); + lv_coord_t w = lv_obj_get_width(list); + lv_coord_t btn_w = w - (style->body.padding.hor + style_scrl->body.padding.hor) * 2; + + lv_obj_t * btn = lv_list_get_prev_btn(list, NULL); + while(btn) { + /*Make the size adjustment for each buttons*/ + if(lv_obj_get_width(btn) != btn_w) { + lv_obj_set_width(btn, btn_w); + /*Set the label size to roll its text*/ + lv_obj_t * label = lv_list_get_btn_label(btn); + lv_obj_set_width(label, btn->coords.x2 - label->coords.x1); + lv_label_set_text(label, NULL); + } + btn = lv_list_get_prev_btn(list, btn); + } +} + +/** + * Make a single button selected in the list, deselect others, should be called in list btns call back. + * @param btn pointer to the currently pressed list btn object + */ +static void lv_list_btn_single_selected(lv_obj_t *btn) +{ + lv_obj_t *list = lv_obj_get_parent(lv_obj_get_parent(btn)); + + lv_obj_t * e = lv_list_get_next_btn(list, NULL); + do + { + if(e == btn) + { + lv_btn_set_state(e, LV_BTN_STATE_TGL_REL); + } + else + { + lv_btn_set_state(e, LV_BTN_STATE_REL); + } + e = lv_list_get_next_btn(list, e); + } while (e != NULL); +} + +/** + * Check if this is really a list button or another object. + * @param list_btn List button + */ +static bool lv_list_is_list_btn(lv_obj_t * list_btn) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_btn, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_btn")) + return true; + } + return false; +} + +/** + * Check if this is really a list label or another object. + * @param list_label List label + */ +static bool lv_list_is_list_label(lv_obj_t * list_label) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_label, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_label")) + return true; + } + return false; +} + +/** + * Check if this is really a list image or another object. + * @param list_image List image + */ +static bool lv_list_is_list_img(lv_obj_t * list_img) +{ + lv_obj_type_t type; + + lv_obj_get_type(list_img, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], "lv_img")) + return true; + } + return false; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.h new file mode 100644 index 0000000..01ebb19 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_list.h @@ -0,0 +1,336 @@ +/** + * @file lv_list.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_BTN == 0 +#error "lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "../lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t anim_time; /*Scroll animation time*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/ + lv_style_t *style_img; /*Style of the list element images on buttons*/ + uint32_t size; /*the number of items(buttons) in the list*/ + bool single_mode; /* whether single selected mode is enabled */ +#if USE_LV_GROUP + lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ + lv_obj_t * selected_btn; /* The button is currently being selected*/ +#endif +} lv_list_ext_t; + +enum { + LV_LIST_STYLE_BG, + LV_LIST_STYLE_SCRL, + LV_LIST_STYLE_SB, + LV_LIST_STYLE_EDGE_FLASH, + LV_LIST_STYLE_BTN_REL, + LV_LIST_STYLE_BTN_PR, + LV_LIST_STYLE_BTN_TGL_REL, + LV_LIST_STYLE_BTN_TGL_PR, + LV_LIST_STYLE_BTN_INA, +}; +typedef uint8_t lv_list_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action); + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode); + +#if USE_LV_GROUP + +/** + * Make a button selected. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @param btn pointer to a button to select + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn); +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time); + +/** + * Set the scroll bar mode of a list + * @param list pointer to a list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(list, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll. + * @param list pointer to a List + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en) +{ + lv_page_set_scroll_propagation(list, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param list pointer to a List + * @param en true or false to enable/disable end flash + */ +static inline void lv_list_set_edge_flash(lv_obj_t * list, bool en) +{ + lv_page_set_edge_flash(list, en); +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list); + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn); +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn); + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn); + +/** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn); + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list); + +#if USE_LV_GROUP +/** + * Get the currently selected button. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); +#endif + + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t *list); + + +/** + * Get the scroll bar mode of a list + * @param list pointer to a list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list) +{ + return lv_page_get_sb_mode(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_scroll_propagation(lv_obj_t * list) +{ + return lv_page_get_scroll_propagation(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_edge_flash(lv_obj_t * list) +{ + return lv_page_get_edge_flash(list); +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list); +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list); + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t *btn, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LIST_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.c new file mode 100644 index 0000000..4d78d8e --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.c @@ -0,0 +1,382 @@ +/** + * @file lv_lmeter.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_lmeter.h" +#if USE_LV_LMETER != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_core/lv_group.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_LMETER_LINE_UPSCALE 5 /*2^x upscale of line to make rounding*/ +#define LV_LMETER_LINE_UPSCALE_MASK ((1 << LV_LMETER_LINE_UPSCALE) - 1) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param); +static lv_coord_t lv_lmeter_coord_round(int32_t x); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("line meter create started"); + + /*Create the ancestor of line meter*/ + lv_obj_t * new_lmeter = lv_obj_create(par, copy); + lv_mem_assert(new_lmeter); + if(new_lmeter == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_lmeter); + + /*Allocate the line meter type specific extended data*/ + lv_lmeter_ext_t * ext = lv_obj_allocate_ext_attr(new_lmeter, sizeof(lv_lmeter_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->min_value = 0; + ext->max_value = 100; + ext->cur_value = 0; + ext->line_cnt = 21; /*Odd scale number looks better*/ + ext->scale_angle = 240; /*(scale_num - 1) * N looks better */ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_lmeter, lv_lmeter_signal); + lv_obj_set_design_func(new_lmeter, lv_lmeter_design); + + /*Init the new line meter line meter*/ + if(copy == NULL) { + lv_obj_set_size(new_lmeter, LV_DPI, LV_DPI); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_lmeter_set_style(new_lmeter, th->lmeter); + } else { + lv_lmeter_set_style(new_lmeter, &lv_style_pretty_color); + } + } + /*Copy an existing line meter*/ + else { + lv_lmeter_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->scale_angle = copy_ext->scale_angle; + ext->line_cnt = copy_ext->line_cnt; + ext->min_value = copy_ext->min_value; + ext->max_value = copy_ext->max_value; + ext->cur_value = copy_ext->cur_value; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_lmeter); + } + + LV_LOG_INFO("line meter created"); + + return new_lmeter; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t * lmeter, int16_t value) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->cur_value == value) return; + + ext->cur_value = value > ext->max_value ? ext->max_value : value; + ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value; + lv_obj_invalidate(lmeter); +} + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t * lmeter, int16_t min, int16_t max) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->min_value == min && ext->max_value == max) return; + + ext->max_value = max; + ext->min_value = min; + if(ext->cur_value > max) { + ext->cur_value = max; + lv_lmeter_set_value(lmeter, ext->cur_value); + } + if(ext->cur_value < min) { + ext->cur_value = min; + lv_lmeter_set_value(lmeter, ext->cur_value); + } + lv_obj_invalidate(lmeter); +} + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + if(ext->scale_angle == angle && ext->line_cnt == line_cnt) return; + + ext->scale_angle = angle; + ext->line_cnt = line_cnt; + + lv_obj_invalidate(lmeter); +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->cur_value; +} + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->min_value; +} + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->max_value; +} + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->line_cnt ; +} + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter) +{ + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + return ext->scale_angle; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the line meters + * @param lmeter pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter); + lv_style_t * style = lv_obj_get_style(lmeter); + lv_opa_t opa_scale = lv_obj_get_opa_scale(lmeter); + lv_style_t style_tmp; + memcpy(&style_tmp, style, sizeof(lv_style_t)); + + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(lmeter); + if(lv_group_get_focused(g) == lmeter) { + style_tmp.line.width += 1; + } +#endif + + lv_coord_t r_out = lv_obj_get_width(lmeter) / 2; + lv_coord_t r_in = r_out - style->body.padding.hor; + if(r_in < 1) r_in = 1; + + lv_coord_t x_ofs = lv_obj_get_width(lmeter) / 2 + lmeter->coords.x1; + lv_coord_t y_ofs = lv_obj_get_height(lmeter) / 2 + lmeter->coords.y1; + int16_t angle_ofs = 90 + (360 - ext->scale_angle) / 2; + int16_t level = (int32_t)((int32_t)(ext->cur_value - ext->min_value) * ext->line_cnt) / (ext->max_value - ext->min_value); + uint8_t i; + + style_tmp.line.color = style->body.main_color; + + /*Calculate every coordinate in a bigger size to make rounding later*/ + r_out = r_out << LV_LMETER_LINE_UPSCALE; + r_in = r_in << LV_LMETER_LINE_UPSCALE; + + for(i = 0; i < ext->line_cnt; i++) { + /*Calculate the position a scale label*/ + int16_t angle = (i * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs; + + lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> LV_TRIGO_SHIFT; + lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> LV_TRIGO_SHIFT; + lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> LV_TRIGO_SHIFT; + lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> LV_TRIGO_SHIFT; + + /*Rounding*/ + x_out = lv_lmeter_coord_round(x_out); + x_in = lv_lmeter_coord_round(x_in); + y_out = lv_lmeter_coord_round(y_out); + y_in = lv_lmeter_coord_round(y_in); + + lv_point_t p1; + lv_point_t p2; + + p2.x = x_in + x_ofs; + p2.y = y_in + y_ofs; + + p1.x = x_out + x_ofs; + p1.y = y_out + y_ofs; + + if(i >= level) style_tmp.line.color = style->line.color; + else { + style_tmp.line.color = lv_color_mix(style->body.grad_color, style->body.main_color, (255 * i) / ext->line_cnt); + } + + lv_draw_line(&p1, &p2, mask, &style_tmp, opa_scale); + } + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the line meter + * @param lmeter pointer to a line meter object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(lmeter, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_refresh_ext_size(lmeter); + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_lmeter_get_style(lmeter); + lmeter->ext_size = LV_MATH_MAX(lmeter->ext_size, style->line.width); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_lmeter"; + } + + return res; +} + +/** + * Round a coordinate which is upscaled (>=x.5 -> x + 1; x) + * @param x a coordinate which is greater then it should be + * @return the downscaled and rounded coordinate (+-1) + */ +static lv_coord_t lv_lmeter_coord_round(int32_t x) +{ +#if LV_LMETER_LINE_UPSCALE > 0 + bool was_negative = false; + if(x < 0) { + was_negative = true; + x = -x; + } + + x = (x >> LV_LMETER_LINE_UPSCALE) + ((x & LV_LMETER_LINE_UPSCALE_MASK) >> (LV_LMETER_LINE_UPSCALE - 1)); + + if(was_negative) x = -x; + + return x; +#else + return x; +#endif +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.h new file mode 100644 index 0000000..0235d34 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_lmeter.h @@ -0,0 +1,153 @@ +/** + * @file lv_lmeter.h + * + */ + +#ifndef LV_LMETER_H +#define LV_LMETER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_LMETER != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of line meter*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ + uint8_t line_cnt; /*Count of lines */ + int16_t cur_value; + int16_t min_value; + int16_t max_value; +} lv_lmeter_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value); + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max); + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt); + +/** + * Set the styles of a line meter + * @param lmeter pointer to a line meter object + * @param bg set the style of the line meter + */ +static inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg) +{ + lv_obj_set_style(lmeter, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t *lmeter); + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter); + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter); + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter); + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter); + +/** + * Get the style of a line meter + * @param lmeter pointer to a line meter object + * @return pointer to the line meter's style + */ +static inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter) +{ + return lv_obj_get_style(lmeter); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LMETER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LMETER_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.c new file mode 100644 index 0000000..4dcacdd --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_mbox.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_mbox.h" +#if USE_LV_MBOX != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +#if USE_LV_ANIMATION +# ifndef LV_MBOX_CLOSE_ANIM_TIME +# define LV_MBOX_CLOSE_ANIM_TIME 200 /*List close animation time) */ +# endif +#else +# undef LV_MBOX_CLOSE_ANIM_TIME +# define LV_MBOX_CLOSE_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param); +static void mbox_realign(lv_obj_t * mbox); +static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt); +#if USE_LV_ANIMATION +static void lv_mbox_close_end_cb(lv_obj_t * mbox); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("mesasge box create started"); + + /*Create the ancestor message box*/ + lv_obj_t * new_mbox = lv_cont_create(par, copy); + lv_mem_assert(new_mbox); + if(new_mbox == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_mbox); + + /*Allocate the message box type specific extended data*/ + lv_mbox_ext_t * ext = lv_obj_allocate_ext_attr(new_mbox, sizeof(lv_mbox_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->text = NULL; + ext->btnm = NULL; + ext->anim_time = LV_MBOX_CLOSE_ANIM_TIME; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_mbox, lv_mbox_signal); + + /*Init the new message box message box*/ + if(copy == NULL) { + ext->text = lv_label_create(new_mbox, NULL); + lv_label_set_align(ext->text, LV_LABEL_ALIGN_CENTER); + lv_label_set_long_mode(ext->text, LV_LABEL_LONG_BREAK); + lv_label_set_text(ext->text, "Message"); + + lv_cont_set_layout(new_mbox, LV_LAYOUT_COL_M); + lv_cont_set_fit(new_mbox, false, true); + lv_obj_set_width(new_mbox, LV_HOR_RES / 2); + lv_obj_align(new_mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, th->mbox.bg); + } else { + lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, &lv_style_pretty); + } + + } + /*Copy an existing message box*/ + else { + lv_mbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + ext->text = lv_label_create(new_mbox, copy_ext->text); + + /*Copy the buttons and the label on them*/ + if(copy_ext->btnm) ext->btnm = lv_btnm_create(new_mbox, copy_ext->btnm); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_mbox); + } + + + LV_LOG_INFO("mesasge box created"); + + return new_mbox; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char ** btn_map, lv_btnm_action_t action) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + /*Create a button matrix if not exists yet*/ + if(ext->btnm == NULL) { + ext->btnm = lv_btnm_create(mbox, NULL); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_BG, th->mbox.btn.bg); + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_REL, th->mbox.btn.rel); + lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_PR, th->mbox.btn.pr); + } else { + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, &lv_style_transp_fit); + } + } + + lv_btnm_set_map(ext->btnm, btn_map); + if(action == NULL) lv_btnm_set_action(ext->btnm, lv_mbox_close_action); /*Set a default action anyway*/ + else lv_btnm_set_action(ext->btnm, action); + + mbox_realign(mbox); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + lv_label_set_text(ext->text, txt); + + mbox_realign(mbox); +} + + +/** + * Stop the action to call when button is released + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + * @param pointer to an 'lv_btnm_action_t' action + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + lv_btnm_set_action(ext->btnm, action); +} + + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + + ext->anim_time = anim_time; +} + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay) +{ +#if USE_LV_ANIMATION + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(ext->anim_time != 0) { + /*Add shrinking animations*/ + lv_obj_animate(mbox, LV_ANIM_GROW_H | LV_ANIM_OUT, ext->anim_time, delay, NULL); + lv_obj_animate(mbox, LV_ANIM_GROW_V | LV_ANIM_OUT, ext->anim_time, delay, lv_mbox_close_end_cb); + + /*Disable fit to let shrinking work*/ + lv_cont_set_fit(mbox, false, false); + } else { + lv_obj_animate(mbox, LV_ANIM_NONE, ext->anim_time, delay, lv_mbox_close_end_cb); + } +#else + (void)delay; /*Unused*/ + lv_obj_del(mbox); +#endif +} + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox) +{ +#if USE_LV_ANIMATION + lv_anim_del(mbox, NULL); +#else + (void)mbox; /*Unused*/ +#endif +} + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t * mbox, lv_mbox_style_t type, lv_style_t * style) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + switch(type) { + case LV_MBOX_STYLE_BG: + lv_obj_set_style(mbox, style); + break; + case LV_MBOX_STYLE_BTN_BG: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, style); + break; + case LV_MBOX_STYLE_BTN_REL: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_REL, style); + break; + case LV_MBOX_STYLE_BTN_PR: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_MBOX_STYLE_BTN_TGL_REL: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_MBOX_STYLE_BTN_TGL_PR: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_MBOX_STYLE_BTN_INA: + lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_INA, style); + break; + } + + mbox_realign(mbox); + +} + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(ext->btnm) + lv_btnm_set_recolor(ext->btnm, en); +} + +void lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if (ext->text) + lv_label_set_recolor(ext->text, en); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + return lv_label_get_text(ext->text); +} + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn) +{ + lv_obj_t * mbox = lv_obj_get_parent(btn); + + return mbox; +} + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + return ext->anim_time; +} + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t * mbox, lv_mbox_style_t type) +{ + lv_style_t * style = NULL; + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + switch(type) { + case LV_MBOX_STYLE_BG: + style = lv_obj_get_style(mbox); + break; + case LV_MBOX_STYLE_BTN_BG: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BG); + break; + case LV_MBOX_STYLE_BTN_REL: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_REL); + break; + case LV_MBOX_STYLE_BTN_PR: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_PR); + break; + case LV_MBOX_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_MBOX_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR); + break; + case LV_MBOX_STYLE_BTN_INA: + style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_INA); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + if(!ext->btnm) + return false; + + return lv_btnm_get_recolor(ext->btnm); +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the message box + * @param mbox pointer to a message box object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /*Translate LV_GROUP_KEY_UP/DOWN to LV_GROUP_KEY_LEFT/RIGHT */ + char c_trans = 0; + if(sign == LV_SIGNAL_CONTROLL) { + c_trans = *((char *)param); + if(c_trans == LV_GROUP_KEY_DOWN) c_trans = LV_GROUP_KEY_LEFT; + if(c_trans == LV_GROUP_KEY_UP) c_trans = LV_GROUP_KEY_RIGHT; + + param = &c_trans; + } + + /* Include the ancient signal function */ + res = ancestor_signal(mbox, sign, param); + if(res != LV_RES_OK) return res; + + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + if(sign == LV_SIGNAL_CORD_CHG) { + if(lv_obj_get_width(mbox) != lv_area_get_width(param)) { + mbox_realign(mbox); + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + mbox_realign(mbox); + + } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS || + sign == LV_SIGNAL_CONTROLL || sign == LV_SIGNAL_GET_EDITABLE) { + if(ext->btnm) { + ext->btnm->signal_func(ext->btnm, sign, param); + } + + /* The button matrix with ENCODER input supposes it's in a group but in this case it isn't (Only the message box's container) + * So so some actions here instead*/ + if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_indev_t * indev = lv_indev_get_act(); + lv_hal_indev_type_t indev_type = lv_indev_get_type(indev); + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigation mode don't select any button but in edit mode select the fist*/ + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btnm); + if(lv_group_get_editing(lv_obj_get_group(mbox))) btnm_ext->btn_id_pr = 0; + else btnm_ext->btn_id_pr = LV_BTNM_PR_NONE; + } +#endif + } + + + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_mbox"; + } + + return res; +} + +/** + * Resize the button holder to fit + * @param mbox pointer to message box object + */ +static void mbox_realign(lv_obj_t * mbox) +{ + lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox); + + lv_style_t * style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BG); + lv_coord_t w = lv_obj_get_width(mbox) - 2 * style->body.padding.hor; + + if(ext->text) { + lv_obj_set_width(ext->text, w); + } + + if(ext->btnm) { + lv_style_t * btn_bg_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_BG); + lv_style_t * btn_rel_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_REL); + lv_coord_t font_h = lv_font_get_height(btn_rel_style->text.font); + lv_obj_set_size(ext->btnm, w, font_h + 2 * btn_rel_style->body.padding.ver + 2 * btn_bg_style->body.padding.ver); + } +} + +static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt) +{ + lv_obj_t * mbox = lv_mbox_get_from_btn(btn); + + if(txt[0] != '\0') { + lv_mbox_start_auto_close(mbox, 0); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +#if USE_LV_ANIMATION +static void lv_mbox_close_end_cb(lv_obj_t * mbox) +{ + lv_obj_del(mbox); +} +#endif +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.h new file mode 100644 index 0000000..ae5c76a --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_mbox.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MBOX_H +#define LV_MBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_MBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#if USE_LV_BTNM == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btnm.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of message box*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *text; /*Text of the message box*/ + lv_obj_t *btnm; /*Button matrix for the buttons*/ + uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ +} lv_mbox_ext_t; + +enum { + LV_MBOX_STYLE_BG, + LV_MBOX_STYLE_BTN_BG, + LV_MBOX_STYLE_BTN_REL, + LV_MBOX_STYLE_BTN_PR, + LV_MBOX_STYLE_BTN_TGL_REL, + LV_MBOX_STYLE_BTN_TGL_PR, + LV_MBOX_STYLE_BTN_INA, +}; +typedef uint8_t lv_mbox_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt); + +/** + * Stop the action to call when button is released + * @param mbox pointer to a message box object + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action); + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time); + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay); + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox); + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`. + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en); + +void lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox); + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn); + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox); + + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type); + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + + +#endif /*USE_LV_MBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MBOX_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx.mk b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx.mk new file mode 100644 index 0000000..d35252b --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx.mk @@ -0,0 +1,36 @@ +CSRCS += lv_arc.c +CSRCS += lv_bar.c +CSRCS += lv_cb.c +CSRCS += lv_ddlist.c +CSRCS += lv_kb.c +CSRCS += lv_line.c +CSRCS += lv_mbox.c +CSRCS += lv_preload.c +CSRCS += lv_roller.c +CSRCS += lv_table.c +CSRCS += lv_tabview.c +CSRCS += lv_tileview.c +CSRCS += lv_btn.c +CSRCS += lv_calendar.c +CSRCS += lv_chart.c +CSRCS += lv_canvas.c +CSRCS += lv_gauge.c +CSRCS += lv_label.c +CSRCS += lv_list.c +CSRCS += lv_slider.c +CSRCS += lv_ta.c +CSRCS += lv_spinbox.c +CSRCS += lv_btnm.c +CSRCS += lv_cont.c +CSRCS += lv_img.c +CSRCS += lv_imgbtn.c +CSRCS += lv_led.c +CSRCS += lv_lmeter.c +CSRCS += lv_page.c +CSRCS += lv_sw.c +CSRCS += lv_win.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx +VPATH += :$(LVGL_DIR)/lvgl/lv_objx + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx" diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c new file mode 100644 index 0000000..f605450 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.c @@ -0,0 +1,231 @@ +/** + * @file lv_templ.c + * + */ + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +/********************* + * INCLUDES + *********************/ +//#include "lv_templ.h" /*TODO uncomment this*/ +#if USE_LV_TEMPL != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a template object + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("template create started"); + + /*Create the ancestor of template*/ + /*TODO modify it to the ancestor create function */ + lv_obj_t * new_templ = lv_ANCESTOR_create(par, copy); + lv_mem_assert(new_templ); + if(new_templ == NULL) return NULL; + + /*Allocate the template type specific extended data*/ + lv_templ_ext_t * ext = lv_obj_allocate_ext_attr(new_templ, sizeof(lv_templ_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_templ); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_templ); + + /*Initialize the allocated 'ext' */ + ext->xyz = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_templ, lv_templ_signal); + lv_obj_set_design_func(new_templ, lv_templ_design); + + /*Init the new template template*/ + if(copy == NULL) { + + } + /*Copy an existing template*/ + else { + lv_templ_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_templ); + } + + LV_LOG_INFO("template created"); + + return new_templ; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/* + * New object specific "add" or "remove" functions come here + */ + + +/*===================== + * Setter functions + *====================*/ + +/* + * New object specific "set" functions come here + */ + + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t * style) +{ + lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ); + + switch(type) { + case LV_TEMPL_STYLE_X: + break; + case LV_TEMPL_STYLE_Y: + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/* + * New object specific "get" functions come here + */ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type) +{ + lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ); + lv_style_t * style = NULL; + + switch(type) { + case LV_TEMPL_STYLE_X: + style = NULL; /*Replace NULL with a pointer to the style*/ + case LV_TEMPL_STYLE_Y: + style = NULL; /*Replace NULL with a pointer to the style*/ + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the templates + * @param templ pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the template + * @param templ pointer to a template object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(templ, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_templ"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h new file mode 100644 index 0000000..ab6d090 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_objx_templ.h @@ -0,0 +1,111 @@ +/** + * @file lv_templ.h + * + */ + + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TEMPL != 0 + +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_templ_ext_t; + + +/*Styles*/ +enum { + LV_TEMPL_STYLE_X, + LV_TEMPL_STYLE_Y, +}; +typedef uint8_t lv_templ_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a template objects + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TEMPL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.c new file mode 100644 index 0000000..65dcb35 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.c @@ -0,0 +1,1205 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_page.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_objx/lv_page.h" +#if USE_LV_PAGE != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_core/lv_refr.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_PAGE_SB_MIN_SIZE (LV_DPI / 8) +#define LV_PAGE_SCROLL_ANIM_TIME 200 /*[ms] Scroll anim time on `lv_page_scroll_up/down/left/rigth`*/ +#define LV_PAGE_END_FLASH_SIZE (LV_DPI / 4) +#define LV_PAGE_END_ANIM_TIME 300 +#define LV_PAGE_END_ANIM_WAIT_TIME 300 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_page_sb_refresh(lv_obj_t * page); +static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param); +static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +#if USE_LV_ANIMATION +static void edge_flash_anim(void * page, int32_t v); +static void edge_flash_anim_end(void * page); +#endif + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("page create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_page = lv_cont_create(par, copy); + lv_mem_assert(new_page); + if(new_page == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_page); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_page); + + /*Allocate the object type specific extended data*/ + lv_page_ext_t * ext = lv_obj_allocate_ext_attr(new_page, sizeof(lv_page_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->scrl = NULL; + ext->pr_action = NULL; + ext->rel_action = NULL; + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + ext->bgo = NULL; + ext->pr = NULL; + ext->sb.style = &lv_style_pretty; + ext->sb.mode = LV_SB_MODE_AUTO; + ext->edge_flash.enabled = 0; + ext->edge_flash.bottom_ip = 0; + ext->edge_flash.top_ip = 0; + ext->edge_flash.left_ip = 0; + ext->edge_flash.right_ip = 0; + ext->edge_flash.state = 0; + ext->edge_flash.style = &lv_style_plain_color; + ext->arrow_scroll = 0; + ext->scroll_prop = 0; + ext->scroll_prop_ip = 0; + + /*Init the new page object*/ + if(copy == NULL) { + ext->scrl = lv_cont_create(new_page, NULL); + lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal); + lv_obj_set_design_func(ext->scrl, lv_scrl_design); + lv_obj_set_drag(ext->scrl, true); + lv_obj_set_drag_throw(ext->scrl, true); + lv_obj_set_protect(ext->scrl, LV_PROTECT_PARENT | LV_PROTECT_PRESS_LOST); + lv_cont_set_fit(ext->scrl, false, true); + + /* Add the signal function only if 'scrolling' is created + * because everything has to be ready before any signal is received*/ + lv_obj_set_signal_func(new_page, lv_page_signal); + lv_obj_set_design_func(new_page, lv_page_design); + + lv_page_set_sb_mode(new_page, ext->sb.mode); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + if(par == NULL) { /*Different styles if it is screen*/ + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->bg); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_transp); + } else { + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->page.bg); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, th->page.scrl); + + } + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, th->page.sb); + } else { + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, &lv_style_pretty_color); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_pretty); + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, &lv_style_pretty_color); + } + + } else { + lv_page_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->scrl = lv_cont_create(new_page, copy_ext->scrl); + ext->bgo = lv_page_get_style(copy, LV_PAGE_STYLE_BGO); + ext->pr = lv_page_get_style(copy, LV_PAGE_STYLE_PR); + lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal); + + lv_page_set_pr_action(new_page, copy_ext->pr_action); + lv_page_set_rel_action(new_page, copy_ext->rel_action); + lv_page_set_sb_mode(new_page, copy_ext->sb.mode); + lv_page_set_arrow_scroll(new_page, copy_ext->arrow_scroll); + + + lv_page_set_style(new_page, LV_PAGE_STYLE_BG, lv_page_get_style(copy, LV_PAGE_STYLE_BG)); + lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy, LV_PAGE_STYLE_SCRL)); + lv_page_set_style(new_page, LV_PAGE_STYLE_SB, lv_page_get_style(copy, LV_PAGE_STYLE_SB)); + + /* Add the signal function only if 'scrolling' is created + * because everything has to be ready before any signal is received*/ + lv_obj_set_signal_func(new_page, lv_page_signal); + lv_obj_set_design_func(new_page, lv_page_design); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_page); + } + + lv_page_sb_refresh(new_page); + + LV_LOG_INFO("page created"); + + return new_page; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is release + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->rel_action = rel_action; +} + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->pr_action = pr_action; +} + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + if(ext->sb.mode == sb_mode) return; + + if(sb_mode == LV_SB_MODE_HIDE) ext->sb.mode |= LV_SB_MODE_HIDE; /*Set the hidden flag*/ + else if(sb_mode == LV_SB_MODE_UNHIDE) ext->sb.mode &= (~LV_SB_MODE_HIDE); /*Clear the hidden flag*/ + else { + if(ext->sb.mode & LV_SB_MODE_HIDE) sb_mode |= LV_SB_MODE_HIDE; + ext->sb.mode = sb_mode; + } + + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + + lv_page_sb_refresh(page); + lv_obj_invalidate(page); +} + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->arrow_scroll = en ? 1 : 0; +} + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->scroll_prop = en ? 1 : 0; +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.enabled = en ? 1 : 0; +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_page_set_style(lv_obj_t * page, lv_page_style_t type, lv_style_t * style) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + switch(type) { + case LV_PAGE_STYLE_BG: + lv_obj_set_style(page, style); + break; + case LV_PAGE_STYLE_BGO: + ext->bgo = style; + break; + case LV_PAGE_STYLE_PR: + ext->pr = style; + break; + case LV_PAGE_STYLE_SCRL: + lv_obj_set_style(ext->scrl, style); + break; + case LV_PAGE_STYLE_SB: + ext->sb.style = style; + lv_area_set_height(&ext->sb.hor_area, ext->sb.style->body.padding.inner); + lv_area_set_width(&ext->sb.ver_area, ext->sb.style->body.padding.inner); + lv_page_sb_refresh(page); + lv_obj_refresh_ext_size(page); + lv_obj_invalidate(page); + break; + case LV_PAGE_STYLE_EDGE_FLASH: + ext->edge_flash.style = style; + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + return ext->scrl; +} + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->pr_action; +} + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->rel_action; +} + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->sb.mode; +} + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->arrow_scroll ? true : false; +} + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->scroll_prop == 0 ? false : true; +} + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + return ext->edge_flash.enabled == 0 ? false : true; +} + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page) +{ + lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + return lv_obj_get_width(page) - 2 * (bg_style->body.padding.hor + scrl_style->body.padding.hor); +} + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page) +{ + lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + return lv_obj_get_height(page) - 2 * (bg_style->body.padding.ver + scrl_style->body.padding.ver); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_page_get_style(const lv_obj_t * page, lv_page_style_t type) +{ + lv_style_t * style = NULL; + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + switch(type) { + case LV_PAGE_STYLE_BG: + style = lv_obj_get_style(page); + break; + case LV_PAGE_STYLE_BGO: + style = ext->bgo; + break; + case LV_PAGE_STYLE_PR: + style = ext->pr; + break; + case LV_PAGE_STYLE_SCRL: + style = lv_obj_get_style(ext->scrl); + break; + case LV_PAGE_STYLE_SB: + style = ext->sb.style; + break; + case LV_PAGE_STYLE_EDGE_FLASH: + style = ext->edge_flash.style; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue) +{ + lv_obj_set_drag_parent(obj, glue); + lv_obj_set_drag(obj, glue); +} + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#else + /* Be sure there is no position changing animation in progress + * because it can overide the current changes*/ + lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_y); + lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_pos); + lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_y); + lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_pos); +#endif + + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_style_t * style_scrl = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + + lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1; + lv_coord_t obj_h = lv_obj_get_height(obj); + lv_coord_t scrlable_y = lv_obj_get_y(ext->scrl); + lv_coord_t page_h = lv_obj_get_height(page); + + lv_coord_t top_err = -(scrlable_y + obj_y); + lv_coord_t bot_err = scrlable_y + obj_y + obj_h - page_h; + + /*If obj is higher then the page focus where the "error" is smaller*/ + + /*Out of the page on the top*/ + if((obj_h <= page_h && top_err > 0) || + (obj_h > page_h && top_err < bot_err)) { + /*Calculate a new position and let some space above*/ + scrlable_y = -(obj_y - style_scrl->body.padding.ver - style->body.padding.ver); + scrlable_y += style_scrl->body.padding.ver; + } + /*Out of the page on the bottom*/ + else if((obj_h <= page_h && bot_err > 0) || + (obj_h > page_h && top_err >= bot_err)) { + /*Calculate a new position and let some space below*/ + scrlable_y = -(obj_y + style_scrl->body.padding.ver + style->body.padding.ver); + scrlable_y -= style_scrl->body.padding.ver; + scrlable_y += page_h - obj_h; + } else { + /*Already in focus*/ + return; + } + + if(anim_time == 0) { + lv_obj_set_y(ext->scrl, scrlable_y); +#if USE_LV_ANIMATION + } else { + lv_anim_t a; + a.act_time = 0; + a.start = lv_obj_get_y(ext->scrl); + a.end = scrlable_y; + a.time = anim_time; + a.end_cb = NULL; + a.playback = 0; + a.repeat = 0; + a.var = ext->scrl; + a.path = lv_anim_path_linear; + a.fp = (lv_anim_fp_t) lv_obj_set_y; + lv_anim_create(&a); +#endif + } +} + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist) +{ + lv_obj_t * scrl = lv_page_get_scrl(page); + +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_x(scrl); + a.end = a.start + dist; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_PAGE_SCROLL_ANIM_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#else + lv_obj_set_x(scrl, lv_obj_get_x(scrl) + dist); +#endif +} + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist) +{ + lv_obj_t * scrl = lv_page_get_scrl(page); + +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = scrl; + a.start = lv_obj_get_y(scrl); + a.end = a.start + dist; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = LV_PAGE_SCROLL_ANIM_TIME; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#else + lv_obj_set_y(scrl, lv_obj_get_y(scrl) + dist); +#endif +} + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page) +{ +#if USE_LV_ANIMATION + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + if(ext->edge_flash.enabled) { + lv_anim_t a; + a.var = page; + a.start = 0; + a.end = LV_PAGE_END_FLASH_SIZE; + a.fp = (lv_anim_fp_t)edge_flash_anim; + a.path = lv_anim_path_linear; + a.end_cb = edge_flash_anim_end; + a.act_time = 0; + a.time = LV_PAGE_END_ANIM_TIME; + a.playback = 1; + a.playback_pause = LV_PAGE_END_ANIM_WAIT_TIME; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); + } +#endif +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the pages + * @param page pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(page, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw without border*/ + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_coord_t border_width_tmp = style->body.border.width; + style->body.border.width = 0; + lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page)); + style->body.border.width = border_width_tmp; + + } else if(mode == LV_DESIGN_DRAW_POST) { /*Draw the scroll bars finally*/ + + /*Draw only a border*/ + lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG); + lv_coord_t shadow_width_tmp = style->body.shadow.width; + uint8_t empty_tmp = style->body.empty; + style->body.shadow.width = 0; + style->body.empty = 1; + lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page)); + style->body.shadow.width = shadow_width_tmp; + style->body.empty = empty_tmp; + + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + + /*Draw the scrollbars*/ + lv_area_t sb_area; + if(ext->sb.hor_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) { + /*Convert the relative coordinates to absolute*/ + lv_area_copy(&sb_area, &ext->sb.hor_area); + sb_area.x1 += page->coords.x1; + sb_area.y1 += page->coords.y1; + sb_area.x2 += page->coords.x1; + sb_area.y2 += page->coords.y1; + lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page)); + } + + if(ext->sb.ver_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) { + /*Convert the relative coordinates to absolute*/ + lv_area_copy(&sb_area, &ext->sb.ver_area); + sb_area.x1 += page->coords.x1; + sb_area.y1 += page->coords.y1; + sb_area.x2 += page->coords.x1; + sb_area.y2 += page->coords.y1; + lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page)); + } + + + lv_coord_t page_w = lv_obj_get_width(page); + lv_coord_t page_h = lv_obj_get_height(page); + lv_area_t flash_area; + + if(ext->edge_flash.top_ip) { + flash_area.x1 = page->coords.x1 - page_w; + flash_area.x2 = page->coords.x2 + page_w; + flash_area.y1 = page->coords.y1 - 3 * page_w + ext->edge_flash.state; + flash_area.y2 = page->coords.y1 + ext->edge_flash.state; + } + else if(ext->edge_flash.bottom_ip) { + flash_area.x1 = page->coords.x1 - page_w; + flash_area.x2 = page->coords.x2 + page_w; + flash_area.y1 = page->coords.y2 - ext->edge_flash.state; + flash_area.y2 = page->coords.y2 + 3 * page_w - ext->edge_flash.state; + } + else if(ext->edge_flash.right_ip) { + flash_area.x1 = page->coords.x2 - ext->edge_flash.state; + flash_area.x2 = page->coords.x2 + 3 * page_h - ext->edge_flash.state; + flash_area.y1 = page->coords.y1 - page_h; + flash_area.y2 = page->coords.y2 + page_h; + } + else if(ext->edge_flash.left_ip) { + flash_area.x1 = page->coords.x1 - 3 * page_h + ext->edge_flash.state; + flash_area.x2 = page->coords.x1 + ext->edge_flash.state; + flash_area.y1 = page->coords.y1 - page_h; + flash_area.y2 = page->coords.y2 + page_h; + } + + if(ext->edge_flash.left_ip || ext->edge_flash.right_ip || ext->edge_flash.top_ip || ext->edge_flash.bottom_ip) { + lv_style_t flash_style; + lv_style_copy(&flash_style, ext->edge_flash.style); + flash_style.body.radius = LV_RADIUS_CIRCLE; + uint32_t opa = (flash_style.body.opa * ext->edge_flash.state) / LV_PAGE_END_FLASH_SIZE; + flash_style.body.opa = opa; + lv_draw_rect(&flash_area, mask, &flash_style, lv_obj_get_opa_scale(page)); + } + + } + + return true; +} + +/** + * Handle the drawing related tasks of the scrollable object + * @param scrl pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + return ancestor_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { +#if USE_LV_GROUP + /* If the page is focused in a group and + * the background object is not visible (transparent or empty) + * then "activate" the style of the scrollable*/ + lv_style_t * style_scrl_ori = lv_obj_get_style(scrl); + lv_obj_t * page = lv_obj_get_parent(scrl); + lv_style_t * style_page = lv_obj_get_style(page); + lv_group_t * g = lv_obj_get_group(page); + if((style_page->body.empty || style_page->body.opa == LV_OPA_TRANSP) && style_page->body.border.width == 0) { /*Is the background visible?*/ + if(lv_group_get_focused(g) == page) { + lv_style_t * style_mod; + style_mod = lv_group_mod_style(g, style_scrl_ori); + scrl->style_p = style_mod; /*Temporally change the style to the activated */ + } + } +#endif + ancestor_design(scrl, mask, mode); + +#if USE_LV_GROUP + scrl->style_p = style_scrl_ori; /*Revert the style*/ +#endif + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(scrl, mask, mode); + } + + return true; +} + +/** + * Signal function of the page + * @param page pointer to a page object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(page, sign, param); + if(res != LV_RES_OK) return res; + + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + lv_style_t * style = lv_obj_get_style(page); + lv_obj_t * child; + if(sign == LV_SIGNAL_CHILD_CHG) { /*Automatically move children to the scrollable object*/ + child = lv_obj_get_child(page, NULL); + while(child != NULL) { + if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) { + lv_obj_t * tmp = child; + child = lv_obj_get_child(page, child); /*Get the next child before move this*/ + lv_obj_set_parent(tmp, ext->scrl); + } else { + child = lv_obj_get_child(page, child); + } + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + /*If no hor_fit enabled set the scrollable's width to the page's width*/ + if(lv_cont_get_hor_fit(ext->scrl) == false) { + lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor); + } else { + ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords); + } + + /*The scrollbars are important only if they are visible now*/ + if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page); + + /*Refresh the ext. size because the scrollbars might be positioned out of the page*/ + lv_obj_refresh_ext_size(page); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*Refresh the scrollbar and notify the scrl if the size is changed*/ + if(ext->scrl != NULL && (lv_obj_get_width(page) != lv_area_get_width(param) || + lv_obj_get_height(page) != lv_area_get_height(param))) { + /*If no hor_fit enabled set the scrollable's width to the page's width*/ + if(lv_cont_get_hor_fit(ext->scrl) == false) { + lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor); + } + + ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords); + + /*The scrollbars are important only if they are visible now*/ + if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page); + } + } else if(sign == LV_SIGNAL_PRESSED) { + if(ext->pr_action != NULL) { + res = ext->pr_action(page); + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(lv_indev_is_dragging(lv_indev_get_act()) == false) { + if(ext->rel_action != NULL) { + res = ext->rel_action(page); + } + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /*Ensure ext. size for the scrollbars if they are out of the page*/ + if(page->ext_size < (-ext->sb.style->body.padding.hor)) page->ext_size = -ext->sb.style->body.padding.hor; + if(page->ext_size < (-ext->sb.style->body.padding.ver)) page->ext_size = -ext->sb.style->body.padding.ver; + } else if(sign == LV_SIGNAL_CONTROLL) { + uint32_t c = *((uint32_t *) param); + + if((c == LV_GROUP_KEY_DOWN) && ext->arrow_scroll) { + lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4); + } else if((c == LV_GROUP_KEY_UP) && ext->arrow_scroll) { + lv_page_scroll_ver(page, lv_obj_get_height(page) / 4); + } else if((c == LV_GROUP_KEY_RIGHT) && ext->arrow_scroll) { + /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/ + if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4); + else lv_page_scroll_hor(page, - lv_obj_get_width(page) / 4); + } else if((c == LV_GROUP_KEY_LEFT) && ext->arrow_scroll) { + /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/ + if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, lv_obj_get_height(page) / 4); + else lv_page_scroll_hor(page, lv_obj_get_width(page) / 4); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = lv_page_get_arrow_scroll(page); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_page"; + } + + return res; +} + +/** + * Signal function of the scrollable part of a page + * @param scrl pointer to the scrollable object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * page = lv_obj_get_parent(scrl); + lv_style_t * page_style = lv_obj_get_style(page); + lv_page_ext_t * page_ext = lv_obj_get_ext_attr(page); + + if(sign == LV_SIGNAL_CORD_CHG) { + /*Limit the position of the scrollable object to be always visible + * (Do not let its edge inner then its parent respective edge)*/ + lv_coord_t new_x = lv_obj_get_x(scrl); + lv_coord_t new_y = lv_obj_get_y(scrl); + bool refr_x = false; + bool refr_y = false; + lv_area_t page_coords; + lv_area_t scrl_coords; + lv_obj_get_coords(scrl, &scrl_coords); + lv_obj_get_coords(page, &page_coords); + + lv_area_t * ori_coords = (lv_area_t *) param; + lv_coord_t diff_x = scrl->coords.x1 - ori_coords->x1; + lv_coord_t diff_y = scrl->coords.y1 - ori_coords->y1; + lv_coord_t hpad = page_style->body.padding.hor; + lv_coord_t vpad = page_style->body.padding.ver; + lv_obj_t * page_parent = lv_obj_get_parent(page); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t drag_vect; + lv_indev_get_vect(indev, &drag_vect); + + + /* Start the scroll propagation if there is drag vector on the indev, but the drag is not started yet + * and the scrollable is in a corner. It will enable the scroll propagation only when a new scroll begins and not + * when the scrollable is already being scrolled.*/ + if(page_ext->scroll_prop && page_ext->scroll_prop_ip == 0 && lv_indev_is_dragging(indev) == false) { + if(((drag_vect.y > 0 && scrl_coords.y1 == page_coords.y1 + vpad) || + (drag_vect.y < 0 && scrl_coords.y2 == page_coords.y2 - vpad)) && + ((drag_vect.x > 0 && scrl_coords.x1 == page_coords.x1 + hpad) || + (drag_vect.x < 0 && scrl_coords.x2 == page_coords.x2 - hpad))) { + + if(lv_obj_get_parent(page_parent) != NULL) { /*Do not propagate the scroll to a screen*/ + page_ext->scroll_prop_ip = 1; + } + } + } + + /*scrollable width smaller then page width? -> align to left*/ + if(lv_area_get_width(&scrl_coords) + 2 * hpad <= lv_area_get_width(&page_coords)) { + if(scrl_coords.x1 != page_coords.x1 + hpad) { + new_x = hpad; + refr_x = true; + } + } else { + /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/ + if(page_ext->scroll_prop_ip) { + if(drag_vect.x == diff_x) { /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/ + new_x = ori_coords->x1 - page_coords.x1; + refr_x = true; + } + } + /*The edges of the scrollable can not be in the page (minus hpad) */ + else if(scrl_coords.x2 < page_coords.x2 - hpad) { + new_x = lv_area_get_width(&page_coords) - lv_area_get_width(&scrl_coords) - hpad; /* Right align */ + refr_x = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.right_ip = 1; + } + } + else if(scrl_coords.x1 > page_coords.x1 + hpad) { + new_x = hpad; /*Left align*/ + refr_x = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.left_ip = 1; + } + } + } + + /*scrollable height smaller then page height? -> align to left*/ + if(lv_area_get_height(&scrl_coords) + 2 * vpad <= lv_area_get_height(&page_coords)) { + if(scrl_coords.y1 != page_coords.y1 + vpad) { + new_y = vpad; + refr_y = true; + } + } else { + /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/ + if(page_ext->scroll_prop_ip) { + if(drag_vect.y == diff_y) { /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/ + new_y = ori_coords->y1 - page_coords.y1; + refr_y = true; + } + } + /*The edges of the scrollable can not be in the page (minus vpad) */ + else if(scrl_coords.y2 < page_coords.y2 - vpad) { + new_y = lv_area_get_height(&page_coords) - lv_area_get_height(&scrl_coords) - vpad; /* Bottom align */ + refr_y = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.bottom_ip = 1; + } + } + else if(scrl_coords.y1 > page_coords.y1 + vpad) { + new_y = vpad; /*Top align*/ + refr_y = true; + if(page_ext->edge_flash.enabled && + page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 && + page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) { + lv_page_start_edge_flash(page); + page_ext->edge_flash.top_ip = 1; + } + } + } + + if(refr_x || refr_y) { + lv_obj_set_pos(scrl, new_x, new_y); + + if(page_ext->scroll_prop_ip) { + if(refr_y) lv_obj_set_y(page_parent, lv_obj_get_y(page_parent) + diff_y); + if(refr_x) lv_obj_set_x(page_parent, lv_obj_get_x(page_parent) + diff_x); + } + } + + lv_page_sb_refresh(page); + } + else if(sign == LV_SIGNAL_DRAG_END) { + + /*Scroll propagation is finished on drag end*/ + page_ext->scroll_prop_ip = 0; + + /*Hide scrollbars if required*/ + if(page_ext->sb.mode == LV_SB_MODE_DRAG) { + lv_area_t sb_area_tmp; + if(page_ext->sb.hor_draw) { + lv_area_copy(&sb_area_tmp, &page_ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + page_ext->sb.hor_draw = 0; + } + if(page_ext->sb.ver_draw) { + lv_area_copy(&sb_area_tmp, &page_ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + page_ext->sb.ver_draw = 0; + } + } + } else if(sign == LV_SIGNAL_PRESSED) { + if(page_ext->pr_action != NULL) { + res = page_ext->pr_action(page); + } + } else if(sign == LV_SIGNAL_RELEASED) { + if(lv_indev_is_dragging(lv_indev_get_act()) == false) { + if(page_ext->rel_action != NULL) { + res = page_ext->rel_action(page); + } + } + } + + return res; +} + + +/** + * Refresh the position and size of the scroll bars. + * @param page pointer to a page object + */ +static void lv_page_sb_refresh(lv_obj_t * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + lv_style_t * style = lv_obj_get_style(page); + lv_obj_t * scrl = ext->scrl; + lv_coord_t size_tmp; + lv_coord_t scrl_w = lv_obj_get_width(scrl); + lv_coord_t scrl_h = lv_obj_get_height(scrl); + lv_coord_t hpad = style->body.padding.hor; + lv_coord_t vpad = style->body.padding.ver; + lv_coord_t obj_w = lv_obj_get_width(page); + lv_coord_t obj_h = lv_obj_get_height(page); + + /*Always let 'scrollbar width' padding above, under, left and right to the scrollbars + * else: + * - horizontal and vertical scrollbars can overlap on the corners + * - if the page has radius the scrollbar can be out of the radius */ + lv_coord_t sb_hor_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.hor); + lv_coord_t sb_ver_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.ver); + + if(ext->sb.mode == LV_SB_MODE_OFF) return; + + if(ext->sb.mode == LV_SB_MODE_ON) { + ext->sb.hor_draw = 1; + ext->sb.ver_draw = 1; + } + + /*Invalidate the current (old) scrollbar areas*/ + lv_area_t sb_area_tmp; + if(ext->sb.hor_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + if(ext->sb.ver_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + + + if(ext->sb.mode == LV_SB_MODE_DRAG && lv_indev_is_dragging(lv_indev_get_act()) == false) { + ext->sb.hor_draw = 0; + ext->sb.ver_draw = 0; + return; + + } + + /*Horizontal scrollbar*/ + if(scrl_w <= obj_w - 2 * hpad) { /*Full sized scroll bar*/ + lv_area_set_width(&ext->sb.hor_area, obj_w - 2 * sb_hor_pad); + lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad, obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver); + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 0; + } else { + size_tmp = (obj_w * (obj_w - (2 * sb_hor_pad))) / (scrl_w + 2 * hpad); + if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; + lv_area_set_width(&ext->sb.hor_area, size_tmp); + + lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad + + (-(lv_obj_get_x(scrl) - hpad) * (obj_w - size_tmp - 2 * sb_hor_pad)) / + (scrl_w + 2 * hpad - obj_w), + obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver); + + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 1; + } + + /*Vertical scrollbar*/ + if(scrl_h <= obj_h - 2 * vpad) { /*Full sized scroll bar*/ + lv_area_set_height(&ext->sb.ver_area, obj_h - 2 * sb_ver_pad); + lv_area_set_pos(&ext->sb.ver_area, obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor, sb_ver_pad); + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 0; + } else { + size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + 2 * vpad); + if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; + lv_area_set_height(&ext->sb.ver_area, size_tmp); + + lv_area_set_pos(&ext->sb.ver_area, obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor, + sb_ver_pad + + (-(lv_obj_get_y(scrl) - vpad) * (obj_h - size_tmp - 2 * sb_ver_pad)) / + (scrl_h + 2 * vpad - obj_h)); + + if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 1; + } + + /*Invalidate the new scrollbar areas*/ + if(ext->sb.hor_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.hor_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } + if(ext->sb.ver_draw != 0) { + lv_area_copy(&sb_area_tmp, &ext->sb.ver_area); + sb_area_tmp.x1 += page->coords.x1; + sb_area_tmp.y1 += page->coords.y1; + sb_area_tmp.x2 += page->coords.x1; + sb_area_tmp.y2 += page->coords.y1; + lv_inv_area(&sb_area_tmp); + } +} + +#if USE_LV_ANIMATION +static void edge_flash_anim(void * page, int32_t v) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.state = v; + lv_obj_invalidate(page); +} + +static void edge_flash_anim_end(void * page) +{ + lv_page_ext_t * ext = lv_obj_get_ext_attr(page); + ext->edge_flash.top_ip = 0; + ext->edge_flash.bottom_ip = 0; + ext->edge_flash.left_ip = 0; + ext->edge_flash.right_ip = 0; + lv_obj_invalidate(page); +} +#endif + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.h new file mode 100644 index 0000000..caed34e --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_page.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_page.h + * + */ + +#ifndef LV_PAGE_H +#define LV_PAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_PAGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "../lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Scrollbar modes: shows when should the scrollbars be visible*/ +enum +{ + LV_SB_MODE_OFF = 0x0, /*Never show scrollbars*/ + LV_SB_MODE_ON = 0x1, /*Always show scrollbars*/ + LV_SB_MODE_DRAG = 0x2, /*Show scrollbars when page is being dragged*/ + LV_SB_MODE_AUTO = 0x3, /*Show scrollbars when the scrollable container is large enough to be scrolled*/ + LV_SB_MODE_HIDE = 0x4, /*Hide the scroll bar temporally*/ + LV_SB_MODE_UNHIDE = 0x5, /*Unhide the previously hidden scrollbar. Recover it's type too*/ +}; +typedef uint8_t lv_sb_mode_t; + +/*Data of page*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * scrl; /*The scrollable object on the background*/ + lv_style_t *bgo; /*The scrollable object on the background*/ + lv_style_t *pr; /*The scrollable object on the background*/ + lv_action_t rel_action; /*Function to call when the page is released*/ + lv_action_t pr_action; /*Function to call when the page is pressed*/ + struct { + lv_style_t *style; /*Style of scrollbars*/ + lv_area_t hor_area; /*Horizontal scrollbar area relative to the page. (Handled by the library) */ + lv_area_t ver_area; /*Vertical scrollbar area relative to the page (Handled by the library)*/ + uint8_t hor_draw :1; /*1: horizontal scrollbar is visible now (Handled by the library)*/ + uint8_t ver_draw :1; /*1: vertical scrollbar is visible now (Handled by the library)*/ + lv_sb_mode_t mode:3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/ + } sb; + struct { + uint16_t state; /*Store the current size of the edge flash effect*/ + lv_style_t *style; /*Style of edge flash effect (usually homogeneous circle)*/ + uint8_t enabled :1; /*1: Show a flash animation on the edge*/ + uint8_t top_ip :1; /*Used internally to show that top most position is reached (flash is In Progress)*/ + uint8_t bottom_ip :1; /*Used internally to show that bottom most position is reached (flash is In Progress)*/ + uint8_t right_ip :1; /*Used internally to show that right most position is reached (flash is In Progress)*/ + uint8_t left_ip :1; /*Used internally to show that left most position is reached (flash is In Progress)*/ + }edge_flash; + + uint8_t arrow_scroll :1; /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/ + uint8_t scroll_prop :1; /*1: Propagate the scrolling the the parent if the edge is reached*/ + uint8_t scroll_prop_ip :1; /*1: Scroll propagation is in progress (used by the library)*/ +} lv_page_ext_t; + +enum { + LV_PAGE_STYLE_BG, + LV_PAGE_STYLE_BGO, + LV_PAGE_STYLE_PR, + LV_PAGE_STYLE_SCRL, + LV_PAGE_STYLE_SB, + LV_PAGE_STYLE_EDGE_FLASH, +}; +typedef uint8_t lv_page_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t *obj); + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page); + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page); + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is released + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action); + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action); + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode); + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en); + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en); + +/** + * Set the fit attribute of the scrollable part of a page. + * It means it can set its size automatically to involve all children. + * (Can be set separately horizontally and vertically) + * @param page pointer to a page object + * @param hor_en true: enable horizontal fit + * @param ver_en true: enable vertical fit + */ +static inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en); +} + +/** + * Set width of the scrollable part of a page + * @param page pointer to a page object + * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled) + */ +static inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w) +{ + lv_obj_set_width(lv_page_get_scrl(page), w); +} + +/** + * Set height of the scrollable part of a page + * @param page pointer to a page object + * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled) + */ +static inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h) +{ + lv_obj_set_height(lv_page_get_scrl(page), h); + +} + +/** +* Set the layout of the scrollable part of the page +* @param page pointer to a page object +* @param layout a layout from 'lv_cont_layout_t' +*/ +static inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout) +{ + lv_cont_set_layout(lv_page_get_scrl(page), layout); +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page); + + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page); + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page); + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page); + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page); + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page); + +/** + * Get width of the scrollable part of a page + * @param page pointer to a page object + * @return the width of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page) +{ + return lv_obj_get_width(lv_page_get_scrl(page)); +} + +/** + * Get height of the scrollable part of a page + * @param page pointer to a page object + * @return the height of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page) +{ + return lv_obj_get_height(lv_page_get_scrl(page)); +} + +/** +* Get the layout of the scrollable part of a page +* @param page pointer to page object +* @return the layout from 'lv_cont_layout_t' +*/ +static inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page) +{ + return lv_cont_get_layout(lv_page_get_scrl(page)); +} + +/** +* Get horizontal fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: horizontal fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page) +{ + return lv_cont_get_hor_fit(lv_page_get_scrl(page)); +} + +/** +* Get vertical fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: vertical fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page) +{ + return lv_cont_get_ver_fit(lv_page_get_scrl(page)); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue); + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist); + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist); + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PAGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PAGE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.c new file mode 100644 index 0000000..1700a4d --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.c @@ -0,0 +1,411 @@ +/** + * @file lv_preload.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_preload.h" +#if USE_LV_PRELOAD != 0 + +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_rect.h" +#include "../lv_draw/lv_draw_arc.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_PRELOAD_DEF_ARC_LENGTH +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +#endif + +#ifndef LV_PRELOAD_DEF_SPIN_TIME +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#endif + +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC /*animation type*/ +#endif + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a pre loader object + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("preload create started"); + + /*Create the ancestor of pre loader*/ + lv_obj_t * new_preload = lv_arc_create(par, copy); + lv_mem_assert(new_preload); + if(new_preload == NULL) return NULL; + + /*Allocate the pre loader type specific extended data*/ + lv_preload_ext_t * ext = lv_obj_allocate_ext_attr(new_preload, sizeof(lv_preload_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_preload); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_preload); + + /*Initialize the allocated 'ext' */ + ext->arc_length = LV_PRELOAD_DEF_ARC_LENGTH; + ext->anim_type = LV_PRELOAD_DEF_ANIM; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_preload, lv_preload_signal); + lv_obj_set_design_func(new_preload, lv_preload_design); + + + /*Init the new pre loader pre loader*/ + if(copy == NULL) { + lv_obj_set_size(new_preload, LV_DPI / 2, LV_DPI / 2); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_preload_set_style(new_preload, LV_PRELOAD_STYLE_MAIN, th->preload); + } else { + lv_obj_set_style(new_preload, &lv_style_pretty_color); + } + + ext->time = LV_PRELOAD_DEF_SPIN_TIME; + + } + /*Copy an existing pre loader*/ + else { + lv_preload_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->arc_length = copy_ext->arc_length; + ext->time = copy_ext->time; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_preload); + } + + lv_preload_set_animation_type(new_preload, ext->anim_type); + + + LV_LOG_INFO("preload created"); + + return new_preload; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + ext->arc_length = deg; +} + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + ext->time = time; + lv_preload_set_animation_type(preload, ext->anim_type); +} +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_PRELOAD_STYLE_MAIN: + lv_arc_set_style(preload, LV_ARC_STYLE_MAIN, style); + break; + } +} + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type) +{ +#if USE_LV_ANIMATION + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + /*delete previous animation*/ + //lv_anim_del(preload, NULL); + switch(type) + { + case LV_PRELOAD_TYPE_FILLSPIN_ARC: + { + ext->anim_type = LV_PRELOAD_TYPE_FILLSPIN_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 1; + a.repeat_pause = 0; + lv_anim_create(&a); + + lv_anim_t b; + b.var = preload; + b.start = ext->arc_length; + b.end = 360 - ext->arc_length; + b.fp = (lv_anim_fp_t)lv_preload_set_arc_length; + b.path = lv_anim_path_ease_in_out; + b.end_cb = NULL; + b.act_time = 0; + b.time = ext->time; + b.playback = 1; + b.playback_pause = 0; + b.repeat = 1; + b.repeat_pause = 0; + lv_anim_create(&b); + break; + } + case LV_PRELOAD_TYPE_SPINNING_ARC: + default: + { + ext->anim_type = LV_PRELOAD_TYPE_SPINNING_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 1; + a.repeat_pause = 0; + lv_anim_create(&a); + break; + } + } + +#endif //USE_LV_ANIMATION +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->arc_length; + +} + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->time; +} + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type) +{ + lv_style_t * style = NULL; + + switch(type) { + case LV_PRELOAD_STYLE_MAIN: + style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->anim_type; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Automatically in an animation to rotate the arc of spinner. + * @param ptr pointer to preloader + * @param val the current desired value [0..360] + */ +void lv_preload_spinner_animation(void * ptr, int32_t val) +{ + lv_obj_t * preload = ptr; + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + int16_t angle_start = val - ext->arc_length / 2 + 180; + int16_t angle_end = angle_start + ext->arc_length; + + angle_start = angle_start % 360; + angle_end = angle_end % 360; + + lv_arc_set_angles(preload, angle_start, angle_end); + +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the pre loaders + * @param preload pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + + /*Draw a circle as background*/ + lv_style_t * style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); + if(style->body.border.width > 0) { + lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(preload), lv_obj_get_height(preload))) / 2; + r -= LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver); + + lv_coord_t x = preload->coords.x1 + lv_obj_get_width(preload) / 2; + lv_coord_t y = preload->coords.y1 + lv_obj_get_height(preload) / 2; + + lv_style_t bg_style; + lv_style_copy(&bg_style, &lv_style_plain); + bg_style.body.empty = 1; + bg_style.body.radius = LV_RADIUS_CIRCLE; + bg_style.body.border.color = style->body.border.color; + bg_style.body.border.width = style->body.border.width; + + lv_area_t bg_area; + bg_area.x1 = x - r; + bg_area.y1 = y - r; + bg_area.x2 = x + r; + bg_area.y2 = y + r; + + lv_draw_rect(&bg_area, mask, &bg_style, lv_obj_get_opa_scale(preload)); + } + /*Draw the arc above the background circle */ + ancestor_design(preload, mask, mode); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the pre loader + * @param preload pointer to a pre loader object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(preload, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_preload"; + } + + return res; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.h new file mode 100644 index 0000000..4f12f02 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_preload.h @@ -0,0 +1,168 @@ +/** + * @file lv_preload.h + * + */ + +#ifndef LV_PRELOAD_H +#define LV_PRELOAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_PRELOAD != 0 + +/*Testing of dependencies*/ +#if USE_LV_ARC == 0 +#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC 1) " +#endif + +#if USE_LV_ANIMATION == 0 +#error "lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_arc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, +}; +typedef uint8_t lv_preloader_type_t; + +/*Data of pre loader*/ +typedef struct { + lv_arc_ext_t arc; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t arc_length; /*Length of the spinning indicator in degree*/ + uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ +} lv_preload_ext_t; + + +/*Styles*/ +enum { + LV_PRELOAD_STYLE_MAIN, +}; +typedef uint8_t lv_preload_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a pre loader objects + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg); + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload); + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + +/*===================== + * Other functions + *====================*/ + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +void lv_preload_spinner_animation(void * ptr, int32_t val); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PRELOAD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PRELOAD_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.c new file mode 100644 index 0000000..28c8b80 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.c @@ -0,0 +1,582 @@ +/** + * @file lv_roller.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_roller.h" +#if USE_LV_ROLLER != 0 + +#include "../lv_draw/lv_draw.h" +#include "../lv_core/lv_group.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 200 /*ms*/ +# endif +#else +# undef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 0 /*No animation*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param); +static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param); +static void refr_position(lv_obj_t * roller, bool anim_en); +static void draw_bg(lv_obj_t * roller, const lv_area_t * mask); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("roller create started"); + + /*Create the ancestor of roller*/ + lv_obj_t * new_roller = lv_ddlist_create(par, copy); + lv_mem_assert(new_roller); + if(new_roller == NULL) return NULL; + + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_roller)); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_roller); + + /*Allocate the roller type specific extended data*/ + lv_roller_ext_t * ext = lv_obj_allocate_ext_attr(new_roller, sizeof(lv_roller_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + ext->ddlist.draw_arrow = 0; /*Do not draw arrow by default*/ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_roller, lv_roller_signal); + lv_obj_set_design_func(new_roller, lv_roller_design); + + /*Init the new roller roller*/ + if(copy == NULL) { + lv_obj_t * scrl = lv_page_get_scrl(new_roller); + lv_obj_set_drag(scrl, true); /*In ddlist is might be disabled*/ + lv_page_set_rel_action(new_roller, NULL); /*Roller don't uses it (like ddlist)*/ + lv_page_set_scrl_fit(new_roller, true, false); /*Height is specified directly*/ + lv_ddlist_open(new_roller, false); + lv_ddlist_set_anim_time(new_roller, LV_ROLLER_ANIM_TIME); + lv_roller_set_visible_row_count(new_roller, 3); + lv_label_set_align(ext->ddlist.label, LV_LABEL_ALIGN_CENTER); + + lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_roller_set_style(new_roller, LV_ROLLER_STYLE_BG, th->roller.bg); + lv_roller_set_style(new_roller, LV_ROLLER_STYLE_SEL, th->roller.sel); + } else { + /*Let the ddlist's style*/ + lv_obj_refresh_style(new_roller); /*To set scrollable size automatically*/ + } + } + /*Copy an existing roller*/ + else { + lv_obj_t * scrl = lv_page_get_scrl(new_roller); + lv_ddlist_open(new_roller, false); + lv_obj_set_signal_func(scrl, lv_roller_scrl_signal); + + lv_obj_refresh_style(new_roller); /*Refresh the style with new signal function*/ + } + + + LV_LOG_INFO("roller created"); + + + return new_roller; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left or center) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_mem_assert(ext); + if(ext->ddlist.label == NULL) return; /*Probably the roller is being deleted if the label is NULL.*/ + lv_label_set_align(ext->ddlist.label, align); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t * roller, uint16_t sel_opt, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + if(lv_roller_get_selected(roller) == sel_opt) return; + + lv_ddlist_set_selected(roller, sel_opt); + refr_position(roller, anim_en); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t * roller, uint8_t row_cnt) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + uint8_t n_line_space = (row_cnt > 1) ? row_cnt - 1 : 1; + lv_ddlist_set_fix_height(roller, lv_font_get_height(style_label->text.font) * row_cnt + style_label->text.line_space * n_line_space); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t * roller, lv_roller_style_t type, lv_style_t * style) +{ + switch(type) { + case LV_ROLLER_STYLE_BG: + lv_obj_set_style(roller, style); + break; + case LV_ROLLER_STYLE_SEL: + lv_ddlist_set_style(roller, LV_DDLIST_STYLE_SEL, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller) +{ + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_mem_assert(ext); + lv_mem_assert(ext->ddlist.label); + return lv_label_get_align(ext->ddlist.label); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t * roller) +{ + return lv_page_get_scrl_hor_fit(roller); +} + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t * roller, lv_roller_style_t type) +{ + switch(type) { + case LV_ROLLER_STYLE_BG: + return lv_obj_get_style(roller); + case LV_ROLLER_STYLE_SEL: + return lv_ddlist_get_style(roller, LV_DDLIST_STYLE_SEL); + default: + return NULL; + } + + /*To avoid warning*/ + return NULL; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the rollers + * @param roller pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + draw_bg(roller, mask); + + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_opa_t opa_scale = lv_obj_get_opa_scale(roller); + const lv_font_t * font = style->text.font; + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_coord_t font_h = lv_font_get_height(font); + lv_area_t rect_area; + rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2; + if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --; /*Compensate the two rounding error*/ + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = roller->coords.x1; + rect_area.x2 = roller->coords.x2; + + lv_draw_rect(&rect_area, mask, ext->ddlist.sel_style, opa_scale); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + const lv_font_t * font = style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_opa_t opa_scale = lv_obj_get_opa_scale(roller); + + /*Redraw the text on the selected area with a different color*/ + lv_area_t rect_area; + rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2; + if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --; /*Compensate the two rounding error*/ + rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1; + rect_area.x1 = roller->coords.x1; + rect_area.x2 = roller->coords.x2; + lv_area_t mask_sel; + bool area_ok; + area_ok = lv_area_intersect(&mask_sel, mask, &rect_area); + if(area_ok) { + lv_style_t * sel_style = lv_roller_get_style(roller, LV_ROLLER_STYLE_SEL); + lv_style_t new_style; + lv_txt_flag_t txt_align = LV_TXT_FLAG_NONE; + + { + lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label); + + if(LV_LABEL_ALIGN_CENTER == label_align) { + txt_align |= LV_TXT_FLAG_CENTER; + } else if(LV_LABEL_ALIGN_RIGHT == label_align) { + txt_align |= LV_TXT_FLAG_RIGHT; + } + } + + lv_style_copy(&new_style, style); + new_style.text.color = sel_style->text.color; + new_style.text.opa = sel_style->text.opa; + lv_draw_label(&ext->ddlist.label->coords, &mask_sel, &new_style, opa_scale, + lv_label_get_text(ext->ddlist.label), txt_align, NULL); + } + } + + return true; +} + +/** + * Signal function of the roller + * @param roller pointer to a roller object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param) +{ + lv_res_t res = LV_RES_OK; + + /*Don't let the drop down list to handle the control signals. It works differently*/ + if(sign != LV_SIGNAL_CONTROLL && sign != LV_SIGNAL_FOCUS && sign != LV_SIGNAL_DEFOCUS) { + /* Include the ancient signal function */ + res = ancestor_signal(roller, sign, param); + if(res != LV_RES_OK) return res; + } + + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_align_t obj_align = LV_ALIGN_IN_LEFT_MID; + if(ext->ddlist.label) { + lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label); + if(LV_LABEL_ALIGN_CENTER == label_align) obj_align = LV_ALIGN_CENTER; + else if(LV_LABEL_ALIGN_RIGHT == label_align) obj_align = LV_ALIGN_IN_RIGHT_MID; + } + + if(sign == LV_SIGNAL_STYLE_CHG) { + lv_obj_set_height(lv_page_get_scrl(roller), + lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); + lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0); + lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); + refr_position(roller, false); + } else if(sign == LV_SIGNAL_CORD_CHG) { + + if(lv_obj_get_width(roller) != lv_area_get_width(param) || + lv_obj_get_height(roller) != lv_area_get_height(param)) { + + lv_ddlist_set_fix_height(roller, lv_obj_get_height(roller)); + lv_obj_set_height(lv_page_get_scrl(roller), + lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller)); + + lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0); + lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id); + refr_position(roller, false); + } + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(roller); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + /*In navigate mode revert the original value*/ + if(!editing) { + if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) { + ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori; + refr_position(roller, true); + } + } + /*Save the current state when entered to edit mode*/ + else { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; + } + } else { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; /*Save the current value. Used to revert this state if ENER wont't be pressed*/ + + } +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { +#if USE_LV_GROUP + /*Revert the original state*/ + if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) { + ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori; + refr_position(roller, true); + } +#endif + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { + if(ext->ddlist.sel_opt_id + 1 < ext->ddlist.option_cnt) { + lv_roller_set_selected(roller, ext->ddlist.sel_opt_id + 1, true); + } + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { + if(ext->ddlist.sel_opt_id > 0) { + lv_roller_set_selected(roller, ext->ddlist.sel_opt_id - 1, true); + } + } else if(c == LV_GROUP_KEY_ENTER) { + ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id; /*Set the entered value as default*/ + if(ext->ddlist.action) ext->ddlist.action(roller); + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(roller); + bool editing = lv_group_get_editing(g); + if(editing) lv_group_set_editing(g, false); /*In edit mode go to navigate mode if an option is selected*/ +#endif + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_roller"; + } + + return res; +} + +/** + * Signal function of the scrollable part of the roller. + * @param roller_scrl ointer to the scrollable part of roller (page) + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(roller_scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_indev_t * indev = lv_indev_get_act(); + int32_t id = -1; + lv_obj_t * roller = lv_obj_get_parent(roller_scrl); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + + if(ext->ddlist.label == NULL) return LV_RES_INV; /*On delete the ddlist signal deletes the label so nothing left to do here*/ + + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + const lv_font_t * font = style_label->text.font; + lv_coord_t font_h = lv_font_get_height(font); + + if(sign == LV_SIGNAL_DRAG_END) { + /*If dragged then align the list to there be an element in the middle*/ + lv_coord_t label_y1 = ext->ddlist.label->coords.y1 - roller->coords.y1; + lv_coord_t label_unit = font_h + style_label->text.line_space; + lv_coord_t mid = (roller->coords.y2 - roller->coords.y1) / 2; + id = (mid - label_y1 + style_label->text.line_space / 2) / label_unit; + if(id < 0) id = 0; + if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1; + ext->ddlist.sel_opt_id = id; + if(ext->ddlist.action) ext->ddlist.action(roller); + } else if(sign == LV_SIGNAL_RELEASED) { + /*If picked an option by clicking then set it*/ + if(!lv_indev_is_dragging(indev)) { + lv_point_t p; + lv_indev_get_point(indev, &p); + p.y = p.y - ext->ddlist.label->coords.y1; + id = p.y / (font_h + style_label->text.line_space); + if(id < 0) id = 0; + if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1; + ext->ddlist.sel_opt_id = id; + if(ext->ddlist.action) ext->ddlist.action(roller); + } + } + + /*Position the scrollable according to the new selected option*/ + if(id != -1) { + refr_position(roller, true); + } + + return res; +} + +/** + * Draw a rectangle which has gradient on its top and bottom + * @param roller pointer to a roller object + * @param mask pointer to the current mask (from the design function) + */ +static void draw_bg(lv_obj_t * roller, const lv_area_t * mask) +{ + lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG); + lv_area_t half_mask; + lv_area_t half_roller; + lv_coord_t h = lv_obj_get_height(roller); + bool union_ok; + lv_area_copy(&half_roller, &roller->coords); + + half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */ + half_roller.x2 += roller->ext_size; + half_roller.y1 -= roller->ext_size; + half_roller.y2 = roller->coords.y1 + h / 2; + + union_ok = lv_area_intersect(&half_mask, &half_roller, mask); + + half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/ + half_roller.x2 -= roller->ext_size; + half_roller.y1 += roller->ext_size; + half_roller.y2 += style->body.radius; + + if(union_ok) { + lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller)); + } + + half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */ + half_roller.x2 += roller->ext_size; + half_roller.y2 = roller->coords.y2 + roller->ext_size; + half_roller.y1 = roller->coords.y1 + h / 2; + if((h & 0x1) == 0) half_roller.y1++; /*With even height the pixels in the middle would be drawn twice*/ + + union_ok = lv_area_intersect(&half_mask, &half_roller, mask); + + half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/ + half_roller.x2 -= roller->ext_size; + half_roller.y2 -= roller->ext_size; + half_roller.y1 -= style->body.radius; + + if(union_ok) { + lv_color_t main_tmp = style->body.main_color; + lv_color_t grad_tmp = style->body.grad_color; + + style->body.main_color = grad_tmp; + style->body.grad_color = main_tmp; + lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller)); + style->body.main_color = main_tmp; + style->body.grad_color = grad_tmp; + } +} + +/** + * Refresh the position of the roller. It uses the id stored in: ext->ddlist.selected_option_id + * @param roller pointer to a roller object + * @param anim_en true: refresh with animation; false: without animation + */ +static void refr_position(lv_obj_t * roller, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_obj_t * roller_scrl = lv_page_get_scrl(roller); + lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller); + lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label); + const lv_font_t * font = style_label->text.font; + lv_coord_t font_h = lv_font_get_height(font); + lv_coord_t h = lv_obj_get_height(roller); + int32_t id = ext->ddlist.sel_opt_id; + lv_coord_t line_y1 = id * (font_h + style_label->text.line_space) + ext->ddlist.label->coords.y1 - roller_scrl->coords.y1; + lv_coord_t new_y = - line_y1 + (h - font_h) / 2; + + if(ext->ddlist.anim_time == 0 || anim_en == false) { + lv_obj_set_y(roller_scrl, new_y); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = roller_scrl; + a.start = lv_obj_get_y(roller_scrl); + a.end = new_y; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->ddlist.anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.h new file mode 100644 index 0000000..2f1b21c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_roller.h @@ -0,0 +1,224 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_ROLLER != 0 + +/*Testing of dependencies*/ +#if USE_LV_DDLIST == 0 +#error "lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_ddlist.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of roller*/ +typedef struct { + lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_roller_ext_t; + +enum { + LV_ROLLER_STYLE_BG, + LV_ROLLER_STYLE_SEL, +}; +typedef uint8_t lv_roller_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left, right or center[default]) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align); + +/** + * Set the options on a roller + * @param roller pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +static inline void lv_roller_set_options(lv_obj_t * roller, const char * options) +{ + lv_ddlist_set_options(roller, options); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en); + +/** + * Set a function to call when a new option is chosen + * @param roller pointer to a roller + * @param action pointer to a callback function + */ +static inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action) +{ + lv_ddlist_set_action(roller, action); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt); + +/** + * Enable or disable the horizontal fit to the content + * @param roller pointer to a roller + * @param en true: enable auto fit; false: disable auto fit + */ +static inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en) +{ + lv_ddlist_set_hor_fit(roller, en); +} + +/** + * Set the open/close animation time. + * @param roller pointer to a roller object + * @param anim_time: open/close animation time [ms] + */ +static inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time) +{ + lv_ddlist_set_anim_time(roller, anim_time); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller); + +/** + * Get the options of a roller + * @param roller pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +static inline const char * lv_roller_get_options(const lv_obj_t *roller) +{ + return lv_ddlist_get_options(roller); +} + +/** + * Get the id of the selected option + * @param roller pointer to a roller object + * @return id of the selected option (0 ... number of option - 1); + */ +static inline uint16_t lv_roller_get_selected(const lv_obj_t *roller) +{ + return lv_ddlist_get_selected(roller); +} + +/** + * Get the current selected option as a string + * @param roller pointer to roller object + * @param buf pointer to an array to store the string + */ +static inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf) +{ + lv_ddlist_get_selected_str(roller, buf); +} + +/** + * Get the "option selected" callback function + * @param roller pointer to a roller + * @return pointer to the call back function + */ +static inline lv_action_t lv_roller_get_action(const lv_obj_t * roller) +{ + return lv_ddlist_get_action(roller); +} + +/** + * Get the open/close animation time. + * @param roller pointer to a roller + * @return open/close animation time [ms] + */ +static inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller) +{ + return lv_ddlist_get_anim_time(roller); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t *roller); + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ROLLER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.c new file mode 100644 index 0000000..eaf04e8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.c @@ -0,0 +1,520 @@ + +/** + * @file lv_slider.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_slider.h" +#if USE_LV_SLIDER != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_SLIDER_SIZE_MIN 4 /*hor. pad and ver. pad cannot make the bar or indicator smaller then this [px]*/ +#define LV_SLIDER_NOT_PRESSED INT16_MIN + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design_f; +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("slider create started"); + + /*Create the ancestor slider*/ + lv_obj_t * new_slider = lv_bar_create(par, copy); + lv_mem_assert(new_slider); + if(new_slider == NULL) return NULL; + + if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_slider); + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_slider); + + /*Allocate the slider type specific extended data*/ + lv_slider_ext_t * ext = lv_obj_allocate_ext_attr(new_slider, sizeof(lv_slider_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->action = NULL; + ext->drag_value = LV_SLIDER_NOT_PRESSED; + ext->style_knob = &lv_style_pretty; + ext->knob_in = 0; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_slider, lv_slider_signal); + lv_obj_set_design_func(new_slider, lv_slider_design); + + /*Init the new slider slider*/ + if(copy == NULL) { + lv_obj_set_click(new_slider, true); + lv_obj_set_protect(new_slider, LV_PROTECT_PRESS_LOST); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_BG, th->slider.bg); + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_INDIC, th->slider.indic); + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, th->slider.knob); + } else { + lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, ext->style_knob); + } + } + /*Copy an existing slider*/ + else { + lv_slider_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->style_knob = copy_ext->style_knob; + ext->action = copy_ext->action; + ext->knob_in = copy_ext->knob_in; + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_slider); + } + + + LV_LOG_INFO("slider created"); + + + return new_slider; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + ext->action = action; +} + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + if(ext->knob_in == in) return; + + ext->knob_in = in == false ? 0 : 1; + lv_obj_invalidate(slider); +} + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t * slider, lv_slider_style_t type, lv_style_t * style) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + switch(type) { + case LV_SLIDER_STYLE_BG: + lv_bar_set_style(slider, LV_BAR_STYLE_BG, style); + break; + case LV_SLIDER_STYLE_INDIC: + lv_bar_set_style(slider, LV_BAR_STYLE_INDIC, style); + break; + case LV_SLIDER_STYLE_KNOB: + ext->style_knob = style; + lv_obj_refresh_ext_size(slider); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + if(ext->drag_value != LV_SLIDER_NOT_PRESSED) return ext->drag_value; + else return lv_bar_get_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->action; +} + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->drag_value == LV_SLIDER_NOT_PRESSED ? false : true; +} + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider) +{ + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + return ext->knob_in == 0 ? false : true; +} + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t * slider, lv_slider_style_t type) +{ + lv_style_t * style = NULL; + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + switch(type) { + case LV_SLIDER_STYLE_BG: + style = lv_bar_get_style(slider, LV_BAR_STYLE_BG); + break; + case LV_SLIDER_STYLE_INDIC: + style = lv_bar_get_style(slider, LV_BAR_STYLE_INDIC); + break; + case LV_SLIDER_STYLE_KNOB: + style = ext->style_knob; + break; + default: + style = NULL; + break; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Handle the drawing related tasks of the sliders + * @param slider pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + + lv_style_t * style_bg = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG); + lv_style_t * style_knob = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB); + lv_style_t * style_indic = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC); + + lv_opa_t opa_scale = lv_obj_get_opa_scale(slider); + + lv_coord_t slider_w = lv_area_get_width(&slider->coords); + lv_coord_t slider_h = lv_area_get_height(&slider->coords); + + /*Draw the bar*/ + lv_area_t area_bg; + lv_area_copy(&area_bg, &slider->coords); + + /*Be sure at least LV_SLIDER_SIZE_MIN size will remain*/ + lv_coord_t pad_ver_bg = style_bg->body.padding.ver; + lv_coord_t pad_hor_bg = style_bg->body.padding.hor; + if(pad_ver_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) { + pad_ver_bg = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + if(pad_hor_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) { + pad_hor_bg = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + + if(ext->knob_in) { /*Enable extra size if the knob is inside */ + area_bg.x1 += pad_hor_bg; + area_bg.x2 -= pad_hor_bg; + area_bg.y1 += pad_hor_bg; + area_bg.y2 -= pad_hor_bg; + } else { /*Let space only in the perpendicular directions*/ + area_bg.x1 += slider_w < slider_h ? pad_hor_bg : 0; /*Pad only for vertical slider*/ + area_bg.x2 -= slider_w < slider_h ? pad_hor_bg : 0; /*Pad only for vertical slider*/ + area_bg.y1 += slider_w > slider_h ? pad_ver_bg : 0; /*Pad only for horizontal slider*/ + area_bg.y2 -= slider_w > slider_h ? pad_ver_bg : 0; /*Pad only for horizontal slider*/ + } + + +#if USE_LV_GROUP == 0 + lv_draw_rect(&area_bg, mask, style_bg, lv_obj_get_opa_scale(slider)); +#else + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(slider)) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.border.width = 0; + lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale); + } else { + lv_draw_rect(&area_bg, mask, style_bg, opa_scale); + } +#endif + + + /*Draw the indicator*/ + lv_area_t area_indic; + lv_area_copy(&area_indic, &area_bg); + + /*Be sure at least ver pad/hor pad width indicator will remain*/ + lv_coord_t pad_ver_indic = style_indic->body.padding.ver; + lv_coord_t pad_hor_indic = style_indic->body.padding.hor; + if(pad_ver_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) { + pad_ver_indic = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + if(pad_hor_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) { + pad_hor_indic = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1; + } + + area_indic.x1 += pad_hor_indic; + area_indic.x2 -= pad_hor_indic; + area_indic.y1 += pad_ver_indic; + area_indic.y2 -= pad_ver_indic; + + + lv_coord_t cur_value = lv_slider_get_value(slider); + lv_coord_t min_value = lv_slider_get_min_value(slider); + lv_coord_t max_value = lv_slider_get_max_value(slider); + + /*If dragged draw to the drag position*/ + if(ext->drag_value != LV_SLIDER_NOT_PRESSED) cur_value = ext->drag_value; + + if(slider_w >= slider_h) { + area_indic.x2 = (int32_t)((int32_t)(lv_area_get_width(&area_indic)) * (cur_value - min_value)) / (max_value - min_value); + area_indic.x2 = area_indic.x1 + area_indic.x2 - 1; + + } else { + area_indic.y1 = (int32_t)((int32_t)(lv_area_get_height(&area_indic)) * (cur_value - min_value)) / (max_value - min_value); + area_indic.y1 = area_indic.y2 - area_indic.y1 + 1; + } + + if(cur_value != min_value) lv_draw_rect(&area_indic, mask, style_indic, opa_scale); + + /*Before the knob add the border if required*/ +#if USE_LV_GROUP + /* Draw the borders later if the bar is focused. + * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/ + if(lv_obj_is_focused(slider)) { + lv_style_t style_tmp; + lv_style_copy(&style_tmp, style_bg); + style_tmp.body.empty = 1; + style_tmp.body.shadow.width = 0; + lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale); + } +#endif + + /*Draw the knob*/ + lv_area_t knob_area; + lv_area_copy(&knob_area, &slider->coords); + + if(slider_w >= slider_h) { + if(ext->knob_in == 0) { + knob_area.x1 = area_indic.x2 - slider_h / 2; + knob_area.x2 = knob_area.x1 + slider_h - 1; + } else { + knob_area.x1 = (int32_t)((int32_t)(slider_w - slider_h - 1) * (cur_value - min_value)) / (max_value - min_value); + knob_area.x1 += slider->coords.x1; + knob_area.x2 = knob_area.x1 + slider_h - 1; + } + + knob_area.y1 = slider->coords.y1; + knob_area.y2 = slider->coords.y2; + } else { + if(ext->knob_in == 0) { + knob_area.y1 = area_indic.y1 - slider_w / 2; + knob_area.y2 = knob_area.y1 + slider_w - 1; + } else { + knob_area.y2 = (int32_t)((int32_t)(slider_h - slider_w - 1) * (cur_value - min_value)) / (max_value - min_value); + knob_area.y2 = slider->coords.y2 - knob_area.y2; + knob_area.y1 = knob_area.y2 - slider_w - 1; + } + knob_area.x1 = slider->coords.x1; + knob_area.x2 = slider->coords.x2; + + } + lv_draw_rect(&knob_area, mask, style_knob, opa_scale); + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the slider + * @param slider pointer to a slider object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(slider, sign, param); + if(res != LV_RES_OK) return res; + + lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider); + lv_point_t p; + lv_coord_t w = lv_obj_get_width(slider); + lv_coord_t h = lv_obj_get_height(slider); + + if(sign == LV_SIGNAL_PRESSED) { + ext->drag_value = lv_slider_get_value(slider); + } else if(sign == LV_SIGNAL_PRESSING) { + lv_indev_get_point(param, &p); + int16_t tmp = 0; + if(w > h) { + lv_coord_t knob_w = h; + p.x -= slider->coords.x1 + h / 2; /*Modify the point to shift with half knob (important on the start and end)*/ + tmp = (int32_t)((int32_t) p.x * (ext->bar.max_value - ext->bar.min_value + 1)) / (w - knob_w); + tmp += ext->bar.min_value; + } else { + lv_coord_t knob_h = w; + p.y -= slider->coords.y1 + w / 2; /*Modify the point to shift with half knob (important on the start and end)*/ + tmp = (int32_t)((int32_t) p.y * (ext->bar.max_value - ext->bar.min_value + 1)) / (h - knob_h); + tmp = ext->bar.max_value - tmp; /*Invert the value: smaller value means higher y*/ + } + + if(tmp < ext->bar.min_value) tmp = ext->bar.min_value; + else if(tmp > ext->bar.max_value) tmp = ext->bar.max_value; + + if(tmp != ext->drag_value) { + ext->drag_value = tmp; + lv_obj_invalidate(slider); + if(ext->action != NULL) res = ext->action(slider); + } + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + lv_slider_set_value(slider, ext->drag_value); + ext->drag_value = LV_SLIDER_NOT_PRESSED; + if(ext->action != NULL) res = ext->action(slider); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /* The knob size depends on slider size. + * During the drawing method the ext. size is used by the knob so refresh the ext. size.*/ + if(lv_obj_get_width(slider) != lv_area_get_width(param) || + lv_obj_get_height(slider) != lv_area_get_height(param)) { + slider->signal_func(slider, LV_SIGNAL_REFR_EXT_SIZE, NULL); + } + } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + lv_style_t * style = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG); + lv_style_t * knob_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB); + lv_coord_t shadow_w = knob_style->body.shadow.width; + if(ext->knob_in == 0) { + /* The smaller size is the knob diameter*/ + lv_coord_t x = LV_MATH_MIN(w / 2 + 1 + shadow_w, h / 2 + 1 + shadow_w); + if(slider->ext_size < x) slider->ext_size = x; + } else { + lv_coord_t pad = LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver); + if(pad < 0) pad = -pad; + if(slider->ext_size < pad) slider->ext_size = pad; + + if(slider->ext_size < shadow_w) slider->ext_size = shadow_w; + } + } else if(sign == LV_SIGNAL_CONTROLL) { + char c = *((char *)param); + + ext->drag_value = LV_SLIDER_NOT_PRESSED; + +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(slider); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER && c == LV_GROUP_KEY_ENTER) { + if(editing) lv_group_set_editing(g, false); + } +#endif + if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) { + lv_slider_set_value(slider, lv_slider_get_value(slider) + 1); + if(ext->action != NULL) res = ext->action(slider); + } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) { + lv_slider_set_value(slider, lv_slider_get_value(slider) - 1); + if(ext->action != NULL) res = ext->action(slider); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_slider"; + } + + return res; +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.h new file mode 100644 index 0000000..6336ae8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_slider.h @@ -0,0 +1,202 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SLIDER != 0 + +/*Testing of dependencies*/ +#if USE_LV_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of slider*/ +typedef struct +{ + lv_bar_ext_t bar; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t action; /*Function to call when a new value is set*/ + lv_style_t *style_knob; /*Style of the knob*/ + int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/ + uint8_t knob_in :1; /*1: Draw the knob inside the bar*/ +} lv_slider_ext_t; + +/*Built-in styles of slider*/ +enum +{ + LV_SLIDER_STYLE_BG, + LV_SLIDER_STYLE_INDIC, + LV_SLIDER_STYLE_KNOB, +}; +typedef uint8_t lv_slider_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param slider pointer to a slider object + * @param value new value + */ +static inline void lv_slider_set_value(lv_obj_t * slider, int16_t value) +{ + lv_bar_set_value(slider, value); +} + +/** + * Set a new value with animation on a slider + * @param slider pointer to a slider object + * @param value new value + * @param anim_time animation time in milliseconds + */ +static inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time) +{ + lv_bar_set_value_anim(slider, value, anim_time); +} + +/** + * Set minimum and the maximum values of a bar + * @param slider pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max) +{ + lv_bar_set_range(slider, min, max); +} + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action); + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in); + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider); + +/** + * Get the minimum value of a slider + * @param slider pointer to a slider object + * @return the minimum value of the slider + */ +static inline int16_t lv_slider_get_min_value(const lv_obj_t * slider) +{ + return lv_bar_get_min_value(slider); +} + +/** + * Get the maximum value of a slider + * @param slider pointer to a slider object + * @return the maximum value of the slider + */ +static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) +{ + return lv_bar_get_max_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider); + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider); + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider); + + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SLIDER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.c new file mode 100644 index 0000000..70fac33 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.c @@ -0,0 +1,471 @@ +/** + * @file lv_spinbox.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_spinbox.h" + +#if USE_LV_SPINBOX != 0 +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param); +static void lv_spinbox_updatevalue(lv_obj_t * spinbox); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a spinbox object + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("spinbox create started"); + + /*Create the ancestor of spinbox*/ + lv_obj_t * new_spinbox = lv_ta_create(par, copy); + lv_mem_assert(new_spinbox); + if(new_spinbox == NULL) return NULL; + + /*Allocate the spinbox type specific extended data*/ + lv_spinbox_ext_t * ext = lv_obj_allocate_ext_attr(new_spinbox, sizeof(lv_spinbox_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_spinbox); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_spinbox); + + /*Initialize the allocated 'ext'*/ + ext->ta.one_line = 1; + ext->ta.pwd_mode = 0; + ext->ta.accapted_chars = "1234567890+-. "; + + ext->value = 0; + ext->dec_point_pos = 0; + ext->digit_count = 5; + ext->digit_padding_left = 0; + ext->step = 1; + ext->range_max = 99999; + ext->range_min = -99999; + ext->value_changed_cb = NULL; + + lv_ta_set_cursor_type(new_spinbox, LV_CURSOR_BLOCK | LV_CURSOR_HIDDEN); /*hidden by default*/ + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_spinbox, lv_spinbox_signal); + lv_obj_set_design_func(new_spinbox, ancestor_design); /*Leave the Text area's design function*/ + + /*Init the new spinbox spinbox*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_BG, th->spinbox.bg); + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_CURSOR, th->spinbox.cursor); + lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_SB, th->spinbox.sb); + } + } + /*Copy an existing spinbox*/ + else { + lv_spinbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + + lv_spinbox_set_value(new_spinbox, copy_ext->value); + lv_spinbox_set_digit_format(new_spinbox, copy_ext->digit_count, copy_ext->dec_point_pos); + lv_spinbox_set_range(new_spinbox, copy_ext->range_min, copy_ext->range_max); + lv_spinbox_set_step(new_spinbox, copy_ext->step); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_spinbox); + } + + lv_spinbox_updatevalue(new_spinbox); + + LV_LOG_INFO("spinbox created"); + + return new_spinbox; +} + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) + return; + + if(i > ext->range_max) + i = ext->range_max; + if(i < ext->range_min) + i = ext->range_min; + + ext->value = i; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) + return; + + if(digit_count > LV_SPINBOX_MAX_DIGIT_COUNT) + digit_count = LV_SPINBOX_MAX_DIGIT_COUNT; + + if(separator_position > LV_SPINBOX_MAX_DIGIT_COUNT) + separator_position = LV_SPINBOX_MAX_DIGIT_COUNT; + + ext->digit_count = digit_count; + ext->dec_point_pos = separator_position; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) return; + + ext->step = step; +} + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + if(ext == NULL) return; + + ext->range_max = range_max; + ext->range_min = range_min; + + if(ext->value > ext->range_max) { + ext->value = ext->range_max; + lv_obj_invalidate(spinbox); + } + if(ext->value < ext->range_min) { + ext->value = ext->range_min; + lv_obj_invalidate(spinbox); + } +} + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + ext->value_changed_cb = cb; +} + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + ext->digit_padding_left = padding; + lv_spinbox_updatevalue(spinbox); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + return ext->value; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + int32_t new_step = ext->step / 10; + if((new_step) > 0) ext->step = new_step; + else ext->step = 1; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + int32_t step_limit; + step_limit = LV_MATH_MAX(ext->range_max, (ext->range_min < 0 ? (-ext->range_min) : ext->range_min)); + int32_t new_step = ext->step * 10; + if(new_step <= step_limit) ext->step = new_step; + + lv_spinbox_updatevalue(spinbox); +} + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + if(ext->value + ext->step <= ext->range_max) { + /*Special mode when zero crossing*/ + if((ext->value + ext->step) > 0 && ext->value < 0) ext->value = -ext->value; + ext->value += ext->step; + + } else { + ext->value = ext->range_max; + } + + if(ext->value_changed_cb != NULL) ext->value_changed_cb(spinbox, ext->value); + lv_spinbox_updatevalue(spinbox); +} + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + if(ext->value - ext->step >= ext->range_min) { + /*Special mode when zero crossing*/ + if((ext->value - ext->step) < 0 && ext->value > 0) ext->value = -ext->value; + ext->value -= ext->step; + } else { + ext->value = ext->range_min; + } + + if(ext->value_changed_cb != NULL) ext->value_changed_cb(spinbox, ext->value); + lv_spinbox_updatevalue(spinbox); +} + + + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the spinbox + * @param spinbox pointer to a spinbox object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param) +{ + + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + lv_res_t res = LV_RES_OK; + + /* Include the ancient signal function */ + if(sign != LV_SIGNAL_CONTROLL) + { + res = ancestor_signal(spinbox, sign, param); + if(res != LV_RES_OK) return res; + } + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) + { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) + { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_spinbox"; + } + else if(sign == LV_SIGNAL_CONTROLL) { + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + uint32_t c = *((uint32_t *)param); /*uint32_t because can be UTF-8*/ + if(c == LV_GROUP_KEY_RIGHT) { + if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_increment(spinbox); + else lv_spinbox_step_next(spinbox); + } + else if(c == LV_GROUP_KEY_LEFT) { + if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_decrement(spinbox); + else lv_spinbox_step_previous(spinbox); + } + else if(c == LV_GROUP_KEY_UP) { + lv_spinbox_increment(spinbox); + } + else if(c == LV_GROUP_KEY_DOWN) { + lv_spinbox_decrement(spinbox); + } + else if(c == LV_GROUP_KEY_ENTER) { + + if(ext->step > 1) { + lv_spinbox_step_next(spinbox); + } else { + /*Restart from the MSB*/ + ext->step = 1; + uint32_t i; + for(i = 0; i < ext->digit_count; i++) { + int32_t new_step = ext->step * 10; + if(new_step >= ext->range_max) break; + ext->step = new_step; + } + lv_spinbox_step_previous(spinbox); + } + } + else { + lv_ta_add_char(spinbox, c); + } + } + + return res; +} + +static void lv_spinbox_updatevalue(lv_obj_t * spinbox) +{ + lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox); + + char buf[LV_SPINBOX_MAX_DIGIT_COUNT + 8]; + memset(buf, 0, sizeof(buf)); + char * buf_p = buf; + + /*Add the sign*/ + (*buf_p) = ext->value >= 0 ? '+' : '-'; + buf_p++; + + int i; + /*padding left*/ + for(i = 0; i < ext->digit_padding_left; i++) { + (*buf_p) = ' '; + buf_p++; + } + + char digits[64]; + /*Convert the numbers to string (the sign is already handled so always covert positive number)*/ + lv_math_num_to_str(ext->value < 0 ? -ext->value : ext->value, digits); + + /*Add leading zeros*/ + int lz_cnt = ext->digit_count - (int)strlen(digits); + if(lz_cnt > 0) { + for(i = strlen(digits); i >= 0; i--) { + digits[i + lz_cnt] = digits[i]; + } + for(i = 0; i < lz_cnt; i++) { + digits[i] = '0'; + } + } + + int32_t intDigits; + intDigits = (ext->dec_point_pos == 0) ? ext->digit_count : ext->dec_point_pos; + + /*Add the decimal part*/ + for(i = 0; i < intDigits && digits[i] != '\0'; i++) { + (*buf_p) = digits[i]; + buf_p++; + } + + if(ext->dec_point_pos != 0) { + /*Insert the decimal point*/ + (*buf_p) = '.'; + buf_p++; + + for(/*Leave i*/ ;i < ext->digit_count && digits[i] != '\0'; i++) { + (*buf_p) = digits[i]; + buf_p++; + } + } + + /*Refresh the text*/ + lv_ta_set_text(spinbox, (char*)buf); + + + /*Set the cursor position*/ + int32_t step = ext->step; + uint8_t cur_pos = ext->digit_count; + while(step >= 10) + { + step /= 10; + cur_pos--; + } + + if(cur_pos > intDigits ) cur_pos ++; /*Skip teh decimal point*/ + + cur_pos += ext->digit_padding_left; + + lv_ta_set_cursor_pos(spinbox, cur_pos); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.h new file mode 100644 index 0000000..ca57614 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_spinbox.h @@ -0,0 +1,201 @@ +/** + * @file lv_spinbox.h + * + */ + + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SPINBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_TA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_ta.h" + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 16 + +/********************** + * TYPEDEFS + **********************/ + +/*callback on value change*/ +typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value); + +/*Data of spinbox*/ +typedef struct { + lv_ta_ext_t ta; /*Ext. of ancestor*/ + /*New data for this type */ + int32_t value; + int32_t range_max; + int32_t range_min; + int32_t step; + uint16_t digit_count:4; + uint16_t dec_point_pos:4; /*if 0, there is no separator and the number is an integer*/ + uint16_t digit_padding_left:4; + lv_spinbox_value_changed_cb_t value_changed_cb; +} lv_spinbox_ext_t; + + +/*Styles*/ +enum { + LV_SPINBOX_STYLE_BG, + LV_SPINBOX_STYLE_SB, + LV_SPINBOX_STYLE_CURSOR, +}; +typedef uint8_t lv_spinbox_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spinbox objects + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a spinbox. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +static inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style) +{ + lv_ta_set_style(spinbox, type, style); +} + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step); + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max); + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb); + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a spinbox. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +static inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type) +{ + return lv_ta_get_style(spinbox, type); +} + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox); + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox); + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SPINBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPINBOX_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.c new file mode 100644 index 0000000..2b09354 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.c @@ -0,0 +1,445 @@ +/** + * @file lv_sw.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_sw.h" + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1) " +#endif + +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param); +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("switch create started"); + + /*Create the ancestor of switch*/ + lv_obj_t * new_sw = lv_slider_create(par, copy); + lv_mem_assert(new_sw); + if(new_sw == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_sw); + + /*Allocate the switch type specific extended data*/ + lv_sw_ext_t * ext = lv_obj_allocate_ext_attr(new_sw, sizeof(lv_sw_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->changed = 0; +#if USE_LV_ANIMATION + ext->anim_time = 0; +#endif + ext->style_knob_off = ext->slider.style_knob; + ext->style_knob_on = ext->slider.style_knob; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_sw, lv_sw_signal); + + /*Init the new switch switch*/ + if(copy == NULL) { + lv_slider_set_range(new_sw, 0, 1); + lv_obj_set_size(new_sw, 2 * LV_DPI / 3, LV_DPI / 3); + lv_slider_set_knob_in(new_sw, true); + lv_slider_set_range(new_sw, 0, LV_SWITCH_SLIDER_ANIM_MAX); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_sw_set_style(new_sw, LV_SW_STYLE_BG, th->sw.bg); + lv_sw_set_style(new_sw, LV_SW_STYLE_INDIC, th->sw.indic); + lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_OFF, th->sw.knob_off); + lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_ON, th->sw.knob_on); + } else { + /*Let the slider' style*/ + } + + } + /*Copy an existing switch*/ + else { + lv_sw_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->style_knob_off = copy_ext->style_knob_off; + ext->style_knob_on = copy_ext->style_knob_on; +#if USE_LV_ANIMATION + ext->anim_time = copy_ext->anim_time; +#endif + + if(lv_sw_get_state(new_sw)) lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); + else lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); + + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_sw); + } + + LV_LOG_INFO("switch created"); + + return new_sw; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +} + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + lv_slider_set_value(sw, 0); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +} + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw) { + bool state = lv_sw_get_state(sw); + if(state) { + lv_sw_off(sw); + } + else { + lv_sw_on(sw); + } + return !state; +} + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + if(lv_sw_get_anim_time(sw) > 0)lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + else lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +} + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + if(lv_sw_get_anim_time(sw) > 0) lv_sw_anim_to_value(sw, 0); + else lv_slider_set_value(sw, 0); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +} + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw) { + bool state = lv_sw_get_state(sw); + if(state) { + lv_sw_off_anim(sw); + } + else { + lv_sw_on_anim(sw); + } + return !state; +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, lv_style_t * style) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + switch(type) { + case LV_SLIDER_STYLE_BG: + lv_slider_set_style(sw, LV_SLIDER_STYLE_BG, style); + break; + case LV_SLIDER_STYLE_INDIC: + lv_bar_set_style(sw, LV_SLIDER_STYLE_INDIC, style); + break; + case LV_SW_STYLE_KNOB_OFF: + ext->style_knob_off = style; + if(lv_sw_get_state(sw) == 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style); + break; + case LV_SW_STYLE_KNOB_ON: + ext->style_knob_on = style; + if(lv_sw_get_state(sw) != 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style); + break; + } +} + +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time) +{ +#if USE_LV_ANIMATION + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + ext->anim_time = anim_time; +#endif +} + + +/*===================== + * Getter functions + *====================*/ + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t * sw, lv_sw_style_t type) +{ + lv_style_t * style = NULL; + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + switch(type) { + case LV_SW_STYLE_BG: + style = lv_slider_get_style(sw, LV_SLIDER_STYLE_BG); + break; + case LV_SW_STYLE_INDIC: + style = lv_slider_get_style(sw, LV_SLIDER_STYLE_INDIC); + break; + case LV_SW_STYLE_KNOB_OFF: + style = ext->style_knob_off; + break; + case LV_SW_STYLE_KNOB_ON: + style = ext->style_knob_on; + break; + default: + style = NULL; + break; + } + + return style; +} + +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw) +{ + +#if USE_LV_ANIMATION + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + return ext->anim_time; +#else + return 0; +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the switch + * @param sw pointer to a switch object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + /*Save the current (old) value before slider signal modifies it*/ + int16_t old_val; + + if(sign == LV_SIGNAL_PRESSING) old_val = ext->slider.drag_value; + else old_val = lv_slider_get_value(sw); + + /*Do not let the slider to call the callback. The Switch will do it if required*/ + lv_action_t slider_action = ext->slider.action; + ext->slider.action = NULL; + + lv_res_t res; + /* Include the ancient signal function */ + res = ancestor_signal(sw, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } + else if(sign == LV_SIGNAL_PRESSED) { + + /*Save the x coordinate of the pressed point to see if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p; + lv_indev_get_point(indev, &p); + ext->start_x = p.x; + } + ext->slided = 0; + ext->changed = 0; + } + else if(sign == LV_SIGNAL_PRESSING) { + /*See if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p = {0,0}; + lv_indev_get_point(indev, &p); + if(LV_MATH_ABS(p.x - ext->start_x) > LV_INDEV_DRAG_LIMIT) ext->slided = 1; + } + + /*If didn't slide then revert the min/max value. So click without slide won't move the switch as a slider*/ + if(ext->slided == 0) { + if(lv_sw_get_state(sw)) ext->slider.drag_value = LV_SWITCH_SLIDER_ANIM_MAX; + else ext->slider.drag_value = 0; + } + + /*If explicitly changed (by slide) don't need to be toggled on release*/ + int16_t threshold = LV_SWITCH_SLIDER_ANIM_MAX / 2; + if((old_val < threshold && ext->slider.drag_value > threshold) || + (old_val > threshold && ext->slider.drag_value < threshold)) + { + ext->changed = 1; + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + if(lv_sw_get_state(sw)) { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +#if USE_LV_ANIMATION + lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); +#endif + } + else { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +#if USE_LV_ANIMATION + lv_sw_anim_to_value(sw, 0); +#endif + } + } + else if(sign == LV_SIGNAL_RELEASED) { + /*If not dragged then toggle the switch*/ + if(ext->changed == 0) { + if(lv_sw_get_state(sw)) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); + + if(slider_action != NULL) res = slider_action(sw); + } + /*If the switch was dragged then calculate the new state based on the current position*/ + else { + int16_t v = lv_slider_get_value(sw); + if(v > LV_SWITCH_SLIDER_ANIM_MAX / 2) lv_sw_on_anim(sw); + else lv_sw_off_anim(sw); + + if(slider_action != NULL) res = slider_action(sw); + } + + } else if(sign == LV_SIGNAL_CONTROLL) { + + char c = *((char *)param); + if(c == LV_GROUP_KEY_ENTER) { + if(old_val) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); + + if(slider_action) res = slider_action(sw); + } else if(c == LV_GROUP_KEY_UP || c == LV_GROUP_KEY_RIGHT) { + lv_sw_on_anim(sw); + if(slider_action) res = slider_action(sw); + } else if(c == LV_GROUP_KEY_DOWN || c == LV_GROUP_KEY_LEFT) { + lv_sw_off_anim(sw); + if(slider_action) res = slider_action(sw); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = false; /*The ancestor slider is editable the switch is not*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_sw"; + } + + /*Restore the callback*/ + if(res == LV_RES_OK) ext->slider.action = slider_action; + + return res; +} + +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value) +{ +#if USE_LV_ANIMATION + lv_anim_t a; + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + a.var = sw; + a.start = ext->slider.bar.cur_value; + a.end = value; + a.fp = (lv_anim_fp_t)lv_slider_set_value; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = lv_sw_get_anim_time(sw); + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.h new file mode 100644 index 0000000..28b22f7 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_sw.h @@ -0,0 +1,194 @@ +/** + * @file lv_sw.h + * + */ + +#ifndef LV_SW_H +#define LV_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1)" +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_slider.h" + +/********************* + * DEFINES + *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 + +/********************** + * TYPEDEFS + **********************/ +/*Data of switch*/ +typedef struct +{ + lv_slider_ext_t slider; /*Ext. of ancestor*/ + /*New data for this type */ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; +#if USE_LV_ANIMATION + uint16_t anim_time; /*switch animation time */ +#endif +} lv_sw_ext_t; + +enum { + LV_SW_STYLE_BG, + LV_SW_STYLE_INDIC, + LV_SW_STYLE_KNOB_OFF, + LV_SW_STYLE_KNOB_ON, +}; +typedef uint8_t lv_sw_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t *sw); + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t *sw); + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw); + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw); + +/** + * Set a function which will be called when the switch is toggled by the user + * @param sw pointer to switch object + * @param action a callback function + */ +static inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action) +{ + lv_slider_set_action(sw, action); +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style); + +#if USE_LV_ANIMATION +/** + * Set the animation time of the switch + * @param sw pointer to a switch object + * @param anim_time animation time + * @return style pointer to a style + */ +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); +#endif + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the state of a switch + * @param sw pointer to a switch object + * @return false: OFF; true: ON + */ +static inline bool lv_sw_get_state(const lv_obj_t *sw) +{ + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; +} + +/** + * Get the switch action function + * @param slider pointer to a switch object + * @return the callback function + */ +static inline lv_action_t lv_sw_get_action(const lv_obj_t * slider) +{ + return lv_slider_get_action(slider); +} + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type); + +/** + * Get the animation time of the switch + * @param sw pointer to a switch object + * @return style pointer to a style + */ +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SW_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.c new file mode 100644 index 0000000..e3492a0 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.c @@ -0,0 +1,1365 @@ +/** + * @file lv_ta.c + * + */ + + +/********************* + * INCLUDES + *********************/ +#include "lv_ta.h" +#if USE_LV_TA != 0 + +#include "../lv_core/lv_group.h" +#include "../lv_core/lv_refr.h" +#include "../lv_draw/lv_draw.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +/*Test configuration*/ + +#ifndef LV_TA_CURSOR_BLINK_TIME +#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#endif + +#ifndef LV_TA_PWD_SHOW_TIME +#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define LV_TA_DEF_WIDTH (2 * LV_DPI) +#define LV_TA_DEF_HEIGHT (1 * LV_DPI) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode); +static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param); +static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +#if USE_LV_ANIMATION +static void cursor_blink_anim(lv_obj_t * ta, uint8_t show); +static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x); +#endif +static void pwd_char_hider(lv_obj_t * ta); +static bool char_is_accepted(lv_obj_t * ta, uint32_t c); +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res); +static void refr_cursor_area(lv_obj_t * ta); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_design_func_t ancestor_design; +static lv_design_func_t scrl_design; +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t scrl_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("text area create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_ta = lv_page_create(par, copy); + lv_mem_assert(new_ta); + if(new_ta == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ta); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ta); + if(scrl_signal == NULL) scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ta)); + if(scrl_design == NULL) scrl_design = lv_obj_get_design_func(lv_page_get_scrl(new_ta)); + + /*Allocate the object type specific extended data*/ + lv_ta_ext_t * ext = lv_obj_allocate_ext_attr(new_ta, sizeof(lv_ta_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->cursor.state = 1; + ext->pwd_mode = 0; + ext->pwd_tmp = NULL; + ext->accapted_chars = NULL; + ext->max_length = 0; + ext->cursor.style = NULL; + ext->cursor.pos = 0; + ext->cursor.type = LV_CURSOR_LINE; + ext->cursor.valid_x = 0; + ext->one_line = 0; + ext->label = NULL; + + lv_obj_set_signal_func(new_ta, lv_ta_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_ta), lv_ta_scrollable_signal); + lv_obj_set_design_func(new_ta, lv_ta_design); + + /*Init the new text area object*/ + if(copy == NULL) { + ext->label = lv_label_create(new_ta, NULL); + + lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design); + + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK); + lv_label_set_text(ext->label, "Text area"); + lv_obj_set_click(ext->label, false); + lv_obj_set_size(new_ta, LV_TA_DEF_WIDTH, LV_TA_DEF_HEIGHT); + lv_ta_set_sb_mode(new_ta, LV_SB_MODE_DRAG); + lv_page_set_style(new_ta, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_ta_set_style(new_ta, LV_TA_STYLE_BG, th->ta.area); + lv_ta_set_style(new_ta, LV_TA_STYLE_SB, th->ta.sb); + } else { + lv_ta_set_style(new_ta, LV_TA_STYLE_BG, &lv_style_pretty); + } + } + /*Copy an existing object*/ + else { + lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design); + lv_ta_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->label = lv_label_create(new_ta, copy_ext->label); + ext->pwd_mode = copy_ext->pwd_mode; + ext->accapted_chars = copy_ext->accapted_chars; + ext->max_length = copy_ext->max_length; + ext->cursor.style = copy_ext->cursor.style; + ext->cursor.pos = copy_ext->cursor.pos; + ext->cursor.valid_x = copy_ext->cursor.valid_x; + ext->cursor.type = copy_ext->cursor.type; + if(copy_ext->one_line) lv_ta_set_one_line(new_ta, true); + + lv_ta_set_style(new_ta, LV_TA_STYLE_CURSOR, lv_ta_get_style(copy, LV_TA_STYLE_CURSOR)); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_ta); + } + +#if USE_LV_ANIMATION + /*Create a cursor blinker animation*/ + lv_anim_t a; + a.var = new_ta; + a.fp = (lv_anim_fp_t)cursor_blink_anim; + a.time = LV_TA_CURSOR_BLINK_TIME; + a.act_time = 0; + a.end_cb = NULL; + a.start = 1; + a.end = 0; + a.repeat = 1; + a.repeat_pause = 0; + a.playback = 1; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#endif + + LV_LOG_INFO("text area created"); + + return new_ta; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Ã' use `lv_txt_encoded_conv_wc('Ã')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->one_line && (c == '\n' || c == '\r')) { + LV_LOG_INFO("Text area: line break ignored in one-line mode"); + return; + } + + uint32_t c_uni = lv_txt_encoded_next((const char *)&c, NULL); + + if(char_is_accepted(ta, c_uni) == false) { + LV_LOG_INFO("Character is no accepted by the text area (too long text or not in the accepted list)"); + return; + } + + /*Disable edge flash. If a new line was added it could show edge flash effect*/ + bool edge_flash_en = lv_ta_get_edge_flash(ta); + lv_ta_set_edge_flash(ta, false); + + if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ + uint32_t letter_buf[2]; + letter_buf[0] = c; + letter_buf[1] = '\0'; + + lv_label_ins_text(ext->label, ext->cursor.pos, (const char *)letter_buf); /*Insert the character*/ + + if(ext->pwd_mode != 0) { + + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 2); /*+2: the new char + \0 */ + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, (const char *)letter_buf); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } + + /*Move the cursor after the new character*/ + lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + 1); + + /*Revert the original edge flash state*/ + lv_ta_set_edge_flash(ta, edge_flash_en); +} + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ + + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c)); + } + return; + } + + /*Disable edge flash. If a new line was added it could show edge flash effect*/ + bool edge_flash_en = lv_ta_get_edge_flash(ta); + lv_ta_set_edge_flash(ta, false); + + /*Insert the text*/ + lv_label_ins_text(ext->label, ext->cursor.pos, txt); + + if(ext->pwd_mode != 0) { + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + strlen(txt) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, txt); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } + + /*Move the cursor after the new text*/ + lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + lv_txt_get_encoded_length(txt)); + + /*Revert the original edge flash state*/ + lv_ta_set_edge_flash(ta, edge_flash_en); +} + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + uint16_t cur_pos = ext->cursor.pos; + + if(cur_pos == 0) return; + + char * label_txt = lv_label_get_text(ext->label); + /*Delete a character*/ + lv_txt_cut(label_txt, ext->cursor.pos - 1, 1); + /*Refresh the label*/ + lv_label_set_text(ext->label, label_txt); + + /*Don't let 'width == 0' because cursor will not be visible*/ + if(lv_obj_get_width(ext->label) == 0) { + lv_style_t * style = lv_obj_get_style(ext->label); + lv_obj_set_width(ext->label, style->line.width); + } + + if(ext->pwd_mode != 0) { +#if LV_TXT_UTF8 == 0 + lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, 1); +#else + uint32_t byte_pos = lv_txt_encoded_get_byte_id(ext->pwd_tmp, ext->cursor.pos - 1); + lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, lv_txt_encoded_size(&label_txt[byte_pos])); +#endif + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + } + + /*Move the cursor to the place of the deleted character*/ + lv_ta_set_cursor_pos(ta, ext->cursor.pos - 1); +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + lv_label_set_text(ext->label, ""); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c)); + } + } else { + lv_label_set_text(ext->label, txt); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + } + + /*Don't let 'width == 0' because the cursor will not be visible*/ + if(lv_obj_get_width(ext->label) == 0) { + lv_style_t * style = lv_obj_get_style(ext->label); + lv_obj_set_width(ext->label, lv_font_get_width(style->text.font, ' ')); + } + + if(ext->pwd_mode != 0) { + ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(txt) + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + strcpy(ext->pwd_tmp, txt); + +#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0 + /*Auto hide characters*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)pwd_char_hider_anim; + a.time = LV_TA_PWD_SHOW_TIME; + a.act_time = 0; + a.end_cb = (lv_anim_cb_t)pwd_char_hider; + a.start = 0; + a.end = 1; + a.repeat = 0; + a.repeat_pause = 0; + a.playback = 0; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#else + pwd_char_hider(ta); +#endif + } +} + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->cursor.pos == pos) return; + + uint16_t len = lv_txt_get_encoded_length(lv_label_get_text(ext->label)); + + if(pos < 0) pos = len + pos; + + if(pos > len || pos == LV_TA_CURSOR_LAST) pos = len; + + ext->cursor.pos = pos; + + /*Position the label to make the cursor visible*/ + lv_obj_t * label_par = lv_obj_get_parent(ext->label); + lv_point_t cur_pos; + lv_style_t * style = lv_obj_get_style(ta); + const lv_font_t * font_p = style->text.font; + lv_area_t label_cords; + lv_area_t ta_cords; + lv_label_get_letter_pos(ext->label, pos, &cur_pos); + lv_obj_get_coords(ta, &ta_cords); + lv_obj_get_coords(ext->label, &label_cords); + + /*Check the top*/ + lv_coord_t font_h = lv_font_get_height(font_p); + if(lv_obj_get_y(label_par) + cur_pos.y < 0) { + lv_obj_set_y(label_par, - cur_pos.y + style->body.padding.ver); + } + + /*Check the bottom*/ + if(label_cords.y1 + cur_pos.y + font_h + style->body.padding.ver > ta_cords.y2) { + lv_obj_set_y(label_par, -(cur_pos.y - lv_obj_get_height(ta) + + font_h + 2 * style->body.padding.ver)); + } + /*Check the left (use the font_h as general unit)*/ + if(lv_obj_get_x(label_par) + cur_pos.x < font_h) { + lv_obj_set_x(label_par, - cur_pos.x + font_h); + } + + /*Check the right (use the font_h as general unit)*/ + if(label_cords.x1 + cur_pos.x + font_h + style->body.padding.hor > ta_cords.x2) { + lv_obj_set_x(label_par, -(cur_pos.x - lv_obj_get_width(ta) + + font_h + 2 * style->body.padding.hor)); + } + + ext->cursor.valid_x = cur_pos.x; + +#if USE_LV_ANIMATION + /*Reset cursor blink animation*/ + lv_anim_t a; + a.var = ta; + a.fp = (lv_anim_fp_t)cursor_blink_anim; + a.time = LV_TA_CURSOR_BLINK_TIME; + a.act_time = 0; + a.end_cb = NULL; + a.start = 1; + a.end = 0; + a.repeat = 1; + a.repeat_pause = 0; + a.playback = 1; + a.playback_pause = 0; + a.path = lv_anim_path_step; + lv_anim_create(&a); +#endif + + refr_cursor_area(ta); +} + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_ta_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->cursor.type == cur_type) return; + + ext->cursor.type = cur_type; + + refr_cursor_area(ta); +} + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->pwd_mode == en) return; + + /*Pwd mode is now enabled*/ + if(ext->pwd_mode == 0 && en != false) { + char * txt = lv_label_get_text(ext->label); + uint16_t len = strlen(txt); + ext->pwd_tmp = lv_mem_alloc(len + 1); + lv_mem_assert(ext->pwd_tmp); + if(ext->pwd_tmp == NULL) return; + + strcpy(ext->pwd_tmp, txt); + + uint16_t i; + for(i = 0; i < len; i++) { + txt[i] = '*'; /*All char to '*'*/ + } + txt[i] = '\0'; + + lv_label_set_text(ext->label, NULL); + } + /*Pwd mode is now disabled*/ + else if(ext->pwd_mode == 1 && en == false) { + lv_label_set_text(ext->label, ext->pwd_tmp); + lv_mem_free(ext->pwd_tmp); + ext->pwd_tmp = NULL; + } + + ext->pwd_mode = en == false ? 0 : 1; + + refr_cursor_area(ta); +} + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->one_line == en) return; + + if(en) { + lv_style_t * style_ta = lv_obj_get_style(ta); + lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(ta)); + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + + ext->one_line = 1; + lv_page_set_scrl_fit(ta, true, true); + lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2); + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_EXPAND); + lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver); + } else { + lv_style_t * style_ta = lv_obj_get_style(ta); + + ext->one_line = 0; + lv_page_set_scrl_fit(ta, false, true); + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK); + lv_obj_set_height(ta, LV_TA_DEF_HEIGHT); + lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver); + } + + refr_cursor_area(ta); +} + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_obj_t * label = lv_ta_get_label(ta); + if(!ext->one_line) { + lv_label_set_align(label, align); + } else { + /*Normal left align. Just let the text expand*/ + if(align == LV_LABEL_ALIGN_LEFT) { + lv_label_set_long_mode(label, LV_LABEL_LONG_EXPAND); + lv_page_set_scrl_fit(ta, true, false); + lv_label_set_align(label, align); + + } + /*Else use fix label width equal to the Text area width*/ + else { + lv_label_set_long_mode(label, LV_LABEL_LONG_CROP); + lv_page_set_scrl_fit(ta, false, false); + lv_page_set_scrl_width(ta, 1); /*To refresh the scrollable's width*/ + lv_label_set_align(label, align); + + lv_style_t * bg_style = lv_ta_get_style(ta, LV_TA_STYLE_BG); + lv_obj_set_width(label, lv_obj_get_width(ta) - 2 * bg_style->body.padding.hor); + } + } + + refr_cursor_area(ta); +} + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + ext->accapted_chars = list; +} + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + ext->max_length = num; +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, lv_style_t * style) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + switch(type) { + case LV_TA_STYLE_BG: + lv_page_set_style(ta, LV_PAGE_STYLE_BG, style); + break; + case LV_TA_STYLE_SB: + lv_page_set_style(ta, LV_PAGE_STYLE_SB, style); + break; + case LV_TA_STYLE_EDGE_FLASH: + lv_page_set_style(ta, LV_PAGE_STYLE_EDGE_FLASH, style); + break; + case LV_TA_STYLE_CURSOR: + ext->cursor.style = style; + lv_obj_refresh_ext_size(lv_page_get_scrl(ta)); /*Refresh ext. size because of cursor drawing*/ + refr_cursor_area(ta); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + const char * txt; + if(ext->pwd_mode == 0) { + txt = lv_label_get_text(ext->label); + } else { + txt = ext->pwd_tmp; + } + + return txt; +} + + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->label; +} + + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->cursor.pos; +} + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_ta_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->cursor.type; +} + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->pwd_mode == 0 ? false : true; +} + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->one_line == 0 ? false : true; +} + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + return ext->accapted_chars; +} + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + return ext->max_length; +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t * ta, lv_ta_style_t type) +{ + lv_style_t * style = NULL; + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + switch(type) { + case LV_TA_STYLE_BG: + style = lv_page_get_style(ta, LV_PAGE_STYLE_BG); + break; + case LV_TA_STYLE_SB: + style = lv_page_get_style(ta, LV_PAGE_STYLE_SB); + break; + case LV_TA_STYLE_EDGE_FLASH: + style = lv_page_get_style(ta, LV_PAGE_STYLE_EDGE_FLASH); + break; + case LV_TA_STYLE_CURSOR: + style = ext->cursor.style; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta) +{ + uint16_t cp = lv_ta_get_cursor_pos(ta); + cp++; + lv_ta_set_cursor_pos(ta, cp); +} + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta) +{ + uint16_t cp = lv_ta_get_cursor_pos(ta); + if(cp > 0) { + cp--; + lv_ta_set_cursor_pos(ta, cp); + } +} + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_point_t pos; + + /*Get the position of the current letter*/ + lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos); + + /*Increment the y with one line and keep the valid x*/ + lv_style_t * label_style = lv_obj_get_style(ext->label); + const lv_font_t * font_p = label_style->text.font; + lv_coord_t font_h = lv_font_get_height(font_p); + pos.y += font_h + label_style->text.line_space + 1; + pos.x = ext->cursor.valid_x; + + /*Do not go below the last line*/ + if(pos.y < lv_obj_get_height(ext->label)) { + /*Get the letter index on the new cursor position and set it*/ + uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos); + + lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x; /*Cursor position set overwrites the valid positon */ + lv_ta_set_cursor_pos(ta, new_cur_pos); + ext->cursor.valid_x = cur_valid_x_tmp; + } +} + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_point_t pos; + + /*Get the position of the current letter*/ + lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos); + + /*Decrement the y with one line and keep the valid x*/ + lv_style_t * label_style = lv_obj_get_style(ext->label); + const lv_font_t * font = label_style->text.font; + lv_coord_t font_h = lv_font_get_height(font); + pos.y -= font_h + label_style->text.line_space - 1; + pos.x = ext->cursor.valid_x; + + + /*Get the letter index on the new cursor position and set it*/ + uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos); + lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x; /*Cursor position set overwrites the valid positon */ + lv_ta_set_cursor_pos(ta, new_cur_pos); + ext->cursor.valid_x = cur_valid_x_tmp; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the text areas + * @param ta pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW_MAIN: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return ancestor_design(ta, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the object*/ + ancestor_design(ta, mask, mode); + + } else if(mode == LV_DESIGN_DRAW_POST) { + ancestor_design(ta, mask, mode); + } + return true; +} + + +/** + * An extended scrollable design of the page. Calls the normal design function and draws a cursor. + * @param scrl pointer to the scrollable part of the Text area + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW_MAIN: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @return return true/false, depends on 'mode' + */ +static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode) +{ + if(mode == LV_DESIGN_COVER_CHK) { + /*Return false if the object is not covers the mask_p area*/ + return scrl_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_MAIN) { + /*Draw the object*/ + scrl_design(scrl, mask, mode); + } else if(mode == LV_DESIGN_DRAW_POST) { + scrl_design(scrl, mask, mode); + + /*Draw the cursor*/ + lv_obj_t * ta = lv_obj_get_parent(scrl); + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + if(ext->cursor.type == LV_CURSOR_NONE || + (ext->cursor.type & LV_CURSOR_HIDDEN) || + ext->cursor.state == 0) { + return true; /*The cursor is not visible now*/ + } + + lv_style_t cur_style; + get_cursor_style(ta, &cur_style); + + const char * txt = lv_label_get_text(ext->label); + + /*Draw he cursor according to the type*/ + lv_area_t cur_area; + lv_area_copy(&cur_area, &ext->cursor.area); + + cur_area.x1 += ext->label->coords.x1; + cur_area.y1 += ext->label->coords.y1; + cur_area.x2 += ext->label->coords.x1; + cur_area.y2 += ext->label->coords.y1; + + lv_opa_t opa_scale = lv_obj_get_opa_scale(ta); + + if(ext->cursor.type == LV_CURSOR_LINE) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } else if(ext->cursor.type == LV_CURSOR_BLOCK) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + +#if LV_TXT_UTF8 == 0 + char letter_buf[2]; + letter_buf[0] = txt[ext->cursor.txt_byte_pos]; + letter_buf[1] = '\0'; +#else + char letter_buf[8] = {0}; + memcpy(letter_buf, &txt[ext->cursor.txt_byte_pos], lv_txt_encoded_size(&txt[ext->cursor.txt_byte_pos])); +#endif + cur_area.x1 += cur_style.body.padding.hor; + cur_area.y1 += cur_style.body.padding.ver; + lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, 0); + + } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { + cur_style.body.empty = 1; + if(cur_style.body.border.width == 0) cur_style.body.border.width = 1; /*Be sure the border will be drawn*/ + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { + lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); + } + } + + return true; +} + +/** + * Signal function of the text area + * @param ta pointer to a text area object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(ta, sign, param); + if(res != LV_RES_OK) return res; + + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(sign == LV_SIGNAL_CLEANUP) { + if(ext->pwd_tmp != NULL) lv_mem_free(ext->pwd_tmp); + + /* (The created label will be deleted automatically) */ + } else if(sign == LV_SIGNAL_STYLE_CHG) { + if(ext->label) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_ta = lv_obj_get_style(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + if(ext->one_line) { + /*In one line mode refresh the Text Area height because 'vpad' can modify it*/ + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2); + } else { + /*In not one line mode refresh the Label width because 'hpad' can modify it*/ + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); /*Be sure the Label is in the correct position*/ + } + lv_label_set_text(ext->label, NULL); + + } + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*Set the label width according to the text area width*/ + if(ext->label) { + if(lv_obj_get_width(ta) != lv_area_get_width(param) || + lv_obj_get_height(ta) != lv_area_get_height(param)) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); + lv_label_set_text(ext->label, NULL); /*Refresh the label*/ + + refr_cursor_area(ta); + } + } + } else if(sign == LV_SIGNAL_CONTROLL) { + uint32_t c = *((uint32_t *)param); /*uint32_t because can be UTF-8*/ + if(c == LV_GROUP_KEY_RIGHT) lv_ta_cursor_right(ta); + else if(c == LV_GROUP_KEY_LEFT) lv_ta_cursor_left(ta); + else if(c == LV_GROUP_KEY_UP) lv_ta_cursor_up(ta); + else if(c == LV_GROUP_KEY_DOWN) lv_ta_cursor_down(ta); + else if(c == LV_GROUP_KEY_BACKSPACE) lv_ta_del_char(ta); + else if(c == LV_GROUP_KEY_DEL) { + uint16_t cp = lv_ta_get_cursor_pos(ta); + lv_ta_set_cursor_pos(ta, cp + 1); + if(cp != lv_ta_get_cursor_pos(ta)) lv_ta_del_char(ta); + } + else { + lv_ta_add_char(ta, c); + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_ta"; + } else if(sign == LV_SIGNAL_DEFOCUS) { + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ta); + lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN); + } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_cursor_type_t cur_type; + cur_type = lv_ta_get_cursor_type(ta); + lv_group_t * g = lv_obj_get_group(ta); + bool editing = lv_group_get_editing(g); + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + + /*Encoders need special handling*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { + if(editing) lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN)); + else lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN); + } + else { + lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN)); + } +#endif + } + return res; +} + +/** + * Signal function of the scrollable part of the text area + * @param scrl pointer to scrollable part of a text area object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + lv_obj_t * ta = lv_obj_get_parent(scrl); + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /* Include the ancient signal function */ + res = scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + if(sign == LV_SIGNAL_REFR_EXT_SIZE) { + /*Set ext. size because the cursor might be out of this object*/ + lv_style_t * style_label = lv_obj_get_style(ext->label); + lv_coord_t font_h = lv_font_get_height(style_label->text.font); + scrl->ext_size = LV_MATH_MAX(scrl->ext_size, style_label->text.line_space + font_h); + } +#if 0 + else if(sign == LV_SIGNAL_CORD_CHG) { + /*Set the label width according to the text area width*/ + if(ext->label) { + if(lv_obj_get_width(ta) != lv_area_get_width(param) || + lv_obj_get_height(ta) != lv_area_get_height(param)) { + lv_obj_t * scrl = lv_page_get_scrl(ta); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); + lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); + lv_label_set_text(ext->label, NULL); /*Refresh the label*/ + + refr_cursor_area(ta); + } + } + } +#endif + + return res; +} + +#if USE_LV_ANIMATION + +/** + * Called to blink the cursor + * @param ta pointer to a text area + * @param hide 1: hide the cursor, 0: show it + */ +static void cursor_blink_anim(lv_obj_t * ta, uint8_t show) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(show != ext->cursor.state) { + ext->cursor.state = show == 0 ? 0 : 1; + if(ext->cursor.type != LV_CURSOR_NONE && + (ext->cursor.type & LV_CURSOR_HIDDEN) == 0) + { + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); + } + } +} + + +/** + * Dummy function to animate char hiding in pwd mode. + * Does nothing, but a function is required in car hiding anim. + * (pwd_char_hider callback do the real job) + * @param ta unused + * @param x unused + */ +static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x) +{ + (void)ta; + (void)x; +} + +#endif + +/** + * Hide all characters (convert them to '*') + * @param ta: pointer to text area object + */ +static void pwd_char_hider(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + if(ext->pwd_mode != 0) { + char * txt = lv_label_get_text(ext->label); + int16_t len = lv_txt_get_encoded_length(txt); + bool refr = false; + uint16_t i; + for(i = 0; i < len; i++) { + txt[i] = '*'; + refr = true; + } + + txt[i] = '\0'; + + if(refr != false) lv_label_set_text(ext->label, txt); + } +} + +/** + * Test an unicode character if it is accepted or not. Checks max length and accepted char list. + * @param ta pointer to a test area object + * @param c an unicode character + * @return true: accapted; false: rejected + */ +static bool char_is_accepted(lv_obj_t * ta, uint32_t c) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + + /*If no restriction accept it*/ + if(ext->accapted_chars == NULL && ext->max_length == 0) return true; + + /*Too many characters?*/ + if(ext->max_length > 0 && + lv_txt_get_encoded_length(lv_ta_get_text(ta)) >= ext->max_length) { + return false; + } + + /*Accepted character?*/ + if(ext->accapted_chars) { + uint32_t i = 0; + uint32_t a; + while(ext->accapted_chars[i] != '\0') { + a = lv_txt_encoded_next(ext->accapted_chars, &i); + if(a == c) return true; /*Accepted*/ + } + + return false; /*The character wasn't in the list*/ + } else { + return true; /*If the accepted char list in not specified the accept the character*/ + } + +} + +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + if(ext->cursor.style) { + lv_style_copy(style_res, ext->cursor.style); + } else { + /*If cursor style is not specified then use the modified label style */ + lv_style_copy(style_res, label_style); + lv_color_t clv_color_tmp = style_res->text.color; /*Make letter color to cursor color*/ + style_res->text.color = style_res->body.main_color; /*In block mode the letter color will be current background color*/ + style_res->body.main_color = clv_color_tmp; + style_res->body.grad_color = clv_color_tmp; + style_res->body.border.color = clv_color_tmp; + style_res->body.border.opa = LV_OPA_COVER; + style_res->body.border.width = 1; + style_res->body.shadow.width = 0; + style_res->body.radius = 0; + style_res->body.empty = 0; + style_res->body.padding.hor = 0; + style_res->body.padding.ver = 0; + style_res->line.width = 1; + style_res->body.opa = LV_OPA_COVER; + } + +} + +static void refr_cursor_area(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + lv_style_t cur_style; + get_cursor_style(ta, &cur_style); + + uint16_t cur_pos = lv_ta_get_cursor_pos(ta); + const char * txt = lv_label_get_text(ext->label); + uint32_t byte_pos; +#if LV_TXT_UTF8 != 0 + byte_pos = lv_txt_encoded_get_byte_id(txt, cur_pos); + uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL); +#else + byte_pos = cur_pos; + uint32_t letter = txt[byte_pos]; +#endif + + lv_coord_t letter_h = lv_font_get_height(label_style->text.font); + /*Set letter_w (set not 0 on non printable but valid chars)*/ + lv_coord_t letter_w; + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + + lv_point_t letter_pos; + lv_label_get_letter_pos(ext->label, cur_pos, &letter_pos); + + /*If the cursor is out of the text (most right) draw it to the next line*/ + if(letter_pos.x + ext->label->coords.x1 + letter_w > ext->label->coords.x2 && ext->one_line == 0 && lv_label_get_align(ext->label) != LV_LABEL_ALIGN_RIGHT) { + letter_pos.x = 0; + letter_pos.y += letter_h + label_style->text.line_space; + + if(letter != '\0') { + byte_pos += lv_txt_encoded_size(&txt[byte_pos]); + letter = lv_txt_encoded_next(&txt[byte_pos], NULL); + } + + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + } + + /*Save the byte position. It is required to draw `LV_CURSOR_BLOCK`*/ + ext->cursor.txt_byte_pos = byte_pos; + + /*Draw he cursor according to the type*/ + lv_area_t cur_area; + + if(ext->cursor.type == LV_CURSOR_LINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor - (cur_style.line.width >> 1) - (cur_style.line.width & 0x1); + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + (cur_style.line.width >> 1); + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_BLOCK) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + + } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver + letter_h - (cur_style.line.width >> 1); + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h + (cur_style.line.width >> 1) + (cur_style.line.width & 0x1); + } + + /*Save the new area*/ + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); + + lv_area_copy(&ext->cursor.area, &cur_area); + + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.h new file mode 100644 index 0000000..3227873 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_ta.h @@ -0,0 +1,390 @@ +/** + * @file lv_ta.h + * + */ + +#ifndef LV_TA_H +#define LV_TA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TA != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_CURSOR_NONE, + LV_CURSOR_LINE, + LV_CURSOR_BLOCK, + LV_CURSOR_OUTLINE, + LV_CURSOR_UNDERLINE, + LV_CURSOR_HIDDEN = 0x08, /*Or it to any value to hide the cursor temporally*/ +}; +typedef uint8_t lv_cursor_type_t; + +/*Data of text area*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * label; /*Label of the text area*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/ + uint16_t max_length; /*The max. number of characters. 0: no limit*/ + uint8_t pwd_mode :1; /*Replace characters with '*' */ + uint8_t one_line :1; /*One line mode (ignore line breaks)*/ + struct { + lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + lv_cursor_type_t type:4; /*Shape of the cursor*/ + uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ + } cursor; +} lv_ta_ext_t; + +enum { + LV_TA_STYLE_BG, + LV_TA_STYLE_SB, + LV_TA_STYLE_EDGE_FLASH, + LV_TA_STYLE_CURSOR, +}; +typedef uint8_t lv_ta_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); + + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Ã' use `lv_txt_encoded_conv_wc('Ã')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt); + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos); + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type); + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en); + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en); + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action) +{ + lv_page_set_rel_action(ta, action); +} + +/** + * Set the scroll bar mode of a text area + * @param ta pointer to a text area object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ta, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll. + * @param ta pointer to a Text area + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en) +{ + lv_page_set_scroll_propagation(ta, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Text Area + * @param en true or false to enable/disable end flash + */ +static inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en) +{ + lv_page_set_edge_flash(ta, en); +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta); + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta); + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta); + +/** + * Get the current cursor visibility. + * @param ta pointer to a text area object + * @return true: the cursor is drawn, false: the cursor is hidden + */ +//bool lv_ta_get_cursor_show(const lv_obj_t * ta); + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta); + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta); + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta); + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline lv_action_t lv_ta_get_action(lv_obj_t * ta) +{ + return lv_page_get_rel_action(ta); +} + +/** + * Get the scroll bar mode of a text area + * @param ta pointer to a text area object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta) +{ + return lv_page_get_sb_mode(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta) +{ + return lv_page_get_scroll_propagation(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_edge_flash(lv_obj_t * ta) +{ + return lv_page_get_edge_flash(ta); +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta); + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta); + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta); + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TA_H*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TA_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.c new file mode 100644 index 0000000..c6177ed --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.c @@ -0,0 +1,855 @@ +/** + * @file lv_table.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_table.h" +#if USE_LV_TABLE != 0 + +#include "../lv_misc/lv_txt.h" +#include "../lv_misc/lv_math.h" +#include "../lv_draw/lv_draw_label.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode); +static lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param); +static lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id); +static void refr_size(lv_obj_t * table); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_design_func_t ancestor_scrl_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("table create started"); + + /*Create the ancestor of table*/ + lv_obj_t * new_table = lv_obj_create(par, copy); + lv_mem_assert(new_table); + if(new_table == NULL) return NULL; + + /*Allocate the table type specific extended data*/ + lv_table_ext_t * ext = lv_obj_allocate_ext_attr(new_table, sizeof(lv_table_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_table); + if(ancestor_scrl_design == NULL) ancestor_scrl_design = lv_obj_get_design_func(new_table); + + /*Initialize the allocated 'ext' */ + ext->cell_data = NULL; + ext->cell_style[0] = &lv_style_plain; + ext->cell_style[1] = &lv_style_plain; + ext->cell_style[2] = &lv_style_plain; + ext->cell_style[3] = &lv_style_plain; + ext->col_cnt = 0; + ext->row_cnt = 0; + + uint16_t i; + for(i = 0; i < LV_TABLE_COL_MAX; i++) { + ext->col_w[i] = LV_DPI; + } + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_table, lv_table_signal); + lv_obj_set_design_func(new_table, lv_table_design); + + /*Init the new table table*/ + if(copy == NULL) { + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_table_set_style(new_table, LV_TABLE_STYLE_BG, th->table.bg); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL1, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL2, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL3, th->table.cell); + lv_table_set_style(new_table, LV_TABLE_STYLE_CELL4, th->table.cell); + } else { + lv_table_set_style(new_table, LV_TABLE_STYLE_BG, &lv_style_plain_color); + } + } + /*Copy an existing table*/ + else { + lv_table_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->cell_style[0] = copy_ext->cell_style[0]; + ext->cell_style[1] = copy_ext->cell_style[1]; + ext->cell_style[2] = copy_ext->cell_style[2]; + ext->cell_style[3] = copy_ext->cell_style[3]; + ext->col_cnt = copy_ext->col_cnt; + ext->row_cnt = copy_ext->row_cnt; + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_table); + } + + LV_LOG_INFO("table created"); + + return new_table; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_value: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + lv_table_cell_format_t format; + + /*Save the format byte*/ + if(ext->cell_data[cell]) { + format.format_byte = ext->cell_data[cell][0]; + } + /*Initialize the format byte*/ + else { + format.align = LV_LABEL_ALIGN_LEFT; + format.right_merge = 0; + format.type = 0; + format.crop = 0; + } + + + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ + strcpy(ext->cell_data[cell] + 1, txt); /*Leave the format byte*/ + ext->cell_data[cell][0] = format.format_byte; + refr_size(table); +} + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t old_row_cnt = ext->row_cnt; + ext->row_cnt = row_cnt; + + if(ext->row_cnt > 0 && ext->col_cnt > 0) { + ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*)); + + /*Initilize the new fields*/ + if(old_row_cnt < row_cnt) { + uint16_t old_cell_cnt = old_row_cnt * ext->col_cnt; + uint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt; + memset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0])); + } + } + else { + lv_mem_free(ext->cell_data); + ext->cell_data = NULL; + } + + refr_size(table); +} + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt) +{ + + if(col_cnt >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_cnt: too many columns. Must be < LV_TABLE_COL_MAX."); + return; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t old_col_cnt = ext->col_cnt; + ext->col_cnt = col_cnt; + + if(ext->row_cnt > 0 && ext->col_cnt > 0) { + ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*)); + /*Initilize the new fields*/ + if(old_col_cnt < col_cnt) { + uint16_t old_cell_cnt = old_col_cnt * ext->row_cnt; + uint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt; + memset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0])); + } + + } + else { + lv_mem_free(ext->cell_data); + ext->cell_data = NULL; + } + refr_size(table); +} + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w) +{ + if(col_id >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX."); + return; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + ext->col_w[col_id] = w; + refr_size(table); +} + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_align: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.align = align; + ext->cell_data[cell][0] = format.format_byte; +} + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_type: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + if(type > 0) type--; /*User gives 1,2,3,4 but easier to handle 0, 1, 2, 3*/ + if(type >= LV_TABLE_CELL_STYLE_CNT) type = LV_TABLE_CELL_STYLE_CNT - 1; + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.type = type; + ext->cell_data[cell][0] = format.format_byte; +} + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_crop: invalid row or column"); + return; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.crop = crop; + ext->cell_data[cell][0] = format.format_byte; +} + + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_merge_right: invalid row or column"); + return; + } + + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) { + ext->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ + ext->cell_data[cell][0] = 0; + ext->cell_data[cell][1] = '\0'; + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + format.right_merge = en ? 1 : 0; + ext->cell_data[cell][0] = format.format_byte; + refr_size(table); +} + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + + switch(type) { + case LV_TABLE_STYLE_BG: + lv_obj_set_style(table, style); + refr_size(table); + break; + case LV_TABLE_STYLE_CELL1: + ext->cell_style[0] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL2: + ext->cell_style[1] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL3: + ext->cell_style[2] = style; + refr_size(table); + break; + case LV_TABLE_STYLE_CELL4: + ext->cell_style[3] = style; + refr_size(table); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_value: invalid row or column"); + return ""; + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return ""; + + return &ext->cell_data[cell][1]; /*Skip the format byte*/ +} + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->row_cnt; +} + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->col_cnt; +} + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id) +{ + if(col_id >= LV_TABLE_COL_MAX) { + LV_LOG_WARN("lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX."); + return 0; + } + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + return ext->col_w[col_id]; +} + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_align: invalid row or column"); + return LV_LABEL_ALIGN_LEFT; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return LV_LABEL_ALIGN_LEFT; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.align; + } +} + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_type: invalid row or column"); + return 1; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return 1; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.type + 1; /*0,1,2,3 is stored but user sees 1,2,3,4*/ + } +} + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_crop: invalid row or column"); + return false; /*Just return with something*/ + } + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return false; /*Just return with something*/ + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.crop; + } +} + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(row >= ext->row_cnt || col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_get_cell_merge_right: invalid row or column"); + return false; + } + + uint32_t cell = row * ext->col_cnt + col; + + if(ext->cell_data[cell] == NULL) return false; + else { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + return format.right_merge ? true : false; + } +} + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_style_t * style = NULL; + + switch(type) { + case LV_TABLE_STYLE_BG: + style = lv_obj_get_style(table); + break; + case LV_TABLE_STYLE_CELL1: + style = ext->cell_style[0]; + break; + case LV_TABLE_STYLE_CELL2: + style = ext->cell_style[1]; + break; + case LV_TABLE_STYLE_CELL3: + style = ext->cell_style[2]; + break; + case LV_TABLE_STYLE_CELL4: + style = ext->cell_style[3]; + break; + default: + return NULL; + } + + return style; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Handle the drawing related tasks of the tables + * @param table pointer to an object + * @param mask the object will be drawn only in this area + * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area + * (return 'true' if yes) + * LV_DESIGN_DRAW: draw the object (always return 'true') + * LV_DESIGN_DRAW_POST: drawing after every children are drawn + * @param return true/false, depends on 'mode' + */ +static bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode) +{ + /*Return false if the object is not covers the mask_p area*/ + if(mode == LV_DESIGN_COVER_CHK) { + return false; + } + /*Draw the object*/ + else if(mode == LV_DESIGN_DRAW_MAIN) { + ancestor_scrl_design(table, mask, mode); + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_style_t * bg_style = lv_obj_get_style(table); + lv_style_t * cell_style; + lv_coord_t h_row; + lv_point_t txt_size; + lv_area_t cell_area; + lv_area_t txt_area; + lv_txt_flag_t txt_flags; + lv_opa_t opa_scale = lv_obj_get_opa_scale(table); + + uint16_t col; + uint16_t row; + uint16_t cell = 0; + + cell_area.y2 = table->coords.y1 + bg_style->body.padding.ver; + for(row = 0; row < ext->row_cnt; row++) { + h_row = get_row_height(table, row); + + cell_area.y1 = cell_area.y2; + cell_area.y2 = cell_area.y1 + h_row; + + cell_area.x2 = table->coords.x1 + bg_style->body.padding.hor; + + for(col = 0; col < ext->col_cnt; col++) { + + lv_table_cell_format_t format; + if(ext->cell_data[cell]) { + format.format_byte = ext->cell_data[cell][0]; + } else { + format.right_merge = 0; + format.align = LV_LABEL_ALIGN_LEFT; + format.type = 0; + format.crop = 1; + } + + cell_style = ext->cell_style[format.type]; + cell_area.x1 = cell_area.x2; + cell_area.x2 = cell_area.x1 + ext->col_w[col]; + + uint16_t col_merge = 0; + for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) { + + if(ext->cell_data[cell + col_merge] != NULL) { + format.format_byte = ext->cell_data[cell + col_merge][0]; + if(format.right_merge) cell_area.x2 += ext->col_w[col + col_merge + 1]; + else break; + } else { + break; + } + } + + lv_draw_rect(&cell_area, mask, cell_style, opa_scale); + + if(ext->cell_data[cell]) { + txt_area.x1 = cell_area.x1 + cell_style->body.padding.hor; + txt_area.x2 = cell_area.x2 - cell_style->body.padding.hor; + txt_area.y1 = cell_area.y1 + cell_style->body.padding.ver; + txt_area.y2 = cell_area.y2 - cell_style->body.padding.ver; + /*Align the content to the middle if not cropped*/ + if(format.crop == 0) { + txt_flags = LV_TXT_FLAG_NONE; + } else { + txt_flags = LV_TXT_FLAG_EXPAND; + } + + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags); + + /*Align the content to the middle if not cropped*/ + if(format.crop == 0) { + txt_area.y1 = cell_area.y1 + h_row / 2 - txt_size.y / 2; + txt_area.y2 = cell_area.y1 + h_row / 2 + txt_size.y / 2; + } + + switch(format.align) { + default: + case LV_LABEL_ALIGN_LEFT: + txt_flags |= LV_TXT_FLAG_NONE; + break; + case LV_LABEL_ALIGN_RIGHT: + txt_flags |= LV_TXT_FLAG_RIGHT; + break; + case LV_LABEL_ALIGN_CENTER: + txt_flags |= LV_TXT_FLAG_CENTER; + break; + } + + lv_area_t label_mask; + bool label_mask_ok; + label_mask_ok = lv_area_intersect(&label_mask, mask, &cell_area); + if(label_mask_ok) { + lv_draw_label(&txt_area, &label_mask, cell_style, opa_scale, ext->cell_data[cell] + 1, txt_flags, NULL); + } + /*Draw lines after '\n's*/ + lv_point_t p1; + lv_point_t p2; + p1.x = cell_area.x1; + p2.x = cell_area.x2; + uint16_t i; + for(i = 1; ext->cell_data[cell][i] != '\0'; i++) { + if(ext->cell_data[cell][i] == '\n') { + ext->cell_data[cell][i] = '\0'; + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags); + + p1.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2; + p2.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2; + lv_draw_line(&p1, &p2, mask, cell_style, opa_scale); + + ext->cell_data[cell][i] = '\n'; + } + } + } + + cell += col_merge + 1; + col += col_merge; + } + } + } + /*Post draw when the children are drawn*/ + else if(mode == LV_DESIGN_DRAW_POST) { + + } + + return true; +} + +/** + * Signal function of the table + * @param table pointer to a table object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(table, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Free the cell texts*/ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + uint16_t cell; + for(cell = 0; cell < ext->col_cnt * ext->row_cnt; cell++) { + if(ext->cell_data[cell]) { + lv_mem_free(ext->cell_data[cell]); + ext->cell_data[cell] = NULL; + } + } + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_table"; + } + + return res; +} + +static void refr_size(lv_obj_t * table) +{ + lv_coord_t h = 0; + lv_coord_t w = 0; + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + + uint16_t i; + for(i= 0; i < ext->col_cnt; i++) { + w += ext->col_w[i]; + } + for(i= 0; i < ext->row_cnt; i++) { + h += get_row_height(table, i); + } + + lv_style_t * bg_style = lv_obj_get_style(table); + + w += bg_style->body.padding.hor * 2; + h += bg_style->body.padding.ver * 2; + + lv_obj_set_size(table, w + 1, h + 1); + lv_obj_invalidate(table); +} + +static lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id) +{ + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + lv_point_t txt_size; + lv_coord_t txt_w; + lv_style_t * cell_style; + + uint16_t row_start = row_id * ext->col_cnt; + uint16_t cell; + uint16_t col; + lv_coord_t h_max = lv_font_get_height(ext->cell_style[0]->text.font) + 2 * ext->cell_style[0]->body.padding.ver; + + for(cell = row_start, col = 0; cell < row_start + ext->col_cnt; cell++, col ++) { + if(ext->cell_data[cell] != NULL) { + + txt_w = ext->col_w[col]; + uint16_t col_merge = 0; + for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) { + + if(ext->cell_data[cell + col_merge] != NULL) { + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell + col_merge][0]; + if(format.right_merge) txt_w += ext->col_w[col + col_merge + 1]; + else break; + } else { + break; + } + } + + lv_table_cell_format_t format; + format.format_byte = ext->cell_data[cell][0]; + cell_style = ext->cell_style[format.type]; + + /*With text crop assume 1 line*/ + if(format.crop) { + h_max = LV_MATH_MAX(lv_font_get_height(cell_style->text.font) + 2 * cell_style->body.padding.ver, h_max); + } + /*Without text crop calculate the height of the text in the cell*/ + else { + txt_w -= 2 * cell_style->body.padding.hor; + + lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font, + cell_style->text.letter_space, cell_style->text.line_space, txt_w, LV_TXT_FLAG_NONE); + + h_max = LV_MATH_MAX(txt_size.y + 2 * cell_style->body.padding.ver, h_max); + cell += col_merge; + col += col_merge; + } + } + } + + return h_max; +} + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.h new file mode 100644 index 0000000..94c3575 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_table.h @@ -0,0 +1,261 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TABLE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TABLE_COL_MAX +#define LV_TABLE_COL_MAX 12 +#endif + +#define LV_TABLE_CELL_STYLE_CNT 4 +/********************** + * TYPEDEFS + **********************/ + +typedef union { + struct { + uint8_t align:2; + uint8_t right_merge:1; + uint8_t type:2; + uint8_t crop:1; + }; + uint8_t format_byte; +}lv_table_cell_format_t; + +/*Data of table*/ +typedef struct { + /*New data for this type */ + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT]; + lv_coord_t col_w[LV_TABLE_COL_MAX]; +} lv_table_ext_t; + + +/*Styles*/ +enum { + LV_TABLE_STYLE_BG, + LV_TABLE_STYLE_CELL1, + LV_TABLE_STYLE_CELL2, + LV_TABLE_STYLE_CELL3, + LV_TABLE_STYLE_CELL4, +}; +typedef uint8_t lv_table_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt); + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt); + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w); + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align); + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type); + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop); + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en); + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table); + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table); + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id); + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col); + + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.c new file mode 100644 index 0000000..00f7d55 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.c @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_tab.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_tabview.h" +#if USE_LV_TABVIEW != 0 + +#include "lv_btnm.h" +#include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 300 /*Animation time of focusing to the a list element [ms] (0: no animation) */ +# endif +#else +# undef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param); +static lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param); +static lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param); + +static void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage); +static lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name); +static void tabview_realign(lv_obj_t * tabview); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t page_signal; +static lv_signal_func_t page_scrl_signal; +static const char * tab_def[] = {""}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("tab view create started"); + + /*Create the ancestor of tab*/ + lv_obj_t * new_tabview = lv_obj_create(par, copy); + lv_mem_assert(new_tabview); + if(new_tabview == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tabview); + + /*Allocate the tab type specific extended data*/ + lv_tabview_ext_t * ext = lv_obj_allocate_ext_attr(new_tabview, sizeof(lv_tabview_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + /*Initialize the allocated 'ext' */ + ext->drag_hor = 0; + ext->draging = 0; + ext->slide_enable = 1; + ext->tab_cur = 0; + ext->point_last.x = 0; + ext->point_last.y = 0; + ext->content = NULL; + ext->indic = NULL; + ext->btns = NULL; + ext->tab_load_action = NULL; + ext->btns_pos = LV_TABVIEW_BTNS_POS_TOP; + ext->anim_time = LV_TABVIEW_ANIM_TIME; + ext->btns_hide = 0; + + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_tabview, lv_tabview_signal); + + /*Init the new tab tab*/ + if(copy == NULL) { + ext->tab_name_ptr = lv_mem_alloc(sizeof(char *)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + ext->tab_name_ptr[0] = ""; + ext->tab_cnt = 0; + + lv_obj_set_size(new_tabview, LV_HOR_RES, LV_VER_RES); + + ext->btns = lv_btnm_create(new_tabview, NULL); + lv_obj_set_height(ext->btns, 3 * LV_DPI / 4); + lv_btnm_set_map(ext->btns, tab_def); + lv_btnm_set_action(ext->btns, tab_btnm_action); + lv_btnm_set_toggle(ext->btns, true, 0); + + ext->indic = lv_obj_create(ext->btns, NULL); + lv_obj_set_width(ext->indic, LV_DPI); + lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_set_click(ext->indic, false); + + ext->content = lv_cont_create(new_tabview, NULL); + lv_cont_set_fit(ext->content, true, false); + lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T); + lv_cont_set_style(ext->content, &lv_style_transp_tight); + lv_obj_set_height(ext->content, LV_VER_RES - lv_obj_get_height(ext->btns)); + lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, th->tabview.bg); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, th->tabview.indic); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, th->tabview.btn.bg); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_REL, th->tabview.btn.rel); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_PR, th->tabview.btn.pr); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_REL, th->tabview.btn.tgl_rel); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->tabview.btn.tgl_pr); + } else { + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_transp); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color); + } + } + /*Copy an existing tab view*/ + else { + lv_tabview_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->point_last.x = 0; + ext->point_last.y = 0; + ext->btns = lv_btnm_create(new_tabview, copy_ext->btns); + ext->indic = lv_obj_create(ext->btns, copy_ext->indic); + ext->content = lv_cont_create(new_tabview, copy_ext->content); + ext->anim_time = copy_ext->anim_time; + ext->tab_load_action = copy_ext->tab_load_action; + + ext->tab_name_ptr = lv_mem_alloc(sizeof(char *)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + ext->tab_name_ptr[0] = ""; + lv_btnm_set_map(ext->btns, ext->tab_name_ptr); + + uint16_t i; + lv_obj_t * new_tab; + lv_obj_t * copy_tab; + for(i = 0; i < copy_ext->tab_cnt; i++) { + new_tab = lv_tabview_add_tab(new_tabview, copy_ext->tab_name_ptr[i]); + copy_tab = lv_tabview_get_tab(copy, i); + lv_page_set_style(new_tab, LV_PAGE_STYLE_BG, lv_page_get_style(copy_tab, LV_PAGE_STYLE_BG)); + lv_page_set_style(new_tab, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SCRL)); + lv_page_set_style(new_tab, LV_PAGE_STYLE_SB, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SB)); + } + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_tabview); + } + + + LV_LOG_INFO("tab view created"); + + return new_tabview; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + /*Create the container page*/ + lv_obj_t * h = lv_page_create(ext->content, NULL); + lv_obj_set_size(h, lv_obj_get_width(tabview), lv_obj_get_height(ext->content)); + lv_page_set_sb_mode(h, LV_SB_MODE_OFF); // Important! + lv_page_set_style(h, LV_PAGE_STYLE_BG, &lv_style_transp); + lv_page_set_style(h, LV_PAGE_STYLE_SCRL, &lv_style_transp); + + if(page_signal == NULL) page_signal = lv_obj_get_signal_func(h); + if(page_scrl_signal == NULL) page_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(h)); + lv_obj_set_signal_func(h, tabpage_signal); + lv_obj_set_signal_func(lv_page_get_scrl(h), tabpage_scrl_signal); + + /*Extend the button matrix map with the new name*/ + char * name_dm; + if((name[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) { /*If control byte presented let is*/ + name_dm = lv_mem_alloc(strlen(name) + 1); /*+1 for the the closing '\0' */ + lv_mem_assert(name_dm); + if(name_dm == NULL) return NULL; + strcpy(name_dm, name); + } else { /*Set a no long press control byte is not presented*/ + name_dm = lv_mem_alloc(strlen(name) + 2); /*+1 for the the closing '\0' and +1 for the control byte */ + lv_mem_assert(name_dm); + if(name_dm == NULL) return NULL; + name_dm[0] = '\221'; + strcpy(&name_dm[1], name); + } + + ext->tab_cnt++; + ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt + 1)); + lv_mem_assert(ext->tab_name_ptr); + if(ext->tab_name_ptr == NULL) return NULL; + + ext->tab_name_ptr[ext->tab_cnt - 1] = name_dm; + ext->tab_name_ptr[ext->tab_cnt] = ""; + + lv_btnm_set_map(ext->btns, ext->tab_name_ptr); + + /*Modify the indicator size*/ + lv_style_t * style_tabs = lv_obj_get_style(ext->btns); + lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) - 2 * style_tabs->body.padding.hor) / ext->tab_cnt; + lv_obj_set_width(ext->indic, indic_width); + lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + style_tabs->body.padding.inner * ext->tab_cur + style_tabs->body.padding.hor); + + /*Set the first btn as active*/ + if(ext->tab_cnt == 1) { + ext->tab_cur = 0; + lv_tabview_set_tab_act(tabview, 0, false); + tabview_realign(tabview); /*To set the proper btns height*/ + } + + return h; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + lv_style_t * style = lv_obj_get_style(ext->content); + + lv_res_t res = LV_RES_OK; + if(id >= ext->tab_cnt) id = ext->tab_cnt - 1; + if(ext->tab_load_action && id != ext->tab_cur) res = ext->tab_load_action(tabview, id); + if(res != LV_RES_OK) return; /*Prevent the tab loading*/ + + ext->tab_cur = id; + + lv_coord_t cont_x = -(lv_obj_get_width(tabview) * id + style->body.padding.inner * id + style->body.padding.hor); + if(ext->anim_time == 0 || anim_en == false) { + lv_obj_set_x(ext->content, cont_x); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = ext->content; + a.start = lv_obj_get_x(ext->content); + a.end = cont_x; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + + /*Move the indicator*/ + lv_coord_t indic_width = lv_obj_get_width(ext->indic); + lv_style_t * tabs_style = lv_obj_get_style(ext->btns); + lv_coord_t indic_x = indic_width * id + tabs_style->body.padding.inner * id + tabs_style->body.padding.hor; + + if(ext->anim_time == 0 || anim_en == false) { + lv_obj_set_x(ext->indic, indic_x); + } else { +#if USE_LV_ANIMATION + lv_anim_t a; + a.var = ext->indic; + a.start = lv_obj_get_x(ext->indic); + a.end = indic_x; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +#endif + } + + lv_btnm_set_toggle(ext->btns, true, ext->tab_cur); +} + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a btn is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t * tabview, lv_tabview_action_t action) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->tab_load_action = action; +} + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->slide_enable = en == false ? 0 : 1; +} + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time_ms time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif + ext->anim_time = anim_time; +} + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t * tabview, lv_tabview_style_t type, lv_style_t * style) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + switch(type) { + case LV_TABVIEW_STYLE_BG: + lv_obj_set_style(tabview, style); + break; + case LV_TABVIEW_STYLE_BTN_BG: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BG, style); + tabview_realign(tabview); + break; + case LV_TABVIEW_STYLE_BTN_REL: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_REL, style); + tabview_realign(tabview); + break; + case LV_TABVIEW_STYLE_BTN_PR: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_PR, style); + break; + case LV_TABVIEW_STYLE_BTN_TGL_REL: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL, style); + break; + case LV_TABVIEW_STYLE_BTN_TGL_PR: + lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR, style); + break; + case LV_TABVIEW_STYLE_INDIC: + lv_obj_set_style(ext->indic, style); + lv_obj_set_height(ext->indic, style->body.padding.inner); + tabview_realign(tabview); + break; + } +} + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tan view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t * tabview, lv_tabview_btns_pos_t btns_pos) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + ext->btns_pos = btns_pos; + tabview_realign(tabview); +} + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + ext->btns_hide = en; + tabview_realign(tabview); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active btn index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_cur; +} + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return btn count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_cnt; +} + +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the btn (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + uint16_t i = 0; + lv_obj_t * page = lv_obj_get_child_back(ext->content, NULL); + + while(page != NULL && i != id) { + i++; + page = lv_obj_get_child_back(ext->content, page); + } + + if(i == id) return page; + + return NULL; +} + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current btn load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->tab_load_action; +} + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->slide_enable ? true : false; +} + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->anim_time; +} + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t * tabview, lv_tabview_style_t type) +{ + lv_style_t * style = NULL; + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + switch(type) { + case LV_TABVIEW_STYLE_BG: + style = lv_obj_get_style(tabview); + break; + case LV_TABVIEW_STYLE_BTN_BG: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BG); + break; + case LV_TABVIEW_STYLE_BTN_REL: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_REL); + break; + case LV_TABVIEW_STYLE_BTN_PR: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_PR); + break; + case LV_TABVIEW_STYLE_BTN_TGL_REL: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL); + break; + case LV_TABVIEW_STYLE_BTN_TGL_PR: + style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR); + break; + default: + style = NULL; + break; + } + + return style; +} + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + return ext->btns_pos; +} + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + return ext->btns_hide; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the Tab view + * @param tabview pointer to a Tab view object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(tabview, sign, param); + if(res != LV_RES_OK) return res; + + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + if(sign == LV_SIGNAL_CLEANUP) { + uint8_t i; + for(i = 0; ext->tab_name_ptr[i][0] != '\0'; i++) lv_mem_free(ext->tab_name_ptr[i]); + + lv_mem_free(ext->tab_name_ptr); + ext->tab_name_ptr = NULL; + ext->btns = NULL; /*These objects were children so they are already invalid*/ + ext->content = NULL; + } else if(sign == LV_SIGNAL_CORD_CHG) { + if(ext->content != NULL && + (lv_obj_get_width(tabview) != lv_area_get_width(param) || + lv_obj_get_height(tabview) != lv_area_get_height(param))) { + tabview_realign(tabview); + } + } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS || sign == LV_SIGNAL_CONTROLL) { + /* The button matrix is not in a group (the tab view is in it) but it should handle the group signals. + * So propagate the related signals to the button matrix manually*/ + if(ext->btns) { + ext->btns->signal_func(ext->btns, sign, param); + } + if(sign == LV_SIGNAL_FOCUS) { + lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + /*With ENCODER select the first button only in edit mode*/ + if(indev_type == LV_INDEV_TYPE_ENCODER) { +#if USE_LV_GROUP + lv_group_t * g = lv_obj_get_group(tabview); + if(lv_group_get_editing(g)) { + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns); + btnm_ext->btn_id_pr = 0; + lv_obj_invalidate(ext->btns); + } +#endif + } else { + lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns); + btnm_ext->btn_id_pr = 0; + lv_obj_invalidate(ext->btns); + } + } + } else if(sign == LV_SIGNAL_GET_EDITABLE) { + bool * editable = (bool *)param; + *editable = true; + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_tabview"; + } + + return res; +} + + +/** + * Signal function of a tab's page + * @param tab pointer to a tab page object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = page_signal(tab_page, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * cont = lv_obj_get_parent(tab_page); + lv_obj_t * tabview = lv_obj_get_parent(cont); + + if(lv_tabview_get_sliding(tabview) == false) return res; + + if(sign == LV_SIGNAL_PRESSED) { + tabpage_pressed_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_PRESSING) { + tabpage_pressing_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + tabpage_press_lost_handler(tabview, tab_page); + } + + return res; +} +/** + * Signal function of the tab page's scrollable object + * @param tab_scrl pointer to a tab page's scrollable object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = page_scrl_signal(tab_scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * tab_page = lv_obj_get_parent(tab_scrl); + lv_obj_t * cont = lv_obj_get_parent(tab_page); + lv_obj_t * tabview = lv_obj_get_parent(cont); + + if(lv_tabview_get_sliding(tabview) == false) return res; + + if(sign == LV_SIGNAL_PRESSED) { + tabpage_pressed_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_PRESSING) { + tabpage_pressing_handler(tabview, tab_page); + } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + tabpage_press_lost_handler(tabview, tab_page); + } + + return res; +} + +/** + * Called when a tab's page or scrollable object is pressed + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + (void)tabpage; + + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + lv_indev_t * indev = lv_indev_get_act(); + lv_indev_get_point(indev, &ext->point_last); +} + +/** + * Called when a tab's page or scrollable object is being pressed + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_coord_t x_diff = point_act.x - ext->point_last.x; + lv_coord_t y_diff = point_act.y - ext->point_last.y; + + if(ext->draging == 0) { + if(x_diff >= LV_INDEV_DRAG_LIMIT || x_diff <= -LV_INDEV_DRAG_LIMIT) { + ext->drag_hor = 1; + ext->draging = 1; + lv_obj_set_drag(lv_page_get_scrl(tabpage), false); + } else if(y_diff >= LV_INDEV_DRAG_LIMIT || y_diff <= -LV_INDEV_DRAG_LIMIT) { + ext->drag_hor = 0; + ext->draging = 1; + } + } + if(ext->drag_hor) { + lv_obj_set_x(ext->content, lv_obj_get_x(ext->content) + point_act.x - ext->point_last.x); + ext->point_last.x = point_act.x; + ext->point_last.y = point_act.y; + + /*Move the indicator*/ + lv_coord_t indic_width = lv_obj_get_width(ext->indic); + lv_style_t * tabs_style = lv_obj_get_style(ext->btns); + lv_style_t * indic_style = lv_obj_get_style(ext->indic); + lv_coord_t p = ((tabpage->coords.x1 - tabview->coords.x1) * (indic_width + tabs_style->body.padding.inner)) / lv_obj_get_width(tabview); + + lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + tabs_style->body.padding.inner * ext->tab_cur + indic_style->body.padding.hor - p); + } +} + +/** + * Called when a tab's page or scrollable object is released or the press id lost + * @param tabview pointer to the btn view object + * @param tabpage pointer to the page of a btn + */ +static void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + ext->drag_hor = 0; + ext->draging = 0; + + lv_obj_set_drag(lv_page_get_scrl(tabpage), true); + + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t x_predict = 0; + + while(vect.x != 0) { + x_predict += vect.x; + vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + lv_coord_t page_x1 = tabpage->coords.x1 - tabview->coords.x1 + x_predict; + lv_coord_t page_x2 = page_x1 + lv_obj_get_width(tabpage); + lv_coord_t treshold = lv_obj_get_width(tabview) / 2; + + uint16_t tab_cur = ext->tab_cur; + if(page_x1 > treshold) { + if(tab_cur != 0) tab_cur--; + } else if(page_x2 < treshold) { + if(tab_cur < ext->tab_cnt - 1) tab_cur++; + } + + lv_tabview_set_tab_act(tabview, tab_cur, true); +} + +/** + * Called when a tab button is released + * @param tab_btnm pointer to the tab's button matrix object + * @param id the id of the tab (>= 0) + * @return LV_ACTION_RES_OK because the button matrix in not deleted in the function + */ +static lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name) +{ + lv_obj_t * tab = lv_obj_get_parent(tab_btnm); + const char ** tabs_map = lv_btnm_get_map(tab_btnm); + + uint8_t i = 0; + + while(tabs_map[i][0] != '\0') { + if(strcmp(&tabs_map[i][1], tab_name) == 0) break; /*[1] to skip the control byte*/ + i++; + } + + lv_tabview_set_tab_act(tab, i, true); + + return LV_RES_OK; +} + +/** + * Realign and resize the elements of Tab view + * @param tabview pointer to a Tab view object + */ +static void tabview_realign(lv_obj_t * tabview) +{ + lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview); + + lv_obj_set_width(ext->btns, lv_obj_get_width(tabview)); + + if(ext->btns_hide) { + lv_obj_set_hidden(ext->btns, true); + lv_obj_set_hidden(ext->indic, true); + lv_obj_set_height(ext->content, lv_obj_get_height(tabview)); + lv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + } + else if(ext->tab_cnt != 0) { + lv_obj_set_hidden(ext->btns, false); + lv_obj_set_hidden(ext->indic, false); + + lv_style_t * style_btn_bg = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_BG); + lv_style_t * style_btn_rel = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_REL); + + /*Set the indicator widths*/ + lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_btn_bg->body.padding.inner * (ext->tab_cnt - 1) - + 2 * style_btn_bg->body.padding.hor) / ext->tab_cnt; + lv_obj_set_width(ext->indic, indic_width); + + /*Set the tabs height*/ + lv_coord_t btns_height = lv_font_get_height(style_btn_rel->text.font) + + 2 * style_btn_rel->body.padding.ver + + 2 * style_btn_bg->body.padding.ver; + lv_obj_set_height(ext->btns, btns_height); + + lv_obj_set_height(ext->content, lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns)); + + switch(ext->btns_pos) { + case LV_TABVIEW_BTNS_POS_TOP: + lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + break; + case LV_TABVIEW_BTNS_POS_BOTTOM: + lv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(ext->btns, ext->content, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); + break; + } + } + + lv_obj_t * pages = lv_obj_get_child(ext->content, NULL); + while(pages != NULL) { + if(lv_obj_get_signal_func(pages) == tabpage_signal) { /*Be sure adjust only the pages (user can other things)*/ + lv_obj_set_size(pages, lv_obj_get_width(tabview), lv_obj_get_height(ext->content)); + } + pages = lv_obj_get_child(ext->content, pages); + } + + if(!ext->btns_hide) { + lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + } + + lv_tabview_set_tab_act(tabview, ext->tab_cur, false); +} +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.h new file mode 100644 index 0000000..2d60c3c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tabview.h @@ -0,0 +1,252 @@ +/** + * @file lv_tabview.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TABVIEW != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_PAGE == 0 +#error "lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "../lv_objx/lv_win.h" +#include "../lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* parametes: pointer to a tabview object, tab_id + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t); + + +enum { + LV_TABVIEW_BTNS_POS_TOP, + LV_TABVIEW_BTNS_POS_BOTTOM, +}; +typedef uint8_t lv_tabview_btns_pos_t; + +/*Data of tab*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * btns; + lv_obj_t * indic; + lv_obj_t * content; /*A rectangle to show the current tab*/ + const char ** tab_name_ptr; + lv_point_t point_last; + uint16_t tab_cur; + uint16_t tab_cnt; + uint16_t anim_time; + uint8_t slide_enable :1; /*1: enable horizontal sliding by touch pad*/ + uint8_t draging :1; + uint8_t drag_hor :1; + uint8_t btns_hide :1; + lv_tabview_btns_pos_t btns_pos :1; + lv_tabview_action_t tab_load_action; +} lv_tabview_ext_t; + +enum { + LV_TABVIEW_STYLE_BG, + LV_TABVIEW_STYLE_INDIC, + LV_TABVIEW_STYLE_BTN_BG, + LV_TABVIEW_STYLE_BTN_REL, + LV_TABVIEW_STYLE_BTN_PR, + LV_TABVIEW_STYLE_BTN_TGL_REL, + LV_TABVIEW_STYLE_BTN_TGL_PR, +}; +typedef uint8_t lv_tabview_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en); + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a tab is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action); + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en); + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time); + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style); + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tab view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos); + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active tab index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview); + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return tab count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview); +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the tab (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id); + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current tab load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview); + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview); + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview); + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type); + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview); + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.c new file mode 100644 index 0000000..7435a9b --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.c @@ -0,0 +1,578 @@ +/** + * @file lv_tileview.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_tileview.h" +#if USE_LV_TILEVIEW != 0 + +#include "lv_cont.h" +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ +#if USE_LV_ANIMATION +# ifndef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 300 /*Animation time loading a tile [ms] (0: no animation) */ +# endif +#else +# undef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 0 /*No animations*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param); +static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param); +static lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param); +static void drag_end_handler(lv_obj_t * tileview); +static bool set_valid_drag_dirs(lv_obj_t * tileview); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; +static lv_signal_func_t ancestor_scrl_signal; +static lv_design_func_t ancestor_design; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a tileview object + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("tileview create started"); + + /*Create the ancestor of tileview*/ + lv_obj_t * new_tileview = lv_page_create(par, copy); + lv_mem_assert(new_tileview); + if(new_tileview == NULL) return NULL; + + /*Allocate the tileview type specific extended data*/ + lv_tileview_ext_t * ext = lv_obj_allocate_ext_attr(new_tileview, sizeof(lv_tileview_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tileview); + if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_tileview)); + if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_tileview); + + /*Initialize the allocated 'ext' */ + ext->anim_time = LV_TILEVIEW_ANIM_TIME; + ext->action = NULL; + ext->act_id.x = 0; + ext->act_id.y = 0; + ext->valid_pos = NULL; + + /*The signal and design functions are not copied so set them here*/ + lv_obj_set_signal_func(new_tileview, lv_tileview_signal); + lv_obj_set_signal_func(lv_page_get_scrl(new_tileview), lv_tileview_scrl_signal); + + /*Init the new tileview*/ + if(copy == NULL) { + lv_obj_set_size(new_tileview, LV_HOR_RES, LV_VER_RES); + lv_obj_set_drag_throw(lv_page_get_scrl(new_tileview), false); + lv_page_set_scrl_fit(new_tileview, true, true); + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, th->tileview.bg); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, th->tileview.scrl); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SB, th->tileview.sb); + } else { + lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, &lv_style_transp_tight); + lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight); + } + } + /*Copy an existing tileview*/ + else { + lv_tileview_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + ext->act_id.x = copy_ext->act_id.x; + ext->act_id.y = copy_ext->act_id.y; + ext->action = copy_ext->action; + ext->anim_time = copy_ext->anim_time; + + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_tileview); + } + + LV_LOG_INFO("tileview created"); + + return new_tileview; +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element) +{ + lv_obj_set_free_ptr(element, lv_obj_get_signal_func(element)); + lv_obj_set_signal_func(element, element_signal_func); + lv_obj_set_drag_parent(element, true); +} + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->valid_pos = valid_pos; +} + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en) +{ +#if USE_LV_ANIMATION == 0 + anim_en = false; +#endif + + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + + + uint16_t i; + bool valid = false; + for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) { + if(ext->valid_pos[i].x == x && ext->valid_pos[i].y == y) { + valid = true; + } + } + + if(valid == false) return; /*Don't load not valid tiles*/ + + lv_res_t res = LV_RES_OK; + if(ext->action) res = ext->action(tileview, x, y); + if(res != LV_RES_OK) return; /*Prevent the tile loading*/ + + ext->act_id.x = x; + ext->act_id.y = y; + + lv_coord_t x_coord = -x * lv_obj_get_width(tileview); + lv_coord_t y_coord = -y * lv_obj_get_height(tileview); + lv_obj_t * scrl = lv_page_get_scrl(tileview); + if(anim_en) { +#if USE_LV_ANIMATION + lv_coord_t x_act = lv_obj_get_x(scrl); + lv_coord_t y_act = lv_obj_get_y(scrl); + + lv_anim_t a; + a.var = scrl; + a.fp = (lv_anim_fp_t)lv_obj_set_x; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = ext->anim_time; + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + + if(x_coord != x_act) { + a.start = x_act; + a.end = x_coord; + lv_anim_create(&a); + } + + if(y_coord != y_act) { + a.start = y_act; + a.end = y_coord; + a.fp = (lv_anim_fp_t)lv_obj_set_y; + lv_anim_create(&a); + } +#endif + } else { + lv_obj_set_pos(scrl, x_coord, y_coord); + } +} + +void lv_tileview_set_tile_load_action(lv_obj_t * tileview, lv_tileview_action_t action) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->action = action; + +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t * style) +{ + + switch(type) { + case LV_TILEVIEW_STYLE_BG: + lv_obj_set_style(tileview, style); + break; + } +} + +/*===================== + * Getter functions + *====================*/ + +/* + * New object specific "get" functions come here + */ + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type) +{ + lv_style_t * style = NULL; + switch(type) { + case LV_TILEVIEW_STYLE_BG: + style = lv_obj_get_style(tileview); + break; + default: + style = NULL; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/* + * New object specific "other" functions come here + */ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the tileview + * @param tileview pointer to a tileview object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(tileview, sign, param); + if(res != LV_RES_OK) return res; + + + if(sign == LV_SIGNAL_CLEANUP) { + /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_tileview"; + } + + return res; +} + +/** + * Signal function of the tileview scrollable + * @param tileview pointer to the scrollable part of the tileview object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param) +{ + + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_scrl_signal(scrl, sign, param); + if(res != LV_RES_OK) return res; + + lv_obj_t * tileview = lv_obj_get_parent(scrl); + lv_style_t * style_bg = lv_tileview_get_style(tileview, LV_TILEVIEW_STYLE_BG); + + + /*Apply constraint on moving of the tileview*/ + if(sign == LV_SIGNAL_CORD_CHG) { + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + + /*Set horizontal drag constraint if no vertical constraint an dragged to valid x direction */ + if(ext->drag_ver == 0 && + ((ext->drag_right_en && indev->proc.drag_sum.x <= -LV_INDEV_DRAG_LIMIT) || + (ext->drag_left_en && indev->proc.drag_sum.x >= LV_INDEV_DRAG_LIMIT))) { + ext->drag_hor = 1; + } + /*Set vertical drag constraint if no horizontal constraint an dragged to valid y direction */ + if(ext->drag_hor == 0 && + ((ext->drag_bottom_en && indev->proc.drag_sum.y <= -LV_INDEV_DRAG_LIMIT) || + (ext->drag_top_en && indev->proc.drag_sum.y >= LV_INDEV_DRAG_LIMIT))) { + ext->drag_ver = 1; + } + + if(ext->drag_hor) { + ext->page.edge_flash.top_ip = 0; + ext->page.edge_flash.bottom_ip = 0; + } + + if(ext->drag_ver) { + ext->page.edge_flash.right_ip = 0; + ext->page.edge_flash.left_ip = 0; + } + + lv_coord_t x = lv_obj_get_x(scrl); + lv_coord_t y = lv_obj_get_y(scrl); + lv_coord_t h = lv_obj_get_height(tileview); + lv_coord_t w = lv_obj_get_width(tileview); + if(ext->drag_top_en == 0) { + if(y > -(ext->act_id.y * h) && indev->proc.vect.y > 0 && ext->drag_hor == 0) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.top_ip = 1; + lv_page_start_edge_flash(tileview); + } + + lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver); + } + } + if(ext->drag_bottom_en == 0 && indev->proc.vect.y < 0 && ext->drag_hor == 0) { + if(y < -(ext->act_id.y * h)) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.bottom_ip = 1; + lv_page_start_edge_flash(tileview); + } + } + + lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver); + } + if(ext->drag_left_en == 0) { + if(x > -(ext->act_id.x * w) && indev->proc.vect.x > 0 && ext->drag_ver == 0) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.left_ip = 1; + lv_page_start_edge_flash(tileview); + } + + lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor); + } + } + if(ext->drag_right_en == 0 && indev->proc.vect.x < 0 && ext->drag_ver == 0) { + if(x < -(ext->act_id.x * w)) { + if(ext->page.edge_flash.enabled && + ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 && + ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) { + ext->page.edge_flash.right_ip = 1; + lv_page_start_edge_flash(tileview); + } + } + + lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor); + } + + /*Apply the drag constraints*/ + if(ext->drag_ver == 0) lv_obj_set_y(scrl, - ext->act_id.y * lv_obj_get_height(tileview) + style_bg->body.padding.ver); + if(ext->drag_hor == 0) lv_obj_set_x(scrl, - ext->act_id.x * lv_obj_get_width(tileview) + style_bg->body.padding.hor); + } + } + + return res; + +} + +/** + * This function is applied called for the elements of the tileview. Used when the element is + * @param element + * @param sign + * @param param + * @return + */ +static lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + lv_signal_func_t sign_func = lv_obj_get_free_ptr(element); + res = sign_func(element, sign, param); + if(res != LV_RES_OK) return res; + + /*Initialize some variables on PRESS*/ + if(sign == LV_SIGNAL_PRESSED) { + /*Get the tileview from the element*/ + lv_obj_t * tileview = lv_obj_get_parent(element); + while(tileview) { + if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview); + else break; + } + + if(tileview) { + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + ext->drag_hor = 0; + ext->drag_ver = 0; + set_valid_drag_dirs(tileview); + } + } + + /*Animate the tabview to the correct location on RELEASE*/ + else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED) { + + /*Get the tileview from the element*/ + lv_obj_t * tileview = lv_obj_get_parent(element); + while(tileview) { + if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview); + else break; + } + + if(tileview) { + /* If the element was dragged and it moved the tileview finish the drag manually to + * let the tileview to finish the move.*/ + lv_indev_t * indev = lv_indev_get_act(); + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + if(indev->proc.drag_in_prog && (ext->drag_hor || ext->drag_ver)) { + + lv_obj_t * drag_obj = element; + while(lv_obj_get_drag_parent(drag_obj)) { + drag_obj = lv_obj_get_parent(drag_obj); + if(drag_obj == NULL) break; + } + indev->proc.drag_in_prog = 0; + if(drag_obj) drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, NULL); + } + + drag_end_handler(tileview); + } + } + + return res; +} + +/** + * Called when the user releases an element of the tileview after dragging it. + * @param tileview pointer to a tileview object + */ +static void drag_end_handler(lv_obj_t * tileview) +{ + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + lv_indev_t * indev = lv_indev_get_act(); + lv_point_t point_act; + lv_indev_get_point(indev, &point_act); + lv_obj_t * scrl = lv_page_get_scrl(tileview); + lv_point_t p; + + p.x = - (scrl->coords.x1 - LV_HOR_RES / 2); + p.y = - (scrl->coords.y1 - LV_VER_RES / 2); + + /*From the drag vector (drag throw) predict the end position*/ + if(ext->drag_hor) { + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t predict = 0; + + while(vect.x != 0) { + predict += vect.x; + vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + p.x -= predict; + } + else if(ext->drag_ver) { + lv_point_t vect; + lv_indev_get_vect(indev, &vect); + lv_coord_t predict = 0; + + while(vect.y != 0) { + predict += vect.y; + vect.y = vect.y * (100 - LV_INDEV_DRAG_THROW) / 100; + } + + p.y -= predict; + } + + /*Get the index of the tile*/ + p.x = p.x / lv_obj_get_width(tileview); + p.y = p.y / lv_obj_get_height(tileview); + + /*Max +- move*/ + lv_coord_t x_move = p.x - ext->act_id.x; + lv_coord_t y_move = p.y - ext->act_id.y; + if(x_move < -1) x_move = -1; + if(x_move > 1) x_move = 1; + if(y_move < -1) y_move = -1; + if(y_move > 1) y_move = 1; + + /*Set the new tile*/ + lv_tileview_set_tile_act(tileview, ext->act_id.x + x_move, ext->act_id.y + y_move,true); +} + +static bool set_valid_drag_dirs(lv_obj_t * tileview) +{ + + lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview); + if(ext->valid_pos == NULL) return false; + + ext->drag_bottom_en = 0; + ext->drag_top_en = 0; + ext->drag_left_en = 0; + ext->drag_right_en = 0; + + uint16_t i; + for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) { + if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y - 1) ext->drag_top_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y + 1) ext->drag_bottom_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x - 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_left_en = 1; + if(ext->valid_pos[i].x == ext->act_id.x + 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_right_en = 1; + } + + return true; +} + + +#endif diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.h new file mode 100644 index 0000000..d276fea --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_tileview.h @@ -0,0 +1,163 @@ +/** + * @file lv_tileview.h + * + */ + + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_TILEVIEW != 0 + +#include "../lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + + + +/* parametes: pointer to a tileview object, x, y (tile coordinates to load) + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t); + +/*Data of tileview*/ +typedef struct { + lv_page_ext_t page; + /*New data for this type */ + const lv_point_t * valid_pos; + uint16_t anim_time; + lv_tileview_action_t action; + lv_point_t act_id; + uint8_t drag_top_en :1; + uint8_t drag_bottom_en :1; + uint8_t drag_left_en :1; + uint8_t drag_right_en :1; + uint8_t drag_hor :1; + uint8_t drag_ver :1; +} lv_tileview_ext_t; + + +/*Styles*/ +enum { + LV_TILEVIEW_STYLE_BG, +}; +typedef uint8_t lv_tileview_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a tileview objects + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element); + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos); + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param tileview pointer to a Tileview + * @param en true or false to enable/disable end flash + */ +static inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en) +{ + lv_page_set_edge_flash(tileview, en); +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scroll propagation property + * @param tileview pointer to a Tileview + * @return true or false + */ +static inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview) +{ + return lv_page_get_edge_flash(tileview); +} + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TILEVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.c b/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.c new file mode 100644 index 0000000..c21c08d --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_win.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_win.h" +#if USE_LV_WIN != 0 + +#include "../lv_themes/lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param); +static void lv_win_realign(lv_obj_t * win); + +/********************** + * STATIC VARIABLES + **********************/ +static lv_signal_func_t ancestor_signal; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy) +{ + LV_LOG_TRACE("window create started"); + + /*Create the ancestor object*/ + lv_obj_t * new_win = lv_obj_create(par, copy); + lv_mem_assert(new_win); + if(new_win == NULL) return NULL; + + if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_win); + + /*Allocate the object type specific extended data*/ + lv_win_ext_t * ext = lv_obj_allocate_ext_attr(new_win, sizeof(lv_win_ext_t)); + lv_mem_assert(ext); + if(ext == NULL) return NULL; + + ext->page = NULL; + ext->header = NULL; + ext->title = NULL; + ext->style_header = &lv_style_plain_color; + ext->style_btn_rel = &lv_style_btn_rel; + ext->style_btn_pr = &lv_style_btn_pr; + ext->btn_size = (LV_DPI) / 2; + + /*Init the new window object*/ + if(copy == NULL) { + lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES); + lv_obj_set_pos(new_win, 0, 0); + lv_obj_set_style(new_win, &lv_style_pretty); + + ext->page = lv_page_create(new_win, NULL); + lv_obj_set_protect(ext->page, LV_PROTECT_PARENT); + lv_page_set_sb_mode(ext->page, LV_SB_MODE_AUTO); + lv_page_set_arrow_scroll(ext->page, true); + + /*Create a holder for the header*/ + ext->header = lv_obj_create(new_win, NULL); + /*Move back the header because it is automatically moved to the scrollable */ + lv_obj_set_protect(ext->header, LV_PROTECT_PARENT); + lv_obj_set_parent(ext->header, new_win); + lv_obj_set_width(ext->header, LV_HOR_RES - 62);//// + ext->btn_size = lv_obj_get_height(ext->header) - 3;//// + + /*Create a title on the header*/ + ext->title = lv_label_create(ext->header, NULL); + lv_label_set_text(ext->title, "My title"); + + /*Set the default styles*/ + lv_theme_t * th = lv_theme_get_current(); + if(th) { + lv_win_set_style(new_win, LV_WIN_STYLE_BG, th->win.bg); + lv_win_set_style(new_win, LV_WIN_STYLE_SB, th->win.sb); + lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, th->win.header); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, th->win.content.bg); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, th->win.content.scrl); + lv_win_set_style(new_win, LV_WIN_STYLE_BTN_REL, th->win.btn.rel); + lv_win_set_style(new_win, LV_WIN_STYLE_BTN_PR, th->win.btn.pr); + } else { + lv_win_set_style(new_win, LV_WIN_STYLE_BG, &lv_style_plain); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, &lv_style_plain); + lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, &lv_style_transp); + lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, &lv_style_plain_color); + } + + lv_obj_set_signal_func(new_win, lv_win_signal); + lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES); + } + /*Copy an existing object*/ + else { + lv_win_ext_t * copy_ext = lv_obj_get_ext_attr(copy); + /*Create the objects*/ + ext->header = lv_obj_create(new_win, copy_ext->header); + ext->title = lv_label_create(ext->header, copy_ext->title); + ext->page = lv_page_create(new_win, copy_ext->page); + ext->btn_size = copy_ext->btn_size; + + /*Copy the control buttons*/ + lv_obj_t * child; + lv_obj_t * cbtn; + child = lv_obj_get_child_back(copy_ext->header, NULL); + child = lv_obj_get_child_back(copy_ext->header, child); /*Sip the title*/ + while(child != NULL) { + cbtn = lv_btn_create(ext->header, child); + lv_img_create(cbtn, lv_obj_get_child(child, NULL)); + child = lv_obj_get_child_back(copy_ext->header, child); + } + + lv_obj_set_signal_func(new_win, lv_win_signal); + + /*Refresh the style with new signal function*/ + lv_obj_refresh_style(new_win); + } + + lv_win_realign(new_win); + + LV_LOG_INFO("window created"); + + return new_win; +} + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t * obj) +{ + lv_obj_t * scrl = lv_page_get_scrl(obj); + lv_obj_clean(scrl); +} + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + lv_obj_t * btn = lv_btn_create(ext->header, NULL); + lv_btn_set_style(btn, LV_BTN_STYLE_REL, ext->style_btn_rel); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, ext->style_btn_pr); + lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size); + lv_btn_set_fit(btn, true, false); + lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, rel_action); + + if (img_src) + { + lv_obj_t * img = lv_img_create(btn, NULL); + lv_obj_set_click(img, false); + lv_img_set_src(img, img_src); + } + else if (label_src) + { + lv_obj_t *label = lv_label_create(btn, NULL); + lv_label_set_recolor(label, true); + lv_label_set_text(label, label_src); + } + + lv_win_realign(win); + + return btn; +} + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn) +{ + lv_obj_t * win = lv_win_get_from_btn(btn); + + lv_obj_del(win); + + return LV_RES_INV; +} + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + lv_label_set_text(ext->title, title); + lv_win_realign(win); +} + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @param size control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + if(ext->btn_size == size) return; + + ext->btn_size = size; + + lv_win_realign(win); +} + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t * win, lv_layout_t layout) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_set_scrl_layout(ext->page, layout); +} + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t * win, lv_sb_mode_t sb_mode) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_set_sb_mode(ext->page, sb_mode); +} + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t * win, lv_win_style_t type, lv_style_t * style) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + switch(type) { + case LV_WIN_STYLE_BG: + lv_obj_set_style(win, style); + lv_win_realign(win); + break; + case LV_WIN_STYLE_CONTENT_BG: + lv_page_set_style(ext->page, LV_PAGE_STYLE_BG, style); + break; + case LV_WIN_STYLE_CONTENT_SCRL: + lv_page_set_style(ext->page, LV_PAGE_STYLE_SCRL, style); + break; + case LV_WIN_STYLE_SB: + lv_page_set_style(ext->page, LV_PAGE_STYLE_SB, style); + break; + case LV_WIN_STYLE_HEADER: + lv_obj_set_style(ext->header, style); + lv_win_realign(win); + break; + case LV_WIN_STYLE_BTN_REL: + ext->style_btn_rel = style; + break; + case LV_WIN_STYLE_BTN_PR: + ext->style_btn_pr = style; + break; + } + + /*Refresh the existing buttons*/ + if(type == LV_WIN_STYLE_BTN_REL || type == LV_WIN_STYLE_BTN_PR) { + lv_obj_t * btn; + btn = lv_obj_get_child_back(ext->header, NULL); + btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/ + while(btn != NULL) { + if(type == LV_WIN_STYLE_BTN_REL) lv_btn_set_style(btn, LV_BTN_STYLE_REL, style); + else lv_btn_set_style(btn, LV_BTN_STYLE_PR, style); + btn = lv_obj_get_child_back(ext->header, btn); + } + } +} + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_obj_t * win_header = ext->header; + lv_obj_set_drag_parent(win_header, en); + lv_obj_set_drag(win, en); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_label_get_text(ext->title); +} + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return ext->page; +} + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return ext->btn_size; +} + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn) +{ + lv_obj_t * header = lv_obj_get_parent(ctrl_btn); + lv_obj_t * win = lv_obj_get_parent(header); + + return win; +} + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_page_get_scrl_layout(ext->page); +} + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + return lv_page_get_sb_mode(ext->page); +} + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content_bg area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_obj_t * scrl = lv_page_get_scrl(ext->page); + lv_style_t * style_scrl = lv_obj_get_style(scrl); + + return lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor; +} + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t * win, lv_win_style_t type) +{ + lv_style_t * style = NULL; + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + switch(type) { + case LV_WIN_STYLE_BG: + style = lv_obj_get_style(win); + break; + case LV_WIN_STYLE_CONTENT_BG: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_BG); + break; + case LV_WIN_STYLE_CONTENT_SCRL: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SCRL); + break; + case LV_WIN_STYLE_SB: + style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SB); + break; + case LV_WIN_STYLE_HEADER: + style = lv_obj_get_style(ext->header); + break; + case LV_WIN_STYLE_BTN_REL: + style = ext->style_btn_rel; + break; + case LV_WIN_STYLE_BTN_PR: + style = ext->style_btn_pr; + break; + default: + style = NULL; + break; + } + + return style; +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + lv_page_focus(ext->page, obj, anim_time); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Signal function of the window + * @param win pointer to a window object + * @param sign a signal type from lv_signal_t enum + * @param param pointer to a signal specific variable + * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted + */ +static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param) +{ + lv_res_t res; + + /* Include the ancient signal function */ + res = ancestor_signal(win, sign, param); + if(res != LV_RES_OK) return res; + + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + if(sign == LV_SIGNAL_CHILD_CHG) { /*Move children to the page*/ + lv_obj_t * page = ext->page; + if(page != NULL) { + lv_obj_t * child; + child = lv_obj_get_child(win, NULL); + while(child != NULL) { + if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) { + lv_obj_t * tmp = child; + child = lv_obj_get_child(win, child); /*Get the next child before move this*/ + lv_obj_set_parent(tmp, page); + } else { + child = lv_obj_get_child(win, child); + } + } + } + } else if(sign == LV_SIGNAL_STYLE_CHG) { + lv_win_realign(win); + } else if(sign == LV_SIGNAL_CORD_CHG) { + /*If the size is changed refresh the window*/ + if(lv_area_get_width(param) != lv_obj_get_width(win) || + lv_area_get_height(param) != lv_obj_get_height(win)) { + lv_win_realign(win); + } + } else if(sign == LV_SIGNAL_CLEANUP) { + ext->header = NULL; /*These objects were children so they are already invalid*/ + ext->page = NULL; + ext->title = NULL; + } else if(sign == LV_SIGNAL_CONTROLL) { + /*Forward all the control signals to the page*/ + ext->page->signal_func(ext->page, sign, param); + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_win"; + } + + + return res; +} + +/** + * Realign the building elements of a window + * @param win pointer to window objectker + */ +static void lv_win_realign(lv_obj_t * win) +{ + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + if(ext->page == NULL || ext->header == NULL || ext->title == NULL) return; + + lv_style_t * header_style = lv_win_get_style(win, LV_WIN_STYLE_HEADER); + lv_obj_set_size(ext->header, lv_obj_get_width(win) - 62, ext->btn_size + 2 * header_style->body.padding.ver); + + bool first_btn = true; + lv_obj_t * btn; + lv_obj_t * btn_prev = NULL; + /*Refresh the size of all control buttons*/ + btn = lv_obj_get_child_back(ext->header, NULL); + btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/ + while(btn != NULL) { + lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size); + if(first_btn) { + lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, - header_style->body.padding.hor, 0); + first_btn = false; + } else { + lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_style->body.padding.inner, 0); + } + btn_prev = btn; + btn = lv_obj_get_child_back(ext->header, btn); + } + + + lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, ext->style_header->body.padding.hor, 0); + + lv_obj_set_pos(ext->header, 31, 0); + + lv_obj_set_size(ext->page, lv_obj_get_width(win), lv_obj_get_height(win) - lv_obj_get_height(ext->header)); + lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); +} + +#endif + diff --git a/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.h b/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.h new file mode 100644 index 0000000..4bb5d00 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_objx/lv_win.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_WIN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#if USE_LV_IMG == 0 +#error "lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG 1) " +#endif + + +#if USE_LV_PAGE == 0 +#error "lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "../lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" +#include "lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of window*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * page; /*Pointer to a page which holds the content*/ + lv_obj_t * header; /*Pointer to the header container of the window*/ + lv_obj_t * title; /*Pointer to the title label of the window*/ + lv_style_t * style_header; /*Style of the header container*/ + lv_style_t * style_btn_rel; /*Control button releases style*/ + lv_style_t * style_btn_pr; /*Control button pressed style*/ + lv_coord_t btn_size; /*Size of the control buttons (square)*/ +} lv_win_ext_t; + +enum { + LV_WIN_STYLE_BG, + LV_WIN_STYLE_CONTENT_BG, + LV_WIN_STYLE_CONTENT_SCRL, + LV_WIN_STYLE_SB, + LV_WIN_STYLE_HEADER, + LV_WIN_STYLE_BTN_REL, + LV_WIN_STYLE_BTN_PR, +}; +typedef uint8_t lv_win_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action); + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn); + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title); + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size); + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t *win, lv_layout_t layout); + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode); + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style); + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win); + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win); + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win); + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn); + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t *win); + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win); + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win); + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type); + +/** + * Get drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @return whether window is draggable + */ +static inline bool lv_win_get_drag(const lv_obj_t *win) +{ + return lv_obj_get_drag(win); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the window horizontally + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +static inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_hor(ext->page, dist); +} +/** + * Scroll the window vertically + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +static inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_ver(ext->page, dist); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_WIN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_WIN_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.c b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.c new file mode 100644 index 0000000..59a0489 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.c @@ -0,0 +1,112 @@ +/** + * @file lv_theme.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_theme.h" +#include "../lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +#if LV_THEME_LIVE_UPDATE == 0 +static lv_theme_t * current_theme; +#else +/* If live update is used then a big `lv_style_t` array is used to store the real styles of the theme not only pointers. + * On `lv_theme_set_current` the styles of the theme are copied to this array. + * The pointers in `current_theme` are initialized to point to the styles in the array. + * This way the theme styles will always point to the same memory address even after theme is change. + * (The pointers in the theme points to the styles declared by the theme itself) */ + +/* Store the styles in this array. + * Can't determine the size in compile time because sizeof is not evaluated (should be `sizeof(lv_theme_t) / sizeof(lv_style_t*)`). + * Error will be generated in run time if too small.*/ +static lv_style_t th_styles[120]; +static bool inited = false; +static lv_theme_t current_theme; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t * th) +{ +#if LV_THEME_LIVE_UPDATE == 0 + current_theme = th; +#else + uint32_t style_num = sizeof(lv_theme_t) / sizeof(lv_style_t *); /*Number of styles in a theme*/ + + if(!inited) { + /*It's not sure `th_styles` is big enough. Check it now!*/ + if(style_num > sizeof(th_styles) / sizeof(lv_style_t)) { + LV_LOG_ERROR("Themes: th_styles array is too small. Increase it's size!"); + while(1); + } + + /*Initialize the style pointers `current_theme` to point to the `th_styles` style array */ + uint16_t i; + lv_style_t ** cur_th_style_p = (lv_style_t **) ¤t_theme; + for(i = 0; i < style_num; i++) { + uintptr_t adr = (uintptr_t)&th_styles[i]; + memcpy(&cur_th_style_p[i], &adr, sizeof(lv_style_t *)); + } + inited = true; + } + + + /*Copy the styles pointed by the new theme to the `th_styles` style array*/ + uint16_t i; + lv_style_t ** th_style = (lv_style_t **) th; + for(i = 0; i < style_num; i++) { + uintptr_t s = (uintptr_t)th_style[i]; + if(s) memcpy(&th_styles[i], (void *)s, sizeof(lv_style_t)); + } + + /*Let the object know their style might change*/ + lv_obj_report_style_mod(NULL); +#endif +} + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void) +{ +#if LV_THEME_LIVE_UPDATE == 0 + return current_theme; +#else + if(!inited) return NULL; + else return ¤t_theme; +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.h b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.h new file mode 100644 index 0000000..f66f9c8 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + *@file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#include "../lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_style_t *bg; + lv_style_t *panel; + +#if USE_LV_CONT != 0 + lv_style_t *cont; +#endif + +#if USE_LV_BTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; +#endif + + +#if USE_LV_IMGBTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } imgbtn; +#endif + +#if USE_LV_LABEL != 0 + struct { + lv_style_t *prim; + lv_style_t *sec; + lv_style_t *hint; + } label; +#endif + +#if USE_LV_IMG != 0 + struct { + lv_style_t *light; + lv_style_t *dark; + } img; +#endif + +#if USE_LV_LINE != 0 + struct { + lv_style_t *decor; + } line; +#endif + +#if USE_LV_LED != 0 + lv_style_t *led; +#endif + +#if USE_LV_BAR != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + } bar; +#endif + +#if USE_LV_SLIDER != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob; + } slider; +#endif + +#if USE_LV_LMETER != 0 + lv_style_t *lmeter; +#endif + +#if USE_LV_GAUGE != 0 + lv_style_t *gauge; +#endif + +#if USE_LV_ARC != 0 + lv_style_t *arc; +#endif + +#if USE_LV_PRELOAD != 0 + lv_style_t *preload; +#endif + +#if USE_LV_SW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob_off; + lv_style_t *knob_on; + } sw; +#endif + +#if USE_LV_CHART != 0 + lv_style_t *chart; +#endif + +#if USE_LV_CALENDAR != 0 + struct { + lv_style_t *bg; + lv_style_t *header; + lv_style_t *header_pr; + lv_style_t *day_names; + lv_style_t *highlighted_days; + lv_style_t *inactive_days; + lv_style_t *week_box; + lv_style_t *today_box; + } calendar; +#endif + +#if USE_LV_CB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } box; + } cb; +#endif + +#if USE_LV_BTNM != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } btnm; +#endif + +#if USE_LV_KB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } kb; +#endif + +#if USE_LV_MBOX != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + } btn; + } mbox; +#endif + +#if USE_LV_PAGE != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } page; +#endif + +#if USE_LV_TA != 0 + struct { + lv_style_t *area; + lv_style_t *oneline; + lv_style_t *cursor; + lv_style_t *sb; + } ta; +#endif + +#if USE_LV_SPINBOX != 0 + struct { + lv_style_t *bg; + lv_style_t *cursor; + lv_style_t *sb; + } spinbox; +#endif + +#if USE_LV_LIST + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } list; +#endif + +#if USE_LV_DDLIST != 0 + struct { + lv_style_t *bg; + lv_style_t *bgo; + lv_style_t *pr; + lv_style_t *sel; + lv_style_t *sb; + } ddlist; +#endif + +#if USE_LV_ROLLER != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + } roller; +#endif + +#if USE_LV_TABVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + } btn; + } tabview; +#endif + +#if USE_LV_TILEVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } tileview; +#endif + +#if USE_LV_TABLE != 0 + struct { + lv_style_t *bg; + lv_style_t *cell; + } table; +#endif + +#if USE_LV_WIN != 0 + struct { + lv_style_t *bg; + lv_style_t *sb; + lv_style_t *header; + struct { + lv_style_t *bg; + lv_style_t *scrl; + } content; + struct { + lv_style_t *rel; + lv_style_t *pr; + } btn; + } win; +#endif +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t *th); + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDE + *********************/ +#include "lv_theme_hekate.h" + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c new file mode 100644 index 0000000..d12732c --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.c @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_theme.h" + +#if USE_LV_THEME_HEKATE + +/********************* + * DEFINES + *********************/ +#define DEF_RADIUS 4 +#define COLOR_SHADOW_LIGHT LV_COLOR_HEX(0xAAAAAA) +#define COLOR_SHADOW_DARK LV_COLOR_HEX(0x1F1F1F) +#define COLOR_HOS_TURQUOISE (lv_color_hsv_to_rgb(_hue, 100, 100)) // 0x00FFC9 +#define COLOR_HOS_TEAL_LIGHTER (lv_color_hsv_to_rgb(_hue, 100, 93)) // 0x00EDBA +#define COLOR_HOS_TEAL_LIGHT (lv_color_hsv_to_rgb(_hue, 100, 72)) // 0x00B78F +#define COLOR_HOS_TEAL (lv_color_hsv_to_rgb(_hue, 100, 64)) // 0x00A273 +#define COLOR_HOS_ORANGE LV_COLOR_HEX(0xFF5500) +#define COLOR_HOS_BG_DARKER LV_COLOR_HEX(0x1B1B1B) +#define COLOR_HOS_BG_DARK LV_COLOR_HEX(0x222222) +#define COLOR_HOS_BG LV_COLOR_HEX(0x2D2D2D) +#define COLOR_HOS_BG_LIGHT LV_COLOR_HEX(0x3D3D3D) +#define COLOR_HOS_LIGHT_BORDER LV_COLOR_HEX(0x4D4D4D) +#define COLOR_HOS_TXT_WHITE LV_COLOR_HEX(0xFBFBFB) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_theme_t theme; +static lv_style_t def; + +/*Static style definitions*/ +static lv_style_t sb; + +/*Saved input parameters*/ +static uint16_t _hue; +static lv_font_t * _font; + +/********************** + * MACROS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void basic_init(void) +{ + static lv_style_t bg, panel; + + lv_style_copy(&def, &lv_style_plain); // Initialize the default style. + def.text.font = _font; + def.body.radius = DEF_RADIUS; + def.text.color = COLOR_HOS_TXT_WHITE; + //def.image.color = COLOR_HOS_TXT_WHITE; //Needed if symbol image. + //def.image.opa = LV_OPA_COVER; + + lv_style_copy(&bg, &def); + bg.body.main_color = COLOR_HOS_BG; + //bg.body.main_color = LV_COLOR_BLACK; + bg.body.grad_color = bg.body.main_color; + bg.body.radius = 0; + bg.body.empty = 1; + + lv_style_copy(&panel, &def); + panel.body.radius = DEF_RADIUS; + panel.body.main_color = COLOR_HOS_BG; + panel.body.grad_color = COLOR_HOS_BG; + panel.body.border.width = 1; + panel.body.border.color = COLOR_HOS_LIGHT_BORDER; + panel.body.border.opa = LV_OPA_COVER; + panel.body.shadow.color = COLOR_SHADOW_LIGHT; + panel.body.shadow.type = LV_SHADOW_BOTTOM; + panel.body.shadow.width = 4; + panel.body.padding.hor = LV_DPI / 8; + panel.body.padding.ver = LV_DPI / 8; + panel.body.padding.inner = LV_DPI / 12; + //panel.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&sb, &def); + sb.body.main_color = LV_COLOR_BLACK; + sb.body.grad_color = LV_COLOR_BLACK; + sb.body.opa = LV_OPA_40; + sb.body.padding.hor = LV_DPI / 25; + + theme.bg = &bg; + theme.panel = &panel; +} + +static void cont_init(void) +{ +#if USE_LV_CONT != 0 + static lv_style_t cont; + lv_style_copy(&cont, theme.panel); + cont.body.shadow.width = 0; + cont.body.border.width = 0; + + theme.cont = &cont; +#endif +} + +static void btn_init(void) +{ +#if USE_LV_BTN != 0 + static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&rel, &def); + rel.body.main_color = COLOR_HOS_BG_LIGHT; + rel.body.grad_color = rel.body.main_color; + rel.body.radius = 6; + rel.body.padding.hor = LV_DPI / 3; + rel.body.padding.ver = LV_DPI / 6; + rel.body.padding.inner = LV_DPI / 10; + rel.body.shadow.color = COLOR_SHADOW_DARK; + rel.body.shadow.type = LV_SHADOW_BOTTOM; + rel.body.shadow.width = 6; + rel.body.border.width = 0; + rel.body.border.color = COLOR_HOS_BG_LIGHT; + rel.body.border.part = LV_BORDER_FULL; + //rel.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&pr, &rel); + pr.body.main_color = LV_COLOR_HEX(0x505050); + pr.body.grad_color = pr.body.main_color; + pr.body.shadow.width = 0; + pr.body.border.color = COLOR_HOS_TEAL_LIGHTER; + pr.text.color = COLOR_HOS_TURQUOISE; + pr.body.border.width = 4; + + lv_style_copy(&tgl_rel, &rel); + tgl_rel.body.border.color = COLOR_HOS_TEAL_LIGHTER; + tgl_rel.body.border.width = 4; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = LV_COLOR_HEX(0x505050); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.text.color = COLOR_HOS_TURQUOISE; + tgl_pr.body.shadow.width = 0; + + lv_style_copy(&ina, &rel); + ina.body.main_color = COLOR_HOS_BG_DARK; + ina.body.grad_color = ina.body.main_color; + //ina.body.shadow.width = 0; + ina.text.color = LV_COLOR_HEX(0x888888); + ina.body.border.width = 4; + + theme.btn.rel = &rel; + theme.btn.pr = ≺ + theme.btn.tgl_rel = &tgl_rel; + theme.btn.tgl_pr = &tgl_pr; + theme.btn.ina = &ina; +#endif +} + + +static void label_init(void) +{ +#if USE_LV_LABEL != 0 + static lv_style_t prim, sec, hint; + + lv_style_copy(&prim, &def); + prim.text.font = _font; + prim.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&sec, &prim); + sec.text.color = COLOR_HOS_ORANGE; + + lv_style_copy(&hint, &prim); + hint.text.color = LV_COLOR_HEX(0xCCCCCC); + + theme.label.prim = &prim; + theme.label.sec = &sec; + theme.label.hint = &hint; +#endif +} + +static void img_init(void) +{ +#if USE_LV_IMG != 0 + static lv_style_t img_light, img_dark; + lv_style_copy(&img_light, &def); + img_light.image.color = LV_COLOR_WHITE; + img_light.image.intense = LV_OPA_80; + + lv_style_copy(&img_dark, &def); + img_dark.image.color = COLOR_HOS_BG_DARKER; + img_dark.image.intense = LV_OPA_80; + + + theme.img.light = &def; + theme.img.dark = &def; +#endif +} + +static void line_init(void) +{ +#if USE_LV_LINE != 0 + static lv_style_t line; + lv_style_copy(&line, &def); + line.line.color = LV_COLOR_HEX(0x656565); + theme.line.decor = &line; +#endif +} + +static void led_init(void) +{ +#if USE_LV_LED != 0 + static lv_style_t led; + lv_style_copy(&led, &def); + led.body.shadow.width = LV_DPI / 10; + led.body.radius = LV_RADIUS_CIRCLE; + led.body.border.width = LV_DPI / 30; + led.body.border.opa = LV_OPA_30; + led.body.main_color = lv_color_hsv_to_rgb(_hue, 100, 100); + led.body.grad_color = lv_color_hsv_to_rgb(_hue, 100, 100); + led.body.border.color = lv_color_hsv_to_rgb(_hue, 60, 60); + led.body.shadow.color = lv_color_hsv_to_rgb(_hue, 100, 100); + + theme.led = &led; +#endif +} + +static void bar_init(void) +{ +#if USE_LV_BAR + static lv_style_t bar_bg, bar_indic; + + lv_style_copy(&bar_bg, &def); + bar_bg.body.main_color = COLOR_HOS_LIGHT_BORDER; + bar_bg.body.grad_color = bar_bg.body.main_color; + bar_bg.body.radius = 3; + bar_bg.body.border.width = 0; + bar_bg.body.padding.hor = LV_DPI / 12; + bar_bg.body.padding.ver = LV_DPI / 12; + + lv_style_copy(&bar_indic, &bar_bg); + bar_indic.body.main_color = COLOR_HOS_TURQUOISE; + bar_indic.body.grad_color = bar_indic.body.main_color; + bar_indic.body.padding.hor = 0; + bar_indic.body.padding.ver = 0; + + theme.bar.bg = &bar_bg; + theme.bar.indic = &bar_indic; +#endif +} + +static void slider_init(void) +{ +#if USE_LV_SLIDER != 0 + static lv_style_t knob; + static lv_style_t slide_bar; + + lv_style_copy(&knob, &def); + knob.body.radius = LV_RADIUS_CIRCLE; + knob.body.border.width = 0; + knob.body.main_color = theme.bar.indic->body.main_color; + knob.body.grad_color = knob.body.main_color; + + lv_style_copy(&slide_bar, theme.bar.indic); + slide_bar.body.main_color = COLOR_HOS_TEAL_LIGHT; + slide_bar.body.grad_color = slide_bar.body.main_color; + + theme.slider.bg = theme.bar.bg; + theme.slider.indic = &slide_bar; + theme.slider.knob = &knob; +#endif +} + +static void sw_init(void) +{ +#if USE_LV_SW != 0 + static lv_style_t sw_bg, sw_indic, sw_knob_off, sw_knob_on; + lv_style_copy(&sw_bg, theme.slider.bg); + sw_bg.body.radius = LV_RADIUS_CIRCLE; + + lv_style_copy(&sw_indic, theme.slider.bg); + sw_indic.body.radius = LV_RADIUS_CIRCLE; + + lv_style_copy(&sw_knob_on, theme.slider.knob); + + lv_style_copy(&sw_knob_off, &sw_knob_on); + sw_knob_off.body.main_color = LV_COLOR_HEX(0xDADADA); + sw_knob_off.body.grad_color = sw_knob_off.body.main_color; + sw_knob_off.body.border.width = 1; + sw_knob_off.body.border.color = LV_COLOR_HEX(0x999999); + sw_knob_off.body.border.opa = LV_OPA_COVER; + + theme.sw.bg = &sw_bg; + theme.sw.indic = &sw_indic; + theme.sw.knob_off = &sw_knob_off; + theme.sw.knob_on = &sw_knob_on; +#endif +} + + +static void lmeter_init(void) +{ +#if USE_LV_LMETER != 0 + static lv_style_t lmeter; + lv_style_copy(&lmeter, &def); + lmeter.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 90); + lmeter.body.grad_color = lmeter.body.main_color; + lmeter.body.padding.hor = LV_DPI / 10; // Scale line length. + lmeter.line.color = LV_COLOR_HEX(0x999999); + lmeter.line.width = 2; + + theme.lmeter = &lmeter; +#endif +} + +static void gauge_init(void) +{ +#if USE_LV_GAUGE != 0 + + static lv_style_t gauge; + lv_style_copy(&gauge, &def); + gauge.body.main_color = lv_color_hsv_to_rgb(_hue, 10, 60); + gauge.body.grad_color = gauge.body.main_color; + gauge.body.padding.hor = LV_DPI / 16; // Scale line length. + gauge.body.padding.inner = LV_DPI / 8; + gauge.body.border.color = LV_COLOR_HEX(0x999999); + gauge.text.color = LV_COLOR_HEX(0xDDDDDD); + gauge.line.width = 3; + gauge.line.color = lv_color_hsv_to_rgb(_hue, 95, 70); + + theme.gauge = &gauge; +#endif +} + +static void arc_init(void) +{ +#if USE_LV_ARC != 0 + + static lv_style_t arc; + lv_style_copy(&arc, &def); + arc.line.width = 10; + arc.line.color = lv_color_hsv_to_rgb(_hue, 90, 90); + + /*For prelaoder*/ + arc.body.border.width = 10; + arc.body.border.color = lv_color_hsv_to_rgb(_hue, 30, 90); + arc.body.padding.hor = 0; + arc.body.padding.ver = 0; + + theme.arc = &arc; +#endif +} + +static void preload_init(void) +{ +#if USE_LV_PRELOAD != 0 + + theme.preload = theme.arc; +#endif +} + +static void chart_init(void) +{ +#if USE_LV_CHART + theme.chart = theme.panel; +#endif +} + +static void calendar_init(void) +{ +#if USE_LV_CALENDAR + static lv_style_t ina_days; + lv_style_copy(&ina_days, &def); + ina_days.text.color = lv_color_hsv_to_rgb(_hue, 0, 70); + + static lv_style_t high_days; + lv_style_copy(&high_days, &def); + high_days.text.color = lv_color_hsv_to_rgb(_hue, 80, 90); + + static lv_style_t week_box; + lv_style_copy(&week_box, &def); + week_box.body.main_color = lv_color_hsv_to_rgb(_hue, 40, 100); + week_box.body.grad_color = lv_color_hsv_to_rgb(_hue, 40, 100); + week_box.body.padding.ver = LV_DPI / 20; + week_box.body.padding.hor = theme.panel->body.padding.hor; + week_box.body.border.color = theme.panel->body.border.color; + week_box.body.border.width = theme.panel->body.border.width; + week_box.body.border.part = LV_BORDER_LEFT | LV_BORDER_RIGHT; + week_box.body.radius = 0; + + static lv_style_t today_box; + lv_style_copy(&today_box, &def); + today_box.body.main_color = LV_COLOR_WHITE; + today_box.body.grad_color = LV_COLOR_WHITE; + today_box.body.padding.ver = LV_DPI / 20; + today_box.body.radius = 0; + + theme.calendar.bg = theme.panel; + theme.calendar.header = &lv_style_transp; + theme.calendar.inactive_days = &ina_days; + theme.calendar.highlighted_days = &high_days; + theme.calendar.week_box = &week_box; + theme.calendar.today_box = &today_box; +#endif +} + +static void cb_init(void) +{ +#if USE_LV_CB != 0 + static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; + lv_style_copy(&rel, theme.panel); + rel.body.shadow.type = LV_SHADOW_FULL; + rel.body.shadow.width = 3; + + lv_style_copy(&pr, &rel); + pr.body.main_color = LV_COLOR_HEX(0xCCCCCC); + pr.body.grad_color = pr.body.main_color; + pr.body.shadow.width = 3; + + lv_style_copy(&tgl_rel, &rel); + tgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 85); + tgl_rel.body.grad_color = tgl_rel.body.main_color; + tgl_rel.body.shadow.width = 0; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 65); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + + lv_style_copy(&ina, theme.btn.ina); + + theme.cb.bg = &lv_style_transp; + theme.cb.box.rel = &rel; + theme.cb.box.pr = ≺ + theme.cb.box.tgl_rel = &tgl_rel; + theme.cb.box.tgl_pr = &tgl_pr; + theme.cb.box.ina = &ina; +#endif +} + + +static void btnm_init(void) +{ +#if USE_LV_BTNM + static lv_style_t bg, rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&bg, theme.panel); + bg.body.padding.hor = 0; + bg.body.padding.ver = 0; + bg.body.padding.inner = 0; + bg.text.color = LV_COLOR_HEX(0x555555); + + lv_style_copy(&rel, theme.panel); + rel.body.border.part = LV_BORDER_FULL | LV_BORDER_INTERNAL; + rel.body.border.width = 1; + rel.body.border.color = LV_COLOR_HEX(0xBBBBBB); + rel.body.empty = 1; + rel.body.shadow.width = 0; + + lv_style_copy(&pr, &rel); + pr.glass = 0; + pr.body.main_color = LV_COLOR_HEX(0xDDDDDD); + pr.body.grad_color = pr.body.main_color; + pr.body.border.width = 0; + pr.body.empty = 0; + + lv_style_copy(&tgl_rel, &pr); + tgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 90, 70); + tgl_rel.body.grad_color = tgl_rel.body.main_color; + tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 95, 65); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + + lv_style_copy(&ina, theme.btn.ina); + + theme.btnm.bg = &bg; + theme.btnm.btn.rel = &rel; + theme.btnm.btn.pr = ≺ + theme.btnm.btn.tgl_rel = &tgl_rel; + theme.btnm.btn.tgl_pr = &tgl_pr; + theme.btnm.btn.ina = &ina; +#endif +} + +static void kb_init(void) +{ +#if USE_LV_KB + + static lv_style_t bg, rel; + + lv_style_copy(&bg, theme.btnm.bg); + bg.text.color = LV_COLOR_HEX(0xCCCCCC); + bg.body.border.width = 0; + bg.body.radius = 0; + bg.body.shadow.color = COLOR_SHADOW_DARK; + bg.body.shadow.type = LV_SHADOW_BOTTOM; + bg.body.shadow.width = 4; + + lv_style_copy(&rel, &lv_style_transp); + rel.text.font = _font; + + theme.kb.bg = &bg; + theme.kb.btn.rel = &rel; + theme.kb.btn.pr = theme.btnm.btn.pr; + theme.kb.btn.tgl_rel = theme.btnm.btn.tgl_rel; + theme.kb.btn.tgl_pr = theme.btnm.btn.tgl_pr; + theme.kb.btn.ina = theme.btnm.btn.ina; +#endif + +} + +static void mbox_init(void) +{ +#if USE_LV_MBOX + static lv_style_t bg; + + lv_style_copy(&bg, theme.panel); + bg.body.main_color = LV_COLOR_HEX(0x464646); + bg.body.grad_color = bg.body.main_color; + bg.body.shadow.color = COLOR_HOS_BG; + bg.body.shadow.type = LV_SHADOW_FULL; + bg.body.shadow.width = 8; + + bg.body.padding.hor = LV_DPI * 3 / 6; + bg.body.padding.ver = LV_DPI / 4; + bg.body.padding.inner = LV_DPI / 3; + + theme.mbox.bg = &bg; + theme.mbox.btn.bg = &lv_style_transp; + theme.mbox.btn.rel = theme.btn.rel; + theme.mbox.btn.pr = theme.btn.pr; +#endif +} + +static void page_init(void) +{ +#if USE_LV_PAGE + theme.page.bg = theme.panel; + theme.page.scrl = &lv_style_transp; + theme.page.sb = &sb; +#endif +} + +static void ta_init(void) +{ +#if USE_LV_TA + static lv_style_t panel, oneline; + + lv_style_copy(&panel, theme.panel); + panel.body.border.width = 0; + panel.body.shadow.color = COLOR_SHADOW_DARK; + panel.body.shadow.type = LV_SHADOW_FULL; + panel.body.shadow.width = 3; + + lv_style_copy(&oneline, &def); + oneline.body.empty = 1; + oneline.body.radius = 0; + oneline.body.border.part = LV_BORDER_BOTTOM; + oneline.body.border.width = 3; + oneline.body.border.color = LV_COLOR_HEX(0x555555); + oneline.body.border.opa = LV_OPA_COVER; + oneline.text.color = LV_COLOR_HEX(0x888888); + + theme.ta.area = &panel; + theme.ta.oneline = &oneline; + theme.ta.cursor = NULL; // Let library to calculate the cursor's style. + theme.ta.sb = &sb; +#endif +} + +static void spinbox_init(void) +{ +#if USE_LV_SPINBOX + theme.spinbox.bg= theme.panel; + theme.spinbox.cursor = theme.ta.cursor; + theme.spinbox.sb = theme.ta.sb; +#endif +} + +static void list_init(void) +{ +#if USE_LV_LIST != 0 + + static lv_style_t list_bg, rel, pr, tgl_rel, tgl_pr, ina; + + lv_style_copy(&list_bg, theme.panel); + list_bg.body.padding.hor = 0; + list_bg.body.padding.ver = 0; + list_bg.body.padding.inner = 0; + list_bg.body.shadow.width = 0; + + lv_style_copy(&rel, &lv_style_transp); + rel.body.padding.hor = LV_DPI / 8; + rel.body.padding.ver = LV_DPI / 6; + rel.body.radius = 0; + rel.body.border.color = LV_COLOR_HEX(0x444444); + rel.body.border.width = 1; + rel.body.border.part = LV_BORDER_BOTTOM; + + lv_style_copy(&pr, &rel); + pr.glass = 0; + pr.body.main_color = LV_COLOR_HEX(0x505050); + pr.body.grad_color = pr.body.main_color; + //pr.body.border.width = 1; + pr.body.empty = 0; + //pr.body.radius = 0; + // pr.text.font = _font; + + lv_style_copy(&tgl_rel, &pr); + tgl_rel.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_rel.body.grad_color = tgl_rel.body.main_color; + //tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); + tgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER; + + lv_style_copy(&tgl_pr, &tgl_rel); + tgl_pr.body.main_color = LV_COLOR_HEX(0x505050); + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + + lv_style_copy(&ina, &pr); + ina.body.main_color = COLOR_HOS_BG_DARK; + ina.body.grad_color = ina.body.main_color; + + theme.list.sb = &sb; + theme.list.bg = &list_bg; + theme.list.scrl = &lv_style_transp_tight; + theme.list.btn.rel = &rel; + theme.list.btn.pr = ≺ + theme.list.btn.tgl_rel = &tgl_rel; + theme.list.btn.tgl_pr = &tgl_pr; + theme.list.btn.ina = &ina; +#endif +} + +static void ddlist_init(void) +{ +#if USE_LV_DDLIST != 0 + static lv_style_t bg, sel; + lv_style_copy(&bg, theme.panel); + bg.body.padding.hor = LV_DPI / 6; + //bg.body.padding.ver = LV_DPI / 6; + bg.body.radius = 0; + bg.body.shadow.width = 0; + bg.body.border.width = 0; + bg.text.line_space = LV_DPI / 8; + bg.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&sel, &bg); + sel.body.main_color = COLOR_HOS_BG_LIGHT; + sel.body.grad_color = sel.body.main_color; + + theme.ddlist.bg = &bg; + theme.ddlist.bgo = &bg; + theme.ddlist.pr = &sel; + theme.ddlist.sel = &sel; + theme.ddlist.sb = &sb; +#endif +} + +static void roller_init(void) +{ +#if USE_LV_ROLLER != 0 + static lv_style_t roller_bg, roller_sel; + + lv_style_copy(&roller_bg, &lv_style_transp); + roller_bg.body.padding.hor = LV_DPI / 6; + roller_bg.body.padding.ver = LV_DPI / 6; + roller_bg.text.line_space = LV_DPI / 8; + roller_bg.text.font = _font; + roller_bg.glass = 0; + roller_bg.text.color = LV_COLOR_HEX(0x444444); + + lv_style_copy(&roller_sel, &roller_bg); + roller_sel.text.color = COLOR_HOS_TURQUOISE; + + theme.roller.bg = &roller_bg; + theme.roller.sel = &roller_sel; +#endif +} + +static void tabview_init(void) +{ +#if USE_LV_TABVIEW != 0 + static lv_style_t indic, btn_bg, rel, pr, tgl_rel, tgl_pr; + + lv_style_copy(&indic, &def); + indic.body.main_color = COLOR_HOS_TURQUOISE; + indic.body.grad_color = indic.body.main_color; + indic.body.radius = 0; + indic.body.border.width = 0; + indic.body.padding.inner = LV_DPI / 20; + indic.body.opa = LV_OPA_0; + + lv_style_copy(&btn_bg, &def); + btn_bg.body.main_color = COLOR_HOS_BG; + btn_bg.body.grad_color = btn_bg.body.main_color; + btn_bg.body.radius = 0; + btn_bg.body.empty = 1; + btn_bg.body.border.width = 0; + btn_bg.body.border.color = LV_COLOR_HEX(0xDDDDDD); + btn_bg.body.border.part = LV_BORDER_BOTTOM; + btn_bg.body.border.opa = LV_OPA_COVER; + btn_bg.body.shadow.width = 0; + btn_bg.body.shadow.color = COLOR_SHADOW_LIGHT; + btn_bg.body.shadow.type = LV_SHADOW_BOTTOM; + btn_bg.body.padding.inner = 0; + btn_bg.body.padding.hor = 0; + btn_bg.body.padding.ver = 0; + btn_bg.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&rel, &lv_style_transp); + rel.body.padding.ver = LV_DPI * 4 / 23; + rel.text.font = _font; + + lv_style_copy(&pr, &def); + pr.body.main_color = COLOR_HOS_BG_LIGHT; + pr.body.grad_color = pr.body.main_color; + pr.body.border.width = 0; + pr.body.empty = 0; + pr.body.radius = 0; + pr.body.border.color = LV_COLOR_HEX(0x888888); + pr.body.border.part = LV_BORDER_BOTTOM; + pr.body.border.opa = LV_OPA_COVER; + pr.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&tgl_rel, &lv_style_transp); + tgl_rel.glass = 0; + tgl_rel.text.font = _font; + tgl_rel.text.color = COLOR_HOS_TURQUOISE; + + lv_style_copy(&tgl_pr, &def); + tgl_pr.body.main_color = COLOR_HOS_BG_LIGHT; + tgl_pr.body.grad_color = tgl_pr.body.main_color; + tgl_pr.body.border.width = 0; + tgl_pr.body.empty = 0; + tgl_pr.body.radius = 0; + tgl_pr.text.color = COLOR_HOS_TURQUOISE; + + theme.tabview.bg = theme.bg; + theme.tabview.indic = &indic; + theme.tabview.btn.bg = &btn_bg; + theme.tabview.btn.rel = &rel; + theme.tabview.btn.pr = ≺ + theme.tabview.btn.tgl_rel = &tgl_rel; + theme.tabview.btn.tgl_pr = &tgl_pr; +#endif +} + +static void tileview_init(void) +{ +#if USE_LV_TILEVIEW != 0 + theme.tileview.bg = &lv_style_transp_tight; + theme.tileview.scrl = &lv_style_transp_tight; + theme.tileview.sb = theme.page.sb; +#endif +} + +static void table_init(void) +{ +#if USE_LV_TABLE != 0 + static lv_style_t cell; + lv_style_copy(&cell, theme.panel); + cell.body.radius = 0; + cell.body.border.width = 1; + cell.body.padding.hor = LV_DPI / 12; + cell.body.padding.ver = LV_DPI / 12; + + theme.table.bg = &lv_style_transp_tight; + theme.table.cell = &cell; +#endif +} + +static void win_init(void) +{ +#if USE_LV_WIN != 0 + static lv_style_t header, rel, pr; + + lv_style_copy(&header, &def); + header.body.main_color = COLOR_HOS_BG; + header.body.grad_color = header.body.main_color; + header.body.radius = 0; + header.body.border.width = 0; + header.body.border.color = LV_COLOR_HEX(0xDDDDDD); + header.body.border.part = LV_BORDER_BOTTOM; + header.body.border.opa = LV_OPA_COVER; + header.body.shadow.width = 0; + header.body.shadow.color = COLOR_SHADOW_LIGHT; + header.body.shadow.type = LV_SHADOW_BOTTOM; + header.body.padding.inner = 0; + header.body.padding.hor = 8; + header.body.padding.ver = 0; + //header.text.color = COLOR_HOS_TXT_WHITE; + + lv_style_copy(&rel, theme.btn.rel); + rel.body.radius = 0; + rel.body.opa = LV_OPA_0; + rel.body.border.width = 0; + + lv_style_copy(&pr, theme.btn.pr); + pr.body.radius = 0; + pr.body.border.width = 0; + + theme.win.bg = theme.panel; + theme.win.sb = &sb; + theme.win.header = &header; + theme.win.content.bg = &lv_style_transp; + theme.win.content.scrl = &lv_style_transp; + theme.win.btn.rel = &rel; + theme.win.btn.pr = ≺ +#endif +} + +/********************** + * GLOBAL FUNCTIONS + **********************/ + + + +/** + * Initialize the hekate theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t * font) +{ + if(font == NULL) font = LV_FONT_DEFAULT; + + _hue = hue; + _font = font; + + /*For backward compatibility initialize all theme elements with a default style */ + uint16_t i; + lv_style_t ** style_p = (lv_style_t **) &theme; + for(i = 0; i < sizeof(lv_theme_t) / sizeof(lv_style_t *); i++) { + *style_p = &def; + style_p++; + } + + basic_init(); + cont_init(); + btn_init(); + label_init(); + img_init(); + line_init(); + led_init(); + bar_init(); + slider_init(); + sw_init(); + lmeter_init(); + gauge_init(); + chart_init(); + arc_init(); + preload_init(); + calendar_init(); + cb_init(); + btnm_init(); + kb_init(); + mbox_init(); + page_init(); + ta_init(); + spinbox_init(); + list_init(); + ddlist_init(); + roller_init(); + tabview_init(); + tileview_init(); + table_init(); + win_init(); + + return &theme; +} + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_hekate(void) +{ + return &theme; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif + diff --git a/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h new file mode 100644 index 0000000..cc61d2d --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_themes/lv_theme_hekate.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LV_THEME_HEKATE_H +#define LV_THEME_HEKATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + +#if USE_LV_THEME_HEKATE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_hekate(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MATERIAL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lv_themes/lv_themes.mk b/ariane/src/bdk/libs/lvgl/lv_themes/lv_themes.mk new file mode 100644 index 0000000..3345b44 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_themes/lv_themes.mk @@ -0,0 +1,9 @@ +CSRCS += lv_theme.c +CSRCS += lv_theme_default.c +CSRCS += lv_theme_templ.c +CSRCS += lv_theme_material.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes +VPATH += :$(LVGL_DIR)/lvgl/lv_themes + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes" diff --git a/ariane/src/bdk/libs/lvgl/lv_version.h b/ariane/src/bdk/libs/lvgl/lv_version.h new file mode 100644 index 0000000..ec8fe64 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lv_version.h @@ -0,0 +1,66 @@ +/** + * @file lv_version.h + * + */ + +#ifndef LV_VERSION_H +#define LV_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +/*Current version of LittlevGL*/ +#define LVGL_VERSION_MAJOR 5 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_INFO "hekate" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +/* Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + * */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VERSION_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lvgl.h b/ariane/src/bdk/libs/lvgl/lvgl.h new file mode 100644 index 0000000..2d0dd56 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lvgl.h @@ -0,0 +1,85 @@ +/** + * @file lvgl.h + * Include all LittleV GL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_version.h" + +#include "lv_misc/lv_log.h" +#include "lv_misc/lv_task.h" + +#include "lv_hal/lv_hal.h" + +#include "lv_core/lv_obj.h" +#include "lv_core/lv_group.h" +#include "lv_core/lv_lang.h" +#include "lv_core/lv_vdb.h" +#include "lv_core/lv_refr.h" + +#include "lv_themes/lv_theme.h" + +#include "lv_objx/lv_btn.h" +#include "lv_objx/lv_imgbtn.h" +#include "lv_objx/lv_img.h" +#include "lv_objx/lv_label.h" +#include "lv_objx/lv_line.h" +#include "lv_objx/lv_page.h" +#include "lv_objx/lv_cont.h" +#include "lv_objx/lv_list.h" +#include "lv_objx/lv_chart.h" +#include "lv_objx/lv_table.h" +#include "lv_objx/lv_cb.h" +#include "lv_objx/lv_bar.h" +#include "lv_objx/lv_slider.h" +#include "lv_objx/lv_led.h" +#include "lv_objx/lv_btnm.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_ddlist.h" +#include "lv_objx/lv_roller.h" +#include "lv_objx/lv_ta.h" +#include "lv_objx/lv_canvas.h" +#include "lv_objx/lv_win.h" +#include "lv_objx/lv_tabview.h" +#include "lv_objx/lv_tileview.h" +#include "lv_objx/lv_mbox.h" +#include "lv_objx/lv_gauge.h" +#include "lv_objx/lv_lmeter.h" +#include "lv_objx/lv_sw.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_arc.h" +#include "lv_objx/lv_preload.h" +#include "lv_objx/lv_calendar.h" +#include "lv_objx/lv_spinbox.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} +#endif + +#endif /*LVGL_H*/ diff --git a/ariane/src/bdk/libs/lvgl/lvgl.mk b/ariane/src/bdk/libs/lvgl/lvgl.mk new file mode 100644 index 0000000..a4f3237 --- /dev/null +++ b/ariane/src/bdk/libs/lvgl/lvgl.mk @@ -0,0 +1,8 @@ +include $(LVGL_DIR)/lvgl/lv_core/lv_core.mk +include $(LVGL_DIR)/lvgl/lv_hal/lv_hal.mk +include $(LVGL_DIR)/lvgl/lv_objx/lv_objx.mk +include $(LVGL_DIR)/lvgl/lv_fonts/lv_fonts.mk +include $(LVGL_DIR)/lvgl/lv_misc/lv_misc.mk +include $(LVGL_DIR)/lvgl/lv_themes/lv_themes.mk +include $(LVGL_DIR)/lvgl/lv_draw/lv_draw.mk + diff --git a/ariane/src/bdk/mem/emc.h b/ariane/src/bdk/mem/emc.h new file mode 100644 index 0000000..9be6fe8 --- /dev/null +++ b/ariane/src/bdk/mem/emc.h @@ -0,0 +1,693 @@ +/* + * arch/arm/mach-tegra/tegra21_emc.h + * + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2020, CTCaer. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _EMC_H_ +#define _EMC_H_ + +#define EMC_DBG 0x8 +#define EMC_CFG 0xC +#define EMC_CONFIG_SAMPLE_DELAY 0x5f0 +#define EMC_CFG_UPDATE 0x5f4 +#define EMC_ADR_CFG 0x10 +#define EMC_REFCTRL 0x20 +#define EMC_PIN 0x24 +#define EMC_TIMING_CONTROL 0x28 +#define EMC_RC 0x2c +#define EMC_RFC 0x30 +#define EMC_RFCPB 0x590 +#define EMC_RAS 0x34 +#define EMC_RP 0x38 +#define EMC_R2W 0x3c +#define EMC_W2R 0x40 +#define EMC_R2P 0x44 +#define EMC_W2P 0x48 +#define EMC_CCDMW 0x5c0 +#define EMC_RD_RCD 0x4c +#define EMC_WR_RCD 0x50 +#define EMC_RRD 0x54 +#define EMC_REXT 0x58 +#define EMC_WDV 0x5c +#define EMC_QUSE 0x60 +#define EMC_QRST 0x64 +#define EMC_ISSUE_QRST 0x428 +#define EMC_QSAFE 0x68 +#define EMC_RDV 0x6c +#define EMC_REFRESH 0x70 +#define EMC_BURST_REFRESH_NUM 0x74 +#define EMC_PDEX2WR 0x78 +#define EMC_PDEX2RD 0x7c +#define EMC_PDEX2CKE 0x118 +#define EMC_PCHG2PDEN 0x80 +#define EMC_ACT2PDEN 0x84 +#define EMC_AR2PDEN 0x88 +#define EMC_RW2PDEN 0x8c +#define EMC_CKE2PDEN 0x11c +#define EMC_TXSR 0x90 +#define EMC_TCKE 0x94 +#define EMC_TFAW 0x98 +#define EMC_TRPAB 0x9c +#define EMC_TCLKSTABLE 0xa0 +#define EMC_TCLKSTOP 0xa4 +#define EMC_TREFBW 0xa8 +#define EMC_TPPD 0xac +#define EMC_PDEX2MRR 0xb4 +#define EMC_ODT_WRITE 0xb0 +#define EMC_WEXT 0xb8 +#define EMC_RFC_SLR 0xc0 +#define EMC_MRS_WAIT_CNT2 0xc4 +#define EMC_MRS_WAIT_CNT 0xc8 +#define EMC_MRS 0xcc +#define EMC_EMRS 0xd0 +#define EMC_REF 0xd4 +#define EMC_PRE 0xd8 +#define EMC_NOP 0xdc +#define EMC_SELF_REF 0xe0 +#define EMC_DPD 0xe4 +#define EMC_MRW 0xe8 +#define EMC_MRR 0xec +#define EMC_CMDQ 0xf0 +#define EMC_MC2EMCQ 0xf4 +#define EMC_FBIO_SPARE 0x100 +#define EMC_FBIO_CFG5 0x104 +#define EMC_CFG_RSV 0x120 +#define EMC_ACPD_CONTROL 0x124 +#define EMC_MPC 0x128 +#define EMC_EMRS2 0x12c +#define EMC_EMRS3 0x130 +#define EMC_MRW2 0x134 +#define EMC_MRW3 0x138 +#define EMC_MRW4 0x13c +#define EMC_MRW5 0x4a0 +#define EMC_MRW6 0x4a4 +#define EMC_MRW7 0x4a8 +#define EMC_MRW8 0x4ac +#define EMC_MRW9 0x4b0 +#define EMC_MRW10 0x4b4 +#define EMC_MRW11 0x4b8 +#define EMC_MRW12 0x4bc +#define EMC_MRW13 0x4c0 +#define EMC_MRW14 0x4c4 +#define EMC_MRW15 0x4d0 +#define EMC_CFG_SYNC 0x4d4 +#define EMC_CLKEN_OVERRIDE 0x140 +#define EMC_R2R 0x144 +#define EMC_W2W 0x148 +#define EMC_EINPUT 0x14c +#define EMC_EINPUT_DURATION 0x150 +#define EMC_PUTERM_EXTRA 0x154 +#define EMC_TCKESR 0x158 +#define EMC_TPD 0x15c +#define EMC_STAT_CONTROL 0x160 +#define EMC_STAT_STATUS 0x164 +#define EMC_STAT_DRAM_CLOCK_LIMIT_LO 0x19c +#define EMC_STAT_DRAM_CLOCK_LIMIT_HI 0x1a0 +#define EMC_STAT_DRAM_CLOCKS_LO 0x1a4 +#define EMC_STAT_DRAM_CLOCKS_HI 0x1a8 +#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO 0x1ac +#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI 0x1b0 +#define EMC_STAT_DRAM_DEV0_READ_CNT_LO 0x1b4 +#define EMC_STAT_DRAM_DEV0_READ_CNT_HI 0x1b8 +#define EMC_STAT_DRAM_DEV0_READ8_CNT_LO 0x1bc +#define EMC_STAT_DRAM_DEV0_READ8_CNT_HI 0x1c0 +#define EMC_STAT_DRAM_DEV0_WRITE_CNT_LO 0x1c4 +#define EMC_STAT_DRAM_DEV0_WRITE_CNT_HI 0x1c8 +#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO 0x1cc +#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI 0x1d0 +#define EMC_STAT_DRAM_DEV0_REF_CNT_LO 0x1d4 +#define EMC_STAT_DRAM_DEV0_REF_CNT_HI 0x1d8 +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1dc +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x1e0 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x1e4 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x1e8 +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x1ec +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x1f0 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x1f4 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x1f8 +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x1fc +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x200 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x204 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x208 +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x20c +#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x210 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x214 +#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x218 +#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO 0x21c +#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI 0x220 +#define EMC_STAT_DRAM_DEV0_DSR 0x224 +#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO 0x228 +#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI 0x22c +#define EMC_STAT_DRAM_DEV1_READ_CNT_LO 0x230 +#define EMC_STAT_DRAM_DEV1_READ_CNT_HI 0x234 +#define EMC_STAT_DRAM_DEV1_READ8_CNT_LO 0x238 +#define EMC_STAT_DRAM_DEV1_READ8_CNT_HI 0x23c +#define EMC_STAT_DRAM_DEV1_WRITE_CNT_LO 0x240 +#define EMC_STAT_DRAM_DEV1_WRITE_CNT_HI 0x244 +#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO 0x248 +#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI 0x24c +#define EMC_STAT_DRAM_DEV1_REF_CNT_LO 0x250 +#define EMC_STAT_DRAM_DEV1_REF_CNT_HI 0x254 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x258 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x25c +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0x260 +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0x264 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x268 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x26c +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0x270 +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0x274 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x278 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x27c +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x280 +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x284 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x288 +#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x28c +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x290 +#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x294 +#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO 0x298 +#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI 0x29c +#define EMC_STAT_DRAM_DEV1_DSR 0x2a0 +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc8c +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0xc90 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 0xc94 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 0xc98 +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0xc9c +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0xca0 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 0xca4 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 0xca8 +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0xcac +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0xcb0 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0xcb4 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0xcb8 +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0xcbc +#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc0 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0xcc4 +#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0xcc8 +#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO 0xccc +#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI 0xcd0 +#define EMC_STAT_DRAM_IO_DSR 0xcd4 +#define EMC_AUTO_CAL_CONFIG 0x2a4 +#define EMC_AUTO_CAL_CONFIG2 0x458 +#define EMC_AUTO_CAL_CONFIG3 0x45c +#define EMC_AUTO_CAL_CONFIG4 0x5b0 +#define EMC_AUTO_CAL_CONFIG5 0x5b4 +#define EMC_AUTO_CAL_CONFIG6 0x5cc +#define EMC_AUTO_CAL_CONFIG7 0x574 +#define EMC_AUTO_CAL_CONFIG8 0x2dc +#define EMC_AUTO_CAL_VREF_SEL_0 0x2f8 +#define EMC_AUTO_CAL_VREF_SEL_1 0x300 +#define EMC_AUTO_CAL_INTERVAL 0x2a8 +#define EMC_AUTO_CAL_STATUS 0x2ac +#define EMC_AUTO_CAL_STATUS2 0x3d4 +#define EMC_AUTO_CAL_CHANNEL 0x464 +#define EMC_PMACRO_RX_TERM 0xc48 +#define EMC_PMACRO_DQ_TX_DRV 0xc70 +#define EMC_PMACRO_CA_TX_DRV 0xc74 +#define EMC_PMACRO_CMD_TX_DRV 0xc4c +#define EMC_PMACRO_AUTOCAL_CFG_0 0x700 +#define EMC_PMACRO_AUTOCAL_CFG_1 0x704 +#define EMC_PMACRO_AUTOCAL_CFG_2 0x708 +#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xc78 +#define EMC_PMACRO_ZCTRL 0xc44 +#define EMC_XM2COMPPADCTRL 0x30c +#define EMC_XM2COMPPADCTRL2 0x578 +#define EMC_XM2COMPPADCTRL3 0x2f4 +#define EMC_COMP_PAD_SW_CTRL 0x57c +#define EMC_REQ_CTRL 0x2b0 +#define EMC_EMC_STATUS 0x2b4 +#define EMC_STATUS_MRR_DIVLD (1 << 20) +#define EMC_CFG_2 0x2b8 +#define EMC_CFG_DIG_DLL 0x2bc +#define EMC_CFG_DIG_DLL_PERIOD 0x2c0 +#define EMC_DIG_DLL_STATUS 0x2c4 +#define EMC_CFG_DIG_DLL_1 0x2c8 +#define EMC_RDV_MASK 0x2cc +#define EMC_WDV_MASK 0x2d0 +#define EMC_RDV_EARLY_MASK 0x2d4 +#define EMC_RDV_EARLY 0x2d8 +#define EMC_WDV_CHK 0x4e0 +#define EMC_ZCAL_INTERVAL 0x2e0 +#define EMC_ZCAL_WAIT_CNT 0x2e4 +#define EMC_ZCAL_MRW_CMD 0x2e8 +#define EMC_ZQ_CAL 0x2ec +#define EMC_SCRATCH0 0x324 +#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE 0x3c8 +#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3cc +#define EMC_UNSTALL_RW_AFTER_CLKCHANGE 0x3d0 +#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4d8 +#define EMC_SEL_DPD_CTRL 0x3d8 +#define EMC_FDPD_CTRL_DQ 0x310 +#define EMC_FDPD_CTRL_CMD 0x314 +#define EMC_PRE_REFRESH_REQ_CNT 0x3dc +#define EMC_REFCTRL2 0x580 +#define EMC_FBIO_CFG7 0x584 +#define EMC_DATA_BRLSHFT_0 0x588 +#define EMC_DATA_BRLSHFT_1 0x58c +#define EMC_DQS_BRLSHFT_0 0x594 +#define EMC_DQS_BRLSHFT_1 0x598 +#define EMC_CMD_BRLSHFT_0 0x59c +#define EMC_CMD_BRLSHFT_1 0x5a0 +#define EMC_CMD_BRLSHFT_2 0x5a4 +#define EMC_CMD_BRLSHFT_3 0x5a8 +#define EMC_QUSE_BRLSHFT_0 0x5ac +#define EMC_QUSE_BRLSHFT_1 0x5b8 +#define EMC_QUSE_BRLSHFT_2 0x5bc +#define EMC_QUSE_BRLSHFT_3 0x5c4 +#define EMC_FBIO_CFG8 0x5c8 +#define EMC_CMD_MAPPING_CMD0_0 0x380 +#define EMC_CMD_MAPPING_CMD0_1 0x384 +#define EMC_CMD_MAPPING_CMD0_2 0x388 +#define EMC_CMD_MAPPING_CMD1_0 0x38c +#define EMC_CMD_MAPPING_CMD1_1 0x390 +#define EMC_CMD_MAPPING_CMD1_2 0x394 +#define EMC_CMD_MAPPING_CMD2_0 0x398 +#define EMC_CMD_MAPPING_CMD2_1 0x39c +#define EMC_CMD_MAPPING_CMD2_2 0x3a0 +#define EMC_CMD_MAPPING_CMD3_0 0x3a4 +#define EMC_CMD_MAPPING_CMD3_1 0x3a8 +#define EMC_CMD_MAPPING_CMD3_2 0x3ac +#define EMC_CMD_MAPPING_BYTE 0x3b0 +#define EMC_DYN_SELF_REF_CONTROL 0x3e0 +#define EMC_TXSRDLL 0x3e4 +#define EMC_CCFIFO_ADDR 0x3e8 +#define EMC_CCFIFO_DATA 0x3ec +#define EMC_CCFIFO_STATUS 0x3f0 +#define EMC_SWIZZLE_RANK0_BYTE0 0x404 +#define EMC_SWIZZLE_RANK0_BYTE1 0x408 +#define EMC_SWIZZLE_RANK0_BYTE2 0x40c +#define EMC_SWIZZLE_RANK0_BYTE3 0x410 +#define EMC_SWIZZLE_RANK1_BYTE0 0x418 +#define EMC_SWIZZLE_RANK1_BYTE1 0x41c +#define EMC_SWIZZLE_RANK1_BYTE2 0x420 +#define EMC_SWIZZLE_RANK1_BYTE3 0x424 +#define EMC_TR_TIMING_0 0x3b4 +#define EMC_TR_CTRL_0 0x3b8 +#define EMC_TR_CTRL_1 0x3bc +#define EMC_TR_DVFS 0x460 +#define EMC_SWITCH_BACK_CTRL 0x3c0 +#define EMC_TR_RDV 0x3c4 +#define EMC_TR_QPOP 0x3f4 +#define EMC_TR_RDV_MASK 0x3f8 +#define EMC_TR_QSAFE 0x3fc +#define EMC_TR_QRST 0x400 +#define EMC_IBDLY 0x468 +#define EMC_OBDLY 0x46c +#define EMC_TXDSRVTTGEN 0x480 +#define EMC_WE_DURATION 0x48c +#define EMC_WS_DURATION 0x490 +#define EMC_WEV 0x494 +#define EMC_WSV 0x498 +#define EMC_CFG_3 0x49c +#define EMC_CFG_PIPE_2 0x554 +#define EMC_CFG_PIPE_CLK 0x558 +#define EMC_CFG_PIPE_1 0x55c +#define EMC_CFG_PIPE 0x560 +#define EMC_QPOP 0x564 +#define EMC_QUSE_WIDTH 0x568 +#define EMC_PUTERM_WIDTH 0x56c +#define EMC_PROTOBIST_CONFIG_ADR_1 0x5d0 +#define EMC_PROTOBIST_CONFIG_ADR_2 0x5d4 +#define EMC_PROTOBIST_MISC 0x5d8 +#define EMC_PROTOBIST_WDATA_LOWER 0x5dc +#define EMC_PROTOBIST_WDATA_UPPER 0x5e0 +#define EMC_PROTOBIST_RDATA 0x5ec +#define EMC_DLL_CFG_0 0x5e4 +#define EMC_DLL_CFG_1 0x5e8 +#define EMC_TRAINING_CMD 0xe00 +#define EMC_TRAINING_CTRL 0xe04 +#define EMC_TRAINING_STATUS 0xe08 +#define EMC_TRAINING_QUSE_CORS_CTRL 0xe0c +#define EMC_TRAINING_QUSE_FINE_CTRL 0xe10 +#define EMC_TRAINING_QUSE_CTRL_MISC 0xe14 +#define EMC_TRAINING_WRITE_FINE_CTRL 0xe18 +#define EMC_TRAINING_WRITE_CTRL_MISC 0xe1c +#define EMC_TRAINING_WRITE_VREF_CTRL 0xe20 +#define EMC_TRAINING_READ_FINE_CTRL 0xe24 +#define EMC_TRAINING_READ_CTRL_MISC 0xe28 +#define EMC_TRAINING_READ_VREF_CTRL 0xe2c +#define EMC_TRAINING_CA_FINE_CTRL 0xe30 +#define EMC_TRAINING_CA_CTRL_MISC 0xe34 +#define EMC_TRAINING_CA_CTRL_MISC1 0xe38 +#define EMC_TRAINING_CA_VREF_CTRL 0xe3c +#define EMC_TRAINING_CA_TADR_CTRL 0xe40 +#define EMC_TRAINING_SETTLE 0xe44 +#define EMC_TRAINING_DEBUG_CTRL 0xe48 +#define EMC_TRAINING_DEBUG_DQ0 0xe4c +#define EMC_TRAINING_DEBUG_DQ1 0xe50 +#define EMC_TRAINING_DEBUG_DQ2 0xe54 +#define EMC_TRAINING_DEBUG_DQ3 0xe58 +#define EMC_TRAINING_MPC 0xe5c +#define EMC_TRAINING_PATRAM_CTRL 0xe60 +#define EMC_TRAINING_PATRAM_DQ 0xe64 +#define EMC_TRAINING_PATRAM_DMI 0xe68 +#define EMC_TRAINING_VREF_SETTLE 0xe6c +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0 0xe70 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1 0xe74 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2 0xe78 +#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3 0xe7c +#define EMC_TRAINING_RW_EYE_CENTER_IB_MISC 0xe80 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0 0xe84 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1 0xe88 +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2 0xe8c +#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3 0xe90 +#define EMC_TRAINING_RW_EYE_CENTER_OB_MISC 0xe94 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE0 0xe98 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE1 0xe9c +#define EMC_TRAINING_RW_OFFSET_IB_BYTE2 0xea0 +#define EMC_TRAINING_RW_OFFSET_IB_BYTE3 0xea4 +#define EMC_TRAINING_RW_OFFSET_IB_MISC 0xea8 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE0 0xeac +#define EMC_TRAINING_RW_OFFSET_OB_BYTE1 0xeb0 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE2 0xeb4 +#define EMC_TRAINING_RW_OFFSET_OB_BYTE3 0xeb8 +#define EMC_TRAINING_RW_OFFSET_OB_MISC 0xebc +#define EMC_TRAINING_OPT_CA_VREF 0xec0 +#define EMC_TRAINING_OPT_DQ_OB_VREF 0xec4 +#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK0 0xec8 +#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK1 0xecc +#define EMC_TRAINING_QUSE_VREF_CTRL 0xed0 +#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xed4 +#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xed8 +#define EMC_TRAINING_DRAMC_TIMING 0xedc +#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 +#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 +#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 +#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60c +#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610 +#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614 +#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620 +#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624 +#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628 +#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62c +#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630 +#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64c +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66c +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670 +#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68c +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6a0 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6a4 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6a8 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6ac +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6b0 +#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6b4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6c0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6c4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6c8 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6cc +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4 0x6d0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5 0x6d4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6e0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6e4 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6e8 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6ec +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4 0x6f0 +#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5 0x6f4 +#define EMC_PMACRO_TX_PWRD_0 0x720 +#define EMC_PMACRO_TX_PWRD_1 0x724 +#define EMC_PMACRO_TX_PWRD_2 0x728 +#define EMC_PMACRO_TX_PWRD_3 0x72c +#define EMC_PMACRO_TX_PWRD_4 0x730 +#define EMC_PMACRO_TX_PWRD_5 0x734 +#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740 +#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744 +#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74c +#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748 +#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750 +#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754 +#define EMC_PMACRO_DDLL_BYPASS 0x760 +#define EMC_PMACRO_DDLL_PWRD_0 0x770 +#define EMC_PMACRO_DDLL_PWRD_1 0x774 +#define EMC_PMACRO_DDLL_PWRD_2 0x778 +#define EMC_PMACRO_CMD_CTRL_0 0x780 +#define EMC_PMACRO_CMD_CTRL_1 0x784 +#define EMC_PMACRO_CMD_CTRL_2 0x788 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8a0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8a4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8a8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8ac +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8b0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8b4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8b8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8bc +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99c +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9a0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9a4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9a8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9ac +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9b0 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9b4 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9b8 +#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9bc +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xa00 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xa04 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xa08 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xa10 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xa14 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xa18 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xa20 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xa24 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xa28 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xa30 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xa34 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xa38 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xa40 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xa44 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xa48 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xa50 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xa54 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xa58 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xa60 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xa64 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xa68 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xa70 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xa74 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xa78 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0 0xa80 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1 0xa84 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2 0xa88 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0 0xa90 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1 0xa94 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2 0xa98 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0 0xaa0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1 0xaa4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2 0xaa8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0 0xab0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1 0xab4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2 0xab8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xb00 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xb04 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xb08 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xb10 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xb14 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xb18 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xb20 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xb24 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xb28 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xb30 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xb34 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xb38 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xb40 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xb44 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xb48 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xb50 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xb54 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xb58 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xb60 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xb64 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xb68 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xb70 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xb74 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xb78 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0 0xb80 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1 0xb84 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2 0xb88 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0 0xb90 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1 0xb94 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2 0xb98 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0 0xba0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1 0xba4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2 0xba8 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0 0xbb0 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1 0xbb4 +#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2 0xbb8 +#define EMC_PMACRO_IB_VREF_DQ_0 0xbe0 +#define EMC_PMACRO_IB_VREF_DQ_1 0xbe4 +#define EMC_PMACRO_IB_VREF_DQ_2 0xbe8 +#define EMC_PMACRO_IB_VREF_DQS_0 0xbf0 +#define EMC_PMACRO_IB_VREF_DQS_1 0xbf4 +#define EMC_PMACRO_IB_VREF_DQS_2 0xbf8 +#define EMC_PMACRO_IB_RXRT 0xcf4 +#define EMC_PMACRO_DDLL_LONG_CMD_0 0xc00 +#define EMC_PMACRO_DDLL_LONG_CMD_1 0xc04 +#define EMC_PMACRO_DDLL_LONG_CMD_2 0xc08 +#define EMC_PMACRO_DDLL_LONG_CMD_3 0xc0c +#define EMC_PMACRO_DDLL_LONG_CMD_4 0xc10 +#define EMC_PMACRO_DDLL_LONG_CMD_5 0xc14 +#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xc20 +#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xc24 +#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xc28 +#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xc30 +#define EMC_PMACRO_VTTGEN_CTRL_0 0xc34 +#define EMC_PMACRO_VTTGEN_CTRL_1 0xc38 +#define EMC_PMACRO_VTTGEN_CTRL_2 0xcf0 +#define EMC_PMACRO_BG_BIAS_CTRL_0 0xc3c +#define EMC_PMACRO_PAD_CFG_CTRL 0xc40 +#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xc50 +#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xc54 +#define EMC_PMACRO_CMD_RX_TERM_MODE 0xc58 +#define EMC_PMACRO_DATA_RX_TERM_MODE 0xc5c +#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xc60 +#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xc64 +#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xc68 +#define EMC_PMACRO_BRICK_MAPPING_0 0xc80 +#define EMC_PMACRO_BRICK_MAPPING_1 0xc84 +#define EMC_PMACRO_BRICK_MAPPING_2 0xc88 +#define EMC_PMACRO_DDLLCAL_CAL 0xce0 +#define EMC_PMACRO_DDLL_OFFSET 0xce4 +#define EMC_PMACRO_DDLL_PERIODIC_OFFSET 0xce8 +#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330 +#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334 +#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318 +#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31c +#define EMC_PMACRO_TRAINING_CTRL_0 0xcf8 +#define EMC_PMACRO_TRAINING_CTRL_1 0xcfc +#define EMC_PMC_SCRATCH1 0x440 +#define EMC_PMC_SCRATCH2 0x444 +#define EMC_PMC_SCRATCH3 0x448 + +#define EMC_STATUS_UPDATE_TIMEOUT 1000 + +typedef enum _emc_mr_t +{ + MR5_MAN_ID = 5, + MR6_REV_ID1 = 6, + MR7_REV_ID2 = 7, + MR8_DENSITY = 8, +} emc_mr_t; + +enum +{ + EMC_CHAN0 = 0, + EMC_CHAN1 = 1 +}; + +typedef struct _emc_mr_data_t +{ + u8 dev0_ch0; + u8 dev0_ch1; + u8 dev1_ch0; + u8 dev1_ch1; +} emc_mr_data_t; + +#endif diff --git a/ariane/src/bdk/mem/heap.c b/ariane/src/bdk/mem/heap.c new file mode 100644 index 0000000..d249140 --- /dev/null +++ b/ariane/src/bdk/mem/heap.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "heap.h" +#include + +static void _heap_create(heap_t *heap, u32 start) +{ + heap->start = start; + heap->first = NULL; +} + +// Node info is before node address. +static u32 _heap_alloc(heap_t *heap, u32 size) +{ + hnode_t *node, *new_node; + + // Align to cache line size. + size = ALIGN(size, sizeof(hnode_t)); + + if (!heap->first) + { + node = (hnode_t *)heap->start; + node->used = 1; + node->size = size; + node->prev = NULL; + node->next = NULL; + heap->first = node; + + return (u32)node + sizeof(hnode_t); + } + + node = heap->first; + while (true) + { + // Check if there's available unused node. + if (!node->used && (size <= node->size)) + { + // Size and offset of the new unused node. + u32 new_size = node->size - size; + new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size); + + // If there's aligned unused space from the old node, + // create a new one and set the leftover size. + if (new_size >= (sizeof(hnode_t) << 2)) + { + new_node->size = new_size - sizeof(hnode_t); + new_node->used = 0; + new_node->next = node->next; + + // Check that we are not on first node. + if (new_node->next) + new_node->next->prev = new_node; + + new_node->prev = node; + node->next = new_node; + } + else // Unused node size is just enough. + size += new_size; + + node->size = size; + node->used = 1; + + return (u32)node + sizeof(hnode_t); + } + + // No unused node found, try the next one. + if (node->next) + node = node->next; + else + break; + } + + // No unused node found, create a new one. + new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); + new_node->used = 1; + new_node->size = size; + new_node->prev = node; + new_node->next = NULL; + node->next = new_node; + + return (u32)new_node + sizeof(hnode_t); +} + +static void _heap_free(heap_t *heap, u32 addr) +{ + hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); + node->used = 0; + node = heap->first; + while (node) + { + if (!node->used) + { + if (node->prev && !node->prev->used) + { + node->prev->size += node->size + sizeof(hnode_t); + node->prev->next = node->next; + + if (node->next) + node->next->prev = node->prev; + } + } + node = node->next; + } +} + +heap_t _heap; + +void heap_init(u32 base) +{ + _heap_create(&_heap, base); +} + +void heap_copy(heap_t *heap) +{ + memcpy(&_heap, heap, sizeof(heap_t)); +} + +void *malloc(u32 size) +{ + return (void *)_heap_alloc(&_heap, size); +} + +void *calloc(u32 num, u32 size) +{ + void *res = (void *)_heap_alloc(&_heap, num * size); + memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size. + return res; +} + +void free(void *buf) +{ + if ((u32)buf >= _heap.start) + _heap_free(&_heap, (u32)buf); +} + +void heap_monitor(heap_monitor_t *mon, bool print_node_stats) +{ + u32 count = 0; + memset(mon, 0, sizeof(heap_monitor_t)); + + hnode_t *node = _heap.first; + while (true) + { + if (node->used) + mon->used += node->size + sizeof(hnode_t); + else + mon->total += node->size + sizeof(hnode_t); + + if (print_node_stats) + gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n", + count, node->used, (u32)node + sizeof(hnode_t), node->size); + + count++; + + if (node->next) + node = node->next; + else + break; + } + mon->total += mon->used; +} diff --git a/ariane/src/bdk/mem/heap.h b/ariane/src/bdk/mem/heap.h new file mode 100644 index 0000000..811f13d --- /dev/null +++ b/ariane/src/bdk/mem/heap.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _HEAP_H_ +#define _HEAP_H_ + +#include + +typedef struct _hnode +{ + int used; + u32 size; + struct _hnode *prev; + struct _hnode *next; + u32 align[4]; // Align to arch cache line size. +} hnode_t; + +typedef struct _heap +{ + u32 start; + hnode_t *first; +} heap_t; + +typedef struct +{ + u32 total; + u32 used; +} heap_monitor_t; + +void heap_init(u32 base); +void heap_copy(heap_t *heap); +void *malloc(u32 size); +void *calloc(u32 num, u32 size); +void free(void *buf); +void heap_monitor(heap_monitor_t *mon, bool print_node_stats); + +#endif diff --git a/ariane/src/bdk/mem/mc.c b/ariane/src/bdk/mem/mc.c new file mode 100644 index 0000000..8a0da1a --- /dev/null +++ b/ariane/src/bdk/mem/mc.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock) +{ + MC(MC_SEC_CARVEOUT_BOM) = bom; + MC(MC_SEC_CARVEOUT_SIZE_MB) = size1mb; + if (lock) + MC(MC_SEC_CARVEOUT_REG_CTRL) = 1; +} + +void mc_config_carveout() +{ + *(vu32 *)0x8005FFFC = 0xC0EDBBCC; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 1; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0; + MC(MC_VIDEO_PROTECT_BOM) = 0; + MC(MC_VIDEO_PROTECT_SIZE_MB) = 0; + MC(MC_VIDEO_PROTECT_REG_CTRL) = 1; + + // Configure TSEC carveout @ 0x90000000, 1MB. + //mc_config_tsec_carveout(0x90000000, 1, false); + mc_config_tsec_carveout(0, 0, true); + + MC(MC_MTS_CARVEOUT_BOM) = 0; + MC(MC_MTS_CARVEOUT_SIZE_MB) = 0; + MC(MC_MTS_CARVEOUT_ADR_HI) = 0; + MC(MC_MTS_CARVEOUT_REG_CTRL) = 1; + + MC(MC_SECURITY_CARVEOUT1_BOM) = 0; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006; + + MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000; + MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E; + + MC(MC_SECURITY_CARVEOUT3_BOM) = 0; + MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0x3000000; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0x300; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E; + + MC(MC_SECURITY_CARVEOUT4_BOM) = 0; + MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F; + + MC(MC_SECURITY_CARVEOUT5_BOM) = 0; + MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F; +} + +void mc_enable_ahb_redirect() +{ + // Enable ARC_CLK_OVR_ON. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000; + //MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE; + MC(MC_IRAM_BOM) = 0x40000000; + MC(MC_IRAM_TOM) = 0x4003F000; +} + +void mc_disable_ahb_redirect() +{ + MC(MC_IRAM_BOM) = 0xFFFFF000; + MC(MC_IRAM_TOM) = 0; + // Disable IRAM_CFG_WRITE_ACCESS (sticky). + //MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1; + // Disable ARC_CLK_OVR_ON. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF; +} + +void mc_enable() +{ + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; + // Enable EMC clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000; + // Enable MC clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1; + // Enable EMC DLL clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000; + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset. + usleep(5); + + //#ifdef CONFIG_ENABLE_AHB_REDIRECT + mc_disable_ahb_redirect(); + //mc_enable_ahb_redirect(); + //#endif +} diff --git a/ariane/src/bdk/mem/mc.h b/ariane/src/bdk/mem/mc.h new file mode 100644 index 0000000..1a9bc83 --- /dev/null +++ b/ariane/src/bdk/mem/mc.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MC_H_ +#define _MC_H_ + +#include +#include + +void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); +void mc_config_carveout(); +void mc_config_carveout_finalize(); +void mc_enable_ahb_redirect(); +void mc_disable_ahb_redirect(); +void mc_enable(); + +#endif diff --git a/ariane/src/bdk/mem/mc_t210.h b/ariane/src/bdk/mem/mc_t210.h new file mode 100644 index 0000000..87fe2ca --- /dev/null +++ b/ariane/src/bdk/mem/mc_t210.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2014, NVIDIA Corporation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MC_T210_H_ +#define _MC_T210_H_ + +#define MC_INTSTATUS 0x0 +#define MC_INTMASK 0x4 +#define MC_ERR_STATUS 0x8 +#define MC_ERR_ADR 0xc +#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0 +#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4 +#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8 +#define MC_PCFIFO_CLIENT_CONFIG3 0xddc +#define MC_PCFIFO_CLIENT_CONFIG4 0xde0 +#define MC_EMEM_CFG 0x50 +#define MC_EMEM_ADR_CFG 0x54 +#define MC_EMEM_ADR_CFG_DEV0 0x58 +#define MC_EMEM_ADR_CFG_DEV1 0x5c +#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60 +#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64 +#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68 +#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c +#define MC_SECURITY_CFG0 0x70 +#define MC_SECURITY_CFG1 0x74 +#define MC_SECURITY_CFG3 0x9bc +#define MC_SECURITY_RSV 0x7c +#define MC_EMEM_ARB_CFG 0x90 +#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 +#define MC_EMEM_ARB_TIMING_RCD 0x98 +#define MC_EMEM_ARB_TIMING_RP 0x9c +#define MC_EMEM_ARB_TIMING_RC 0xa0 +#define MC_EMEM_ARB_TIMING_RAS 0xa4 +#define MC_EMEM_ARB_TIMING_FAW 0xa8 +#define MC_EMEM_ARB_TIMING_RRD 0xac +#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 +#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 +#define MC_EMEM_ARB_TIMING_R2R 0xb8 +#define MC_EMEM_ARB_TIMING_W2W 0xbc +#define MC_EMEM_ARB_TIMING_R2W 0xc0 +#define MC_EMEM_ARB_TIMING_W2R 0xc4 +#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0 +#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4 +#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0 +#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4 +#define MC_EMEM_ARB_DA_TURNS 0xd0 +#define MC_EMEM_ARB_DA_COVERS 0xd4 +#define MC_EMEM_ARB_MISC0 0xd8 +#define MC_EMEM_ARB_MISC1 0xdc +#define MC_EMEM_ARB_MISC2 0xc8 +#define MC_EMEM_ARB_RING1_THROTTLE 0xe0 +#define MC_EMEM_ARB_RING3_THROTTLE 0xe4 +#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0 +#define MC_EMEM_ARB_OVERRIDE 0xe8 +#define MC_EMEM_ARB_RSV 0xec +#define MC_CLKEN_OVERRIDE 0xf4 +#define MC_TIMING_CONTROL_DBG 0xf8 +#define MC_TIMING_CONTROL 0xfc +#define MC_STAT_CONTROL 0x100 +#define MC_STAT_STATUS 0x104 +#define MC_STAT_EMC_CLOCK_LIMIT 0x108 +#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c +#define MC_STAT_EMC_CLOCKS 0x110 +#define MC_STAT_EMC_CLOCKS_MSBS 0x114 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c +#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0 +#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0 +#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120 +#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c +#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c +#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c +#define MC_STAT_EMC_SET0_COUNT 0x138 +#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c +#define MC_STAT_EMC_SET1_COUNT 0x178 +#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c +#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140 +#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144 +#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180 +#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184 +#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148 +#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c +#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188 +#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c +#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150 +#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190 +#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8 +#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc +#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8 +#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc +#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0 +#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0 +#define MC_CLIENT_HOTRESET_CTRL 0x200 +#define MC_CLIENT_HOTRESET_CTRL_1 0x970 +#define MC_CLIENT_HOTRESET_STATUS 0x204 +#define MC_CLIENT_HOTRESET_STATUS_1 0x974 +#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208 +#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c +#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210 +#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214 +#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94 +#define MC_EMEM_ARB_HYSTERESIS_0 0x218 +#define MC_EMEM_ARB_HYSTERESIS_1 0x21c +#define MC_EMEM_ARB_HYSTERESIS_2 0x220 +#define MC_EMEM_ARB_HYSTERESIS_3 0x224 +#define MC_EMEM_ARB_HYSTERESIS_4 0xb84 +#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0 +#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4 +#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8 +#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc +#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0 +#define MC_EMEM_ARB_DHYST_CTRL 0xbcc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec +#define MC_RESERVED_RSV 0x3fc +#define MC_DISB_EXTRA_SNAP_LEVELS 0x408 +#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4 +#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0 +#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18 +#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08 +#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10 +#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c +#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40 +#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414 +#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc +#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c +#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14 +#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0 +#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac +#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c +#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48 +#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8 +#define MC_USBX_EXTRA_SNAP_LEVELS 0x404 +#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8 +#define MC_SD_EXTRA_SNAP_LEVELS 0xa04 +#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c +#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8 +#define MC_GK_EXTRA_SNAP_LEVELS 0xa00 +#define MC_VE2_EXTRA_SNAP_LEVELS 0x410 +#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44 +#define MC_VIDEO_PROTECT_BOM 0x648 +#define MC_VIDEO_PROTECT_SIZE_MB 0x64c +#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978 +#define MC_VIDEO_PROTECT_REG_CTRL 0x650 +#define MC_ERR_VPR_STATUS 0x654 +#define MC_ERR_VPR_ADR 0x658 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590 +#define MC_IRAM_BOM 0x65c +#define MC_IRAM_TOM 0x660 +#define MC_IRAM_ADR_HI 0x980 +#define MC_IRAM_REG_CTRL 0x964 +#define MC_EMEM_CFG_ACCESS_CTRL 0x664 +#define MC_TZ_SECURITY_CTRL 0x668 +#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c +#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4 +#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc +#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8 +#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80 +#define MC_SEC_CARVEOUT_BOM 0x670 +#define MC_SEC_CARVEOUT_SIZE_MB 0x674 +#define MC_SEC_CARVEOUT_ADR_HI 0x9d4 +#define MC_SEC_CARVEOUT_REG_CTRL 0x678 +#define MC_ERR_SEC_STATUS 0x67c +#define MC_ERR_SEC_ADR 0x680 +#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684 +#define MC_STUTTER_CONTROL 0x688 +#define MC_RESERVED_RSV_1 0x958 +#define MC_DVFS_PIPE_SELECT 0x95c +#define MC_AHB_PTSA_MIN 0x4e0 +#define MC_AUD_PTSA_MIN 0x54c +#define MC_MLL_MPCORER_PTSA_RATE 0x44c +#define MC_RING2_PTSA_RATE 0x440 +#define MC_USBD_PTSA_RATE 0x530 +#define MC_USBX_PTSA_MIN 0x528 +#define MC_USBD_PTSA_MIN 0x534 +#define MC_APB_PTSA_MAX 0x4f0 +#define MC_JPG_PTSA_RATE 0x584 +#define MC_DIS_PTSA_MIN 0x420 +#define MC_AVP_PTSA_MAX 0x4fc +#define MC_AVP_PTSA_RATE 0x4f4 +#define MC_RING1_PTSA_MIN 0x480 +#define MC_DIS_PTSA_MAX 0x424 +#define MC_SD_PTSA_MAX 0x4d8 +#define MC_MSE_PTSA_RATE 0x4c4 +#define MC_VICPC_PTSA_MIN 0x558 +#define MC_PCX_PTSA_MAX 0x4b4 +#define MC_ISP_PTSA_RATE 0x4a0 +#define MC_A9AVPPC_PTSA_MIN 0x48c +#define MC_RING2_PTSA_MAX 0x448 +#define MC_AUD_PTSA_RATE 0x548 +#define MC_HOST_PTSA_MIN 0x51c +#define MC_MLL_MPCORER_PTSA_MAX 0x454 +#define MC_SD_PTSA_MIN 0x4d4 +#define MC_RING1_PTSA_RATE 0x47c +#define MC_JPG_PTSA_MIN 0x588 +#define MC_HDAPC_PTSA_MIN 0x62c +#define MC_AVP_PTSA_MIN 0x4f8 +#define MC_JPG_PTSA_MAX 0x58c +#define MC_VE_PTSA_MAX 0x43c +#define MC_DFD_PTSA_MAX 0x63c +#define MC_VICPC_PTSA_RATE 0x554 +#define MC_GK_PTSA_MAX 0x544 +#define MC_VICPC_PTSA_MAX 0x55c +#define MC_SDM_PTSA_MAX 0x624 +#define MC_SAX_PTSA_RATE 0x4b8 +#define MC_PCX_PTSA_MIN 0x4b0 +#define MC_APB_PTSA_MIN 0x4ec +#define MC_GK2_PTSA_MIN 0x614 +#define MC_PCX_PTSA_RATE 0x4ac +#define MC_RING1_PTSA_MAX 0x484 +#define MC_HDAPC_PTSA_RATE 0x628 +#define MC_MLL_MPCORER_PTSA_MIN 0x450 +#define MC_GK2_PTSA_MAX 0x618 +#define MC_AUD_PTSA_MAX 0x550 +#define MC_GK2_PTSA_RATE 0x610 +#define MC_ISP_PTSA_MAX 0x4a8 +#define MC_DISB_PTSA_RATE 0x428 +#define MC_VE2_PTSA_MAX 0x49c +#define MC_DFD_PTSA_MIN 0x638 +#define MC_FTOP_PTSA_RATE 0x50c +#define MC_A9AVPPC_PTSA_RATE 0x488 +#define MC_VE2_PTSA_MIN 0x498 +#define MC_USBX_PTSA_MAX 0x52c +#define MC_DIS_PTSA_RATE 0x41c +#define MC_USBD_PTSA_MAX 0x538 +#define MC_A9AVPPC_PTSA_MAX 0x490 +#define MC_USBX_PTSA_RATE 0x524 +#define MC_FTOP_PTSA_MAX 0x514 +#define MC_HDAPC_PTSA_MAX 0x630 +#define MC_SD_PTSA_RATE 0x4d0 +#define MC_DFD_PTSA_RATE 0x634 +#define MC_FTOP_PTSA_MIN 0x510 +#define MC_SDM_PTSA_RATE 0x61c +#define MC_AHB_PTSA_RATE 0x4dc +#define MC_SMMU_SMMU_PTSA_MAX 0x460 +#define MC_RING2_PTSA_MIN 0x444 +#define MC_SDM_PTSA_MIN 0x620 +#define MC_APB_PTSA_RATE 0x4e8 +#define MC_MSE_PTSA_MIN 0x4c8 +#define MC_HOST_PTSA_RATE 0x518 +#define MC_VE_PTSA_RATE 0x434 +#define MC_AHB_PTSA_MAX 0x4e4 +#define MC_SAX_PTSA_MIN 0x4bc +#define MC_SMMU_SMMU_PTSA_MIN 0x45c +#define MC_ISP_PTSA_MIN 0x4a4 +#define MC_HOST_PTSA_MAX 0x520 +#define MC_SAX_PTSA_MAX 0x4c0 +#define MC_VE_PTSA_MIN 0x438 +#define MC_GK_PTSA_MIN 0x540 +#define MC_MSE_PTSA_MAX 0x4cc +#define MC_DISB_PTSA_MAX 0x430 +#define MC_DISB_PTSA_MIN 0x42c +#define MC_SMMU_SMMU_PTSA_RATE 0x458 +#define MC_VE2_PTSA_RATE 0x494 +#define MC_GK_PTSA_RATE 0x53c +#define MC_PTSA_GRANT_DECREMENT 0x960 +#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4 +#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0 +#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380 +#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384 +#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc +#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8 +#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370 +#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0 +#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374 +#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8 +#define MC_LATENCY_ALLOWANCE_VIC_0 0x394 +#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8 +#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8 +#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc +#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390 +#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694 +#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348 +#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c +#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344 +#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0 +#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698 +#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec +#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0 +#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4 +#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8 +#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4 +#define MC_LATENCY_ALLOWANCE_HC_1 0x314 +#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0 +#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4 +#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c +#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec +#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320 +#define MC_LATENCY_ALLOWANCE_VI2_0 0x398 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4 +#define MC_LATENCY_ALLOWANCE_SATA_0 0x350 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690 +#define MC_LATENCY_ALLOWANCE_HC_0 0x310 +#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8 +#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac +#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4 +#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388 +#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328 +#define MC_LATENCY_ALLOWANCE_HDA_0 0x318 +#define MC_MIN_LENGTH_APE_0 0xb34 +#define MC_MIN_LENGTH_DCB_2 0x8a8 +#define MC_MIN_LENGTH_A9AVP_0 0x950 +#define MC_MIN_LENGTH_TSEC_0 0x93c +#define MC_MIN_LENGTH_DC_1 0x898 +#define MC_MIN_LENGTH_AXIAP_0 0x94c +#define MC_MIN_LENGTH_ISP2B_0 0x930 +#define MC_MIN_LENGTH_VI2_0 0x944 +#define MC_MIN_LENGTH_DCB_0 0x8a0 +#define MC_MIN_LENGTH_DCB_1 0x8a4 +#define MC_MIN_LENGTH_PPCS_1 0x8f4 +#define MC_MIN_LENGTH_NVJPG_0 0xb3c +#define MC_MIN_LENGTH_HDA_0 0x8c4 +#define MC_MIN_LENGTH_NVENC_0 0x8d4 +#define MC_MIN_LENGTH_SDMMC_0 0xb18 +#define MC_MIN_LENGTH_ISP2B_1 0x934 +#define MC_MIN_LENGTH_HC_1 0x8c0 +#define MC_MIN_LENGTH_DC_3 0xb20 +#define MC_MIN_LENGTH_AVPC_0 0x890 +#define MC_MIN_LENGTH_VIC_0 0x940 +#define MC_MIN_LENGTH_ISP2_0 0x91c +#define MC_MIN_LENGTH_HC_0 0x8bc +#define MC_MIN_LENGTH_SE_0 0xb38 +#define MC_MIN_LENGTH_NVDEC_0 0xb30 +#define MC_MIN_LENGTH_SATA_0 0x8fc +#define MC_MIN_LENGTH_DC_0 0x894 +#define MC_MIN_LENGTH_XUSB_1 0x92c +#define MC_MIN_LENGTH_DC_2 0x89c +#define MC_MIN_LENGTH_SDMMCAA_0 0xb14 +#define MC_MIN_LENGTH_GPU_0 0xb04 +#define MC_MIN_LENGTH_ETR_0 0xb44 +#define MC_MIN_LENGTH_AFI_0 0x88c +#define MC_MIN_LENGTH_PPCS_0 0x8f0 +#define MC_MIN_LENGTH_ISP2_1 0x920 +#define MC_MIN_LENGTH_XUSB_0 0x928 +#define MC_MIN_LENGTH_MPCORE_0 0x8cc +#define MC_MIN_LENGTH_TSECB_0 0xb48 +#define MC_MIN_LENGTH_SDMMCA_0 0xb10 +#define MC_MIN_LENGTH_GPU2_0 0xb40 +#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c +#define MC_MIN_LENGTH_PTC_0 0x8f8 +#define MC_EMEM_ARB_OVERRIDE_1 0x968 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988 +#define MC_EMEM_ARB_STATS_0 0x990 +#define MC_EMEM_ARB_STATS_1 0x994 +#define MC_MTS_CARVEOUT_BOM 0x9a0 +#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4 +#define MC_MTS_CARVEOUT_ADR_HI 0x9a8 +#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac +#define MC_ERR_MTS_STATUS 0x9b0 +#define MC_ERR_MTS_ADR 0x9b4 +#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00 +#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74 +#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10 +#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c +#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4 +#define MC_SECURITY_CARVEOUT2_CFG0 0xc58 +#define MC_SECURITY_CARVEOUT1_CFG0 0xc08 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68 +#define MC_SECURITY_CARVEOUT3_BOM 0xcac +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60 +#define MC_SECURITY_CARVEOUT3_CFG0 0xca8 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88 +#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64 +#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50 +#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14 +#define MC_SECURITY_CARVEOUT1_BOM 0xc0c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c +#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8 +#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60 +#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80 +#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc +#define MC_SECURITY_CARVEOUT4_BOM 0xcfc +#define MC_SECURITY_CARVEOUT5_CFG0 0xd48 +#define MC_SECURITY_CARVEOUT2_BOM 0xc5c +#define MC_SECURITY_CARVEOUT5_BOM 0xd4c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0 +#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 +#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 +#define MC_DA_CONFIG0 0x9dc + +// MC_SECURITY_CARVEOUTX_CFG0 +// Mode of LOCK_MODE. +#define PROTECT_MODE_SHIFT 0 +#define SEC_CARVEOUT_CFG_SECURE (0 << PROTECT_MODE_SHIFT0) +#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT0) +// Enables PROTECT_MODE. +#define LOCK_MODE_SHIFT 1 +#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT) +#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT) + +#define ADDRESS_TYPE_SHIFT 2 +#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT) +#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT) + +#define READ_ACCESS_LEVEL_SHIFT 3 +#define SEC_CARVEOUT_CFG_RD_ALL (1 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_UNK (2 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT) + +#define WRITE_ACCESS_LEVEL_SHIFT 7 +#define SEC_CARVEOUT_CFG_WR_ALL (1 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_UNK (2 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT) + +#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11) + +#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14 +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L0 (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L1 (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L2 (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L3 (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT) + +#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18 +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L0 (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L1 (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L2 (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) +#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L3 (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT) + +#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU (1 << 22) + +#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK (1 << 23) +#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK (1 << 24) + +#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH (1 << 25) +#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH (1 << 26) + +#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27) + +#endif diff --git a/ariane/src/bdk/mem/minerva.c b/ariane/src/bdk/mem/minerva.c new file mode 100644 index 0000000..395bd39 --- /dev/null +++ b/ariane/src/bdk/mem/minerva.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "minerva.h" + +#include +#include +#include +#include +#include +#include + +extern volatile nyx_storage_t *nyx_str; + +void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); + +u32 minerva_init() +{ + u32 curr_ram_idx = 0; + + minerva_cfg = NULL; + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + +#ifdef NYX + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; + + // Check if Minerva is already initialized. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; // Retrain if needed. + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + minerva_cfg = (void *)ep_addr; + + return 0; + } + else + { + mtc_config_t mtc_tmp; + + mtc_tmp.mtc_table = mtc_cfg->mtc_table; + mtc_tmp.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_tmp.init_done = MTC_NEW_MAGIC; + + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp); + + // Ensure that Minerva is new. + if (mtc_tmp.init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; + + // Copy Minerva context to Nyx storage. + if (minerva_cfg) + memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t)); + } +#else + memset(mtc_cfg, 0, sizeof(mtc_config_t)); + + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table; + + mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. + + u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + + // Ensure that Minerva is new. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; +#endif + + if (!minerva_cfg) + return 1; + + // Get current frequency + for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) + { + if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc) + break; + } + + mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; + mtc_cfg->rate_to = 204000; + mtc_cfg->train_mode = OP_TRAIN; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = 800000; + minerva_cfg(mtc_cfg, NULL); + mtc_cfg->rate_to = 1600000; + minerva_cfg(mtc_cfg, NULL); + + // FSP WAR. + mtc_cfg->train_mode = OP_SWITCH; + mtc_cfg->rate_to = 800000; + minerva_cfg(mtc_cfg, NULL); + + // Switch to max. + mtc_cfg->rate_to = 1600000; + minerva_cfg(mtc_cfg, NULL); + + return 0; +} + +void minerva_change_freq(minerva_freq_t freq) +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (mtc_cfg->rate_from != freq) + { + mtc_cfg->rate_to = freq; + mtc_cfg->train_mode = OP_SWITCH; + minerva_cfg(mtc_cfg, NULL); + } +} + +void minerva_periodic_training() +{ + if (!minerva_cfg) + return; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + if (mtc_cfg->rate_from == FREQ_1600) + { + mtc_cfg->train_mode = OP_PERIODIC_TRAIN; + minerva_cfg(mtc_cfg, NULL); + } +} diff --git a/ariane/src/bdk/mem/minerva.h b/ariane/src/bdk/mem/minerva.h new file mode 100644 index 0000000..ed80b95 --- /dev/null +++ b/ariane/src/bdk/mem/minerva.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FE_MINERVA_H_ +#define _FE_MINERVA_H_ + +#include "mtc_table.h" +#include + +#define MTC_INIT_MAGIC 0x3043544D +#define MTC_NEW_MAGIC 0x5243544D + +#define EMC_PERIODIC_TRAIN_MS 250 + +typedef struct +{ + s32 rate_to; + s32 rate_from; + emc_table_t *mtc_table; + u32 table_entries; + emc_table_t *current_emc_table; + u32 train_mode; + u32 sdram_id; + u32 prev_temp; + bool emc_2X_clk_src_is_pllmb; + bool fsp_for_src_freq; + bool train_ram_patterns; + bool init_done; +} mtc_config_t; + +enum train_mode_t +{ + OP_SWITCH = 0, + OP_TRAIN = 1, + OP_TRAIN_SWITCH = 2, + OP_PERIODIC_TRAIN = 3, + OP_TEMP_COMP = 4 +}; + +typedef enum +{ + FREQ_204 = 204000, + FREQ_800 = 800000, + FREQ_1600 = 1600000 +} minerva_freq_t; + +extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); +u32 minerva_init(); +void minerva_change_freq(minerva_freq_t freq); +void minerva_periodic_training(); + +#endif diff --git a/ariane/src/minerva_tc/mtc/mtc_table.h b/ariane/src/bdk/mem/mtc_table.h similarity index 99% rename from ariane/src/minerva_tc/mtc/mtc_table.h rename to ariane/src/bdk/mem/mtc_table.h index 6301ff8..e24fa81 100644 --- a/ariane/src/minerva_tc/mtc/mtc_table.h +++ b/ariane/src/bdk/mem/mtc_table.h @@ -20,9 +20,9 @@ #ifndef _MTC_TABLE_H_ #define _MTC_TABLE_H_ -#include "types.h" +#include -typedef struct +typedef struct { s32 pll_osc_in; s32 pll_out; @@ -257,7 +257,7 @@ typedef struct } burst_regs_t; -typedef struct +typedef struct { u32 burst_regs[221]; u32 burst_reg_per_ch[8]; @@ -266,7 +266,7 @@ typedef struct u32 shadow_regs_rdwr_train[221]; } burst_regs_table_t; -typedef struct +typedef struct { u32 ptfv_dqsosc_movavg_c0d0u0_idx; u32 ptfv_dqsosc_movavg_c0d0u1_idx; diff --git a/ariane/src/bdk/mem/sdram.c b/ariane/src/bdk/mem/sdram.c new file mode 100644 index 0000000..e58a1eb --- /dev/null +++ b/ariane/src/bdk/mem/sdram.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 balika011 + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_SDRAM_KEEP_ALIVE + +#ifdef CONFIG_SDRAM_COMPRESS_CFG +#include +#include "sdram_config_lz.inl" +#else +#include "sdram_config.inl" +#endif + +static u32 _get_sdram_id() +{ + return ((fuse_read_odm(4) & 0xF8) >> 3); +} + +static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) +{ + bool err = true; + + for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) + { + if (emc_channel) + { + if (emc_channel != 1) + goto done; + + if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state) + { + err = false; + break; + } + } + else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state) + { + err = false; + break; + } + usleep(1); + } + +done: + return err; +} + +static void _sdram_req_mrr_data(u32 data, bool dual_channel) +{ + EMC(EMC_MRR) = data; + _sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0); + if (dual_channel) + _sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1); +} + +emc_mr_data_t sdram_read_mrx(emc_mr_t mrx) +{ + emc_mr_data_t data; + _sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0); + data.dev0_ch0 = EMC(EMC_MRR) & 0xFF; + data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); + _sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1); + data.dev1_ch0 = EMC(EMC_MRR) & 0xFF; + data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); + + return data; +} + +static void _sdram_config(const sdram_params_t *params) +{ + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; + usleep(params->pmc_io_dpd3_req_wait); + + // Disable e_dpd_vttgen. + dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; + usleep(params->pmc_io_dpd4_req_wait); + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; + usleep(params->pmc_io_dpd4_req_wait); + + PMC(APBDEV_PMC_WEAK_BIAS) = 0; + usleep(1); + + // Start clocks. + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; + CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; + +#ifdef CONFIG_SDRAM_KEEP_ALIVE + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = + (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE; +#else + u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div; + CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE; +#endif + + u32 wait_end = get_tmr_us() + 300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000)) + { + if (get_tmr_us() >= wait_end) + goto break_nosleep; + } + usleep(10); + +break_nosleep: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); + if (params->emc_clock_source_dll) + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; + if (params->clear_clock2_mc1) + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1. + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. + + // Set pad macros. + EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; + EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; + EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(10); // Ensure the regulators settle. + + // Select EMC write mux. + EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. + if (params->emc_bct_spare2) + *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. + EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; + EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; + EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; + EMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2; + EMC(EMC_CMD_MAPPING_CMD1_0) = params->emc_cmd_mapping_cmd1_0; + EMC(EMC_CMD_MAPPING_CMD1_1) = params->emc_cmd_mapping_cmd1_1; + EMC(EMC_CMD_MAPPING_CMD1_2) = params->emc_cmd_mapping_cmd1_2; + EMC(EMC_CMD_MAPPING_CMD2_0) = params->emc_cmd_mapping_cmd2_0; + EMC(EMC_CMD_MAPPING_CMD2_1) = params->emc_cmd_mapping_cmd2_1; + EMC(EMC_CMD_MAPPING_CMD2_2) = params->emc_cmd_mapping_cmd2_2; + EMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0; + EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; + EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; + EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; + + // Program brick mapping. + EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; + EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1; + EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2; + + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED; + + // This is required to do any reads from the pad macros. + EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. + EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0; + EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1; + EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2; + EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3; + // Set swizzle for Rank 1. + EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0; + EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1; + EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; + EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; + + // Patch 3 using BCT spare variables. + if (params->emc_bct_spare6) + *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Set pad controls. + EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl; + EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; + EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; + + // Program Autocal controls with shadowed register fields. + EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2; + EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; + EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; + EMC(EMC_AUTO_CAL_CONFIG5) = params->emc_auto_cal_config5; + EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6; + EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; + EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; + + EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; + EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; + EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; + EMC(EMC_PMACRO_CMD_TX_DRV) = params->emc_pmacro_cmd_tx_drive; + EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; + EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; + EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; + + EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; + EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; + EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; + + EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0; + EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; + EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; + EMC(EMC_DQS_BRLSHFT_1) = params->emc_dqs_brlshft1; + EMC(EMC_CMD_BRLSHFT_0) = params->emc_cmd_brlshft0; + EMC(EMC_CMD_BRLSHFT_1) = params->emc_cmd_brlshft1; + EMC(EMC_CMD_BRLSHFT_2) = params->emc_cmd_brlshft2; + EMC(EMC_CMD_BRLSHFT_3) = params->emc_cmd_brlshft3; + EMC(EMC_QUSE_BRLSHFT_0) = params->emc_quse_brlshft0; + EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1; + EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; + EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; + + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40; + EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; + + EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F; + EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; + EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = params->emc_pmacro_bg_bias_ctrl0; + EMC(EMC_PMACRO_DATA_PAD_RX_CTRL) = params->emc_pmacro_data_pad_rx_ctrl; + EMC(EMC_PMACRO_CMD_PAD_RX_CTRL) = params->emc_pmacro_cmd_pad_rx_ctrl; + EMC(EMC_PMACRO_DATA_PAD_TX_CTRL) = params->emc_pmacro_data_pad_tx_ctrl; + EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode; + EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; + EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + + EMC(EMC_CFG_3) = params->emc_cfg3; + EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; + EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; + EMC(EMC_PMACRO_TX_PWRD_2) = params->emc_pmacro_tx_pwrd2; + EMC(EMC_PMACRO_TX_PWRD_3) = params->emc_pmacro_tx_pwrd3; + EMC(EMC_PMACRO_TX_PWRD_4) = params->emc_pmacro_tx_pwrd4; + EMC(EMC_PMACRO_TX_PWRD_5) = params->emc_pmacro_tx_pwrd5; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_0) = params->emc_pmacro_tx_sel_clk_src0; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_1) = params->emc_pmacro_tx_sel_clk_src1; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_2) = params->emc_pmacro_tx_sel_clk_src2; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_3) = params->emc_pmacro_tx_sel_clk_src3; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_4) = params->emc_pmacro_tx_sel_clk_src4; + EMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5; + EMC(EMC_PMACRO_DDLL_BYPASS) = params->emc_pmacro_ddll_bypass; + EMC(EMC_PMACRO_DDLL_PWRD_0) = params->emc_pmacro_ddll_pwrd0; + EMC(EMC_PMACRO_DDLL_PWRD_1) = params->emc_pmacro_ddll_pwrd1; + EMC(EMC_PMACRO_DDLL_PWRD_2) = params->emc_pmacro_ddll_pwrd2; + EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0; + EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1; + EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2; + EMC(EMC_PMACRO_IB_VREF_DQ_0) = params->emc_pmacro_ib_vref_dq_0; + EMC(EMC_PMACRO_IB_VREF_DQ_1) = params->emc_pmacro_ib_vref_dq_1; + EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0; + EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1; + EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; + + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_3) = params->emc_pmacro_quse_ddll_rank0_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_4) = params->emc_pmacro_quse_ddll_rank0_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_5) = params->emc_pmacro_quse_ddll_rank0_5; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_0) = params->emc_pmacro_quse_ddll_rank1_0; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_1) = params->emc_pmacro_quse_ddll_rank1_1; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_2) = params->emc_pmacro_quse_ddll_rank1_2; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_3) = params->emc_pmacro_quse_ddll_rank1_3; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4; + EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) = params->emc_pmacro_ob_ddll_long_dq_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4) = params->emc_pmacro_ob_ddll_long_dq_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) = params->emc_pmacro_ob_ddll_long_dq_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0) = params->emc_pmacro_ob_ddll_long_dq_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1) = params->emc_pmacro_ob_ddll_long_dq_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) = params->emc_pmacro_ob_ddll_long_dq_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5; + + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ob_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4) = params->emc_pmacro_ob_ddll_long_dqs_rank0_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5) = params->emc_pmacro_ob_ddll_long_dqs_rank0_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ob_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ob_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ob_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ob_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4) = params->emc_pmacro_ob_ddll_long_dqs_rank1_4; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5) = params->emc_pmacro_ob_ddll_long_dqs_rank1_5; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ib_ddll_long_dqs_rank0_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ib_ddll_long_dqs_rank0_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ib_ddll_long_dqs_rank0_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ib_ddll_long_dqs_rank0_3; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ib_ddll_long_dqs_rank1_0; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2; + EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3; + + EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0; + EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1; + EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; + EMC(EMC_PMACRO_DDLL_LONG_CMD_3) = params->emc_pmacro_ddll_long_cmd_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_4) = params->emc_pmacro_ddll_long_cmd_4; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1; + EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2; + + // Common pad macro (cpm). + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; + + // Patch 4 using BCT spare variables. + if (params->emc_bct_spare4) + *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + // Initialize MC VPR settings. + MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; + MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi; + MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE) = params->mc_video_protect_vpr_override; + MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1; + + // Program SDRAM geometry parameters. + MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg; + MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0; + MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1; + MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask; + + // Program bank swizzling. + MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0; + MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1; + MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2; + + // Program external memory aperture (base and size). + MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). + MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom; + MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi; + MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb; + + // Program MTS carveout (base and size). + MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom; + MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi; + MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb; + + // Program the memory arbiter. + MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg; + MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req; + MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl; + MC(MC_EMEM_ARB_REFPB_BANK_CTRL) = params->emc_emem_arb_refpb_bank_ctrl; + MC(MC_EMEM_ARB_TIMING_RCD) = params->mc_emem_arb_timing_rcd; + MC(MC_EMEM_ARB_TIMING_RP) = params->mc_emem_arb_timing_rp; + MC(MC_EMEM_ARB_TIMING_RC) = params->mc_emem_arb_timing_rc; + MC(MC_EMEM_ARB_TIMING_RAS) = params->mc_emem_arb_timing_ras; + MC(MC_EMEM_ARB_TIMING_FAW) = params->mc_emem_arb_timing_faw; + MC(MC_EMEM_ARB_TIMING_RRD) = params->mc_emem_arb_timing_rrd; + MC(MC_EMEM_ARB_TIMING_RAP2PRE) = params->mc_emem_arb_timing_rap2pre; + MC(MC_EMEM_ARB_TIMING_WAP2PRE) = params->mc_emem_arb_timing_wap2pre; + MC(MC_EMEM_ARB_TIMING_R2R) = params->mc_emem_arb_timing_r2r; + MC(MC_EMEM_ARB_TIMING_W2W) = params->mc_emem_arb_timing_w2w; + MC(MC_EMEM_ARB_TIMING_CCDMW) = params->mc_emem_arb_timing_ccdmw; + MC(MC_EMEM_ARB_TIMING_R2W) = params->mc_emem_arb_timing_r2w; + MC(MC_EMEM_ARB_TIMING_W2R) = params->mc_emem_arb_timing_w2r; + MC(MC_EMEM_ARB_TIMING_RFCPB) = params->mc_emem_arb_timing_rfcpb; + MC(MC_EMEM_ARB_DA_TURNS) = params->mc_emem_arb_da_turns; + MC(MC_EMEM_ARB_DA_COVERS) = params->mc_emem_arb_da_covers; + MC(MC_EMEM_ARB_MISC0) = params->mc_emem_arb_misc0; + MC(MC_EMEM_ARB_MISC1) = params->mc_emem_arb_misc1; + MC(MC_EMEM_ARB_MISC2) = params->mc_emem_arb_misc2; + MC(MC_EMEM_ARB_RING1_THROTTLE) = params->mc_emem_arb_ring1_throttle; + MC(MC_EMEM_ARB_OVERRIDE) = params->mc_emem_arb_override; + MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1; + MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; + MC(MC_DA_CONFIG0) = params->mc_da_cfg0; + + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + + // Program second-level clock enable overrides. + MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. + MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. + EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. + EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. + EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0; + EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1; + EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2; + + EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; + EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; + + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; + usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. + if (params->emc_bct_spare8) + *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + // Program EMC timing configuration. + EMC(EMC_CFG_2) = params->emc_cfg2; + EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe; + EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1; + EMC(EMC_CFG_PIPE_2) = params->emc_cfg_pipe2; + EMC(EMC_CMDQ) = params->emc_cmd_q; + EMC(EMC_MC2EMCQ) = params->emc_mc2emc_q; + EMC(EMC_MRS_WAIT_CNT) = params->emc_mrs_wait_cnt; + EMC(EMC_MRS_WAIT_CNT2) = params->emc_mrs_wait_cnt2; + EMC(EMC_FBIO_CFG5) = params->emc_fbio_cfg5; + EMC(EMC_RC) = params->emc_rc; + EMC(EMC_RFC) = params->emc_rfc; + EMC(EMC_RFCPB) = params->emc_rfc_pb; + EMC(EMC_REFCTRL2) = params->emc_ref_ctrl2; + EMC(EMC_RFC_SLR) = params->emc_rfc_slr; + EMC(EMC_RAS) = params->emc_ras; + EMC(EMC_RP) = params->emc_rp; + EMC(EMC_TPPD) = params->emc_tppd; + EMC(EMC_R2R) = params->emc_r2r; + EMC(EMC_W2W) = params->emc_w2w; + EMC(EMC_R2W) = params->emc_r2w; + EMC(EMC_W2R) = params->emc_w2r; + EMC(EMC_R2P) = params->emc_r2p; + EMC(EMC_W2P) = params->emc_w2p; + EMC(EMC_CCDMW) = params->emc_ccdmw; + EMC(EMC_RD_RCD) = params->emc_rd_rcd; + EMC(EMC_WR_RCD) = params->emc_wr_rcd; + EMC(EMC_RRD) = params->emc_rrd; + EMC(EMC_REXT) = params->emc_rext; + EMC(EMC_WEXT) = params->emc_wext; + EMC(EMC_WDV) = params->emc_wdv; + EMC(EMC_WDV_CHK) = params->emc_wdv_chk; + EMC(EMC_WSV) = params->emc_wsv; + EMC(EMC_WEV) = params->emc_wev; + EMC(EMC_WDV_MASK) = params->emc_wdv_mask; + EMC(EMC_WS_DURATION) = params->emc_ws_duration; + EMC(EMC_WE_DURATION) = params->emc_we_duration; + EMC(EMC_QUSE) = params->emc_quse; + EMC(EMC_QUSE_WIDTH) = params->emc_quse_width; + EMC(EMC_IBDLY) = params->emc_ibdly; + EMC(EMC_OBDLY) = params->emc_obdly; + EMC(EMC_EINPUT) = params->emc_einput; + EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration; + EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra; + EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; + + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl; + EMC(EMC_DBG) = params->emc_dbg; + EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; + EMC(EMC_ISSUE_QRST) = 0; + EMC(EMC_QSAFE) = params->emc_qsafe; + EMC(EMC_RDV) = params->emc_rdv; + EMC(EMC_RDV_MASK) = params->emc_rdv_mask; + EMC(EMC_RDV_EARLY) = params->emc_rdv_early; + EMC(EMC_RDV_EARLY_MASK) = params->emc_rdv_early_mask; + EMC(EMC_QPOP) = params->emc_qpop; + EMC(EMC_REFRESH) = params->emc_refresh; + EMC(EMC_BURST_REFRESH_NUM) = params->emc_burst_refresh_num; + EMC(EMC_PRE_REFRESH_REQ_CNT) = params->emc_prerefresh_req_cnt; + EMC(EMC_PDEX2WR) = params->emc_pdex2wr; + EMC(EMC_PDEX2RD) = params->emc_pdex2rd; + EMC(EMC_PCHG2PDEN) = params->emc_pchg2pden; + EMC(EMC_ACT2PDEN) = params->emc_act2pden; + EMC(EMC_AR2PDEN) = params->emc_ar2pden; + EMC(EMC_RW2PDEN) = params->emc_rw2pden; + EMC(EMC_CKE2PDEN) = params->emc_cke2pden; + EMC(EMC_PDEX2CKE) = params->emc_pdex2che; + EMC(EMC_PDEX2MRR) = params->emc_pdex2mrr; + EMC(EMC_TXSR) = params->emc_txsr; + EMC(EMC_TXSRDLL) = params->emc_txsr_dll; + EMC(EMC_TCKE) = params->emc_tcke; + EMC(EMC_TCKESR) = params->emc_tckesr; + EMC(EMC_TPD) = params->emc_tpd; + EMC(EMC_TFAW) = params->emc_tfaw; + EMC(EMC_TRPAB) = params->emc_trpab; + EMC(EMC_TCLKSTABLE) = params->emc_tclkstable; + EMC(EMC_TCLKSTOP) = params->emc_tclkstop; + EMC(EMC_TREFBW) = params->emc_trefbw; + EMC(EMC_ODT_WRITE) = params->emc_odt_write; + EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll; + EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD; + EMC(EMC_CFG_RSV) = params->emc_cfg_rsv; + EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1; + EMC(EMC_PMC_SCRATCH2) = params->emc_pmc_scratch2; + EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; + EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; + EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; + + // Set pipe bypass enable bits before sending any DRAM commands. + EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // Patch BootROM. + if (params->boot_rom_patch_control & (1 << 31)) + { + *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + } + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; + usleep(params->pmc_io_dpd3_req_wait); + + // Set autocal interval if not configured. + if (!params->emc_auto_cal_interval) + EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200; + + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2; + + // ZQ CAL setup (not actually issuing ZQ CAL now). + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + if (params->memory_type == MEMORY_TYPE_DDR3L) + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; + if (params->memory_type == MEMORY_TYPE_LPDDR4) + { + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + } + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. + PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; + usleep(params->pmc_ddr_ctrl_wait); + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4) + { + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_extra_wait + 200); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); + } + + if (params->memory_type == MEMORY_TYPE_LPDDR4) + usleep(params->emc_pin_extra_wait + 2000); + else if (params->memory_type == MEMORY_TYPE_DDR3L) + usleep(params->emc_pin_extra_wait + 500); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); + usleep(params->emc_pin_program_wait); + + // Send NOP (trigger just needs to be non-zero). + if (params->memory_type != MEMORY_TYPE_LPDDR4) + EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; + + // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. + if (params->memory_type == MEMORY_TYPE_LPDDR2) + usleep(params->emc_pin_extra_wait + 200); + + // Init zq calibration, + if (params->memory_type == MEMORY_TYPE_LPDDR4) + { + // Patch 6 using BCT spare variables. + if (params->emc_bct_spare10) + *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. + EMC(EMC_MRW2) = params->emc_mrw2; + EMC(EMC_MRW) = params->emc_mrw1; + EMC(EMC_MRW3) = params->emc_mrw3; + EMC(EMC_MRW4) = params->emc_mrw4; + EMC(EMC_MRW6) = params->emc_mrw6; + EMC(EMC_MRW14) = params->emc_mrw14; + + EMC(EMC_MRW8) = params->emc_mrw8; + EMC(EMC_MRW12) = params->emc_mrw12; + EMC(EMC_MRW9) = params->emc_mrw9; + EMC(EMC_MRW13) = params->emc_mrw13; + + if (params->emc_zcal_warm_cold_boot_enables & 1) + { + // Issue ZQCAL start, device 0. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; + usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. + if (!(params->emc_dev_select & 2)) + { + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; + usleep(params->emc_zcal_init_wait); + EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3; + } + } + } + + // Set package and DPD pad control. + PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). + if (params->memory_type && params->memory_type <= MEMORY_TYPE_LPDDR4) + { + EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; + } + + // Patch 7 using BCT spare variables. + if (params->emc_bct_spare12) + *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + if (params->emc_extra_refresh_num) + EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; + + // Enable refresh. + EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; + + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; + EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; + EMC(EMC_CFG) = params->emc_cfg; + EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq; + EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd; + EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; + + // Write addr swizzle lock bit. + EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; + + EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. + + // Enable EMC pipe clock gating. + EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. + EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); + + // Lock carveouts per BCT cfg. + MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; + MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; + MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; + + // Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; +} + +#ifndef CONFIG_SDRAM_COMPRESS_CFG +static void _sdram_patch_model_params(u32 dramid, u32 *params) +{ + for (u32 i = 0; i < sizeof(sdram_cfg_vendor_patches) / sizeof(sdram_vendor_patch_t); i++) + if (sdram_cfg_vendor_patches[i].dramid & DRAM_ID(dramid)) + params[sdram_cfg_vendor_patches[i].addr] = sdram_cfg_vendor_patches[i].val; +} +#endif + +sdram_params_t *sdram_get_params() +{ + // Check if id is proper. + u32 dramid = _get_sdram_id(); + if (dramid > 6) + dramid = 0; + +#ifdef CONFIG_SDRAM_COMPRESS_CFG + u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; + LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); + return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid]; +#else + sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR; + memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t)); + switch (dramid) + { + case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH: + case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT: + break; + + case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN: + case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH: +#ifdef CONFIG_SDRAM_COPPER_SUPPORT + case DRAM_4GB_COPPER_SAMSUNG: + case DRAM_4GB_COPPER_HYNIX: + case DRAM_4GB_COPPER_MICRON: +#endif + _sdram_patch_model_params(dramid, (u32 *)buf); + break; + } + return buf; +#endif +} + +/* + * Function: sdram_get_params_patched + * + * This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again. + * If the boot_rom_patch_control's MSB is set, it uses it as an index to + * APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data. + * (The MSB falls out when it gets multiplied by sizeof(u32)). + * Because the bootrom does not do any boundary checks, it lets us write anywhere and anything. + * Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time. + * The first patch is not needed any more when the exploit is triggered, so we overwrite that. + * 0x10459E is the address where it returns an error when the signature is not valid. + * We change that to MOV R0, #0, so we pass the check. + * + * Note: The modulus in the header must match and validated. + */ + +sdram_params_t *sdram_get_params_patched() +{ + #define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff)) + sdram_params_t *sdram_params = sdram_get_params(); + + // Disable Warmboot signature check. + sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); + sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); +/* + // Disable SBK lock. + sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); + sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); + + // Disable bootrom read lock. + sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); + sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); + sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); + sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); +*/ + return sdram_params; +} + +void sdram_init() +{ + const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); + + // Set DRAM voltage. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); + max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); + + // VDDP Select. + PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; + usleep(params->pmc_vddp_sel_wait); + + // Set DDR pad voltage. + PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); + + // Turn on MEM IO Power. + PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power; + PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + + // Patch 1 using BCT spare variables + if (params->emc_bct_spare0) + *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; + + _sdram_config(params); +} diff --git a/ariane/src/bdk/mem/sdram.h b/ariane/src/bdk/mem/sdram.h new file mode 100644 index 0000000..620c078 --- /dev/null +++ b/ariane/src/bdk/mem/sdram.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SDRAM_H_ +#define _SDRAM_H_ + +#include +#include + +void sdram_init(); +sdram_params_t *sdram_get_params(); +sdram_params_t *sdram_get_params_patched(); +void sdram_lp0_save_params(const void *params); +emc_mr_data_t sdram_read_mrx(emc_mr_t mrx); + +#endif diff --git a/ariane/src/bdk/mem/sdram_config.inl b/ariane/src/bdk/mem/sdram_config.inl new file mode 100644 index 0000000..42e0555 --- /dev/null +++ b/ariane/src/bdk/mem/sdram_config.inl @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define DRAM_CFG_SIZE 1896 + +#define DRAM_ID(x) (1 << (x)) + +#define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH 0 +#define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN 1 +#define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2 +#define DRAM_4GB_COPPER_SAMSUNG 3 +#define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH 4 +#define DRAM_4GB_COPPER_HYNIX 5 +#define DRAM_4GB_COPPER_MICRON 6 + +typedef struct _sdram_vendor_patch_t +{ + u32 val; + u16 addr:9; + u16 dramid:7; +} sdram_vendor_patch_t; + +static const sdram_params_t _dram_cfg_0_samsung_4gb = { + /* Specifies the type of memory device */ + .memory_type = MEMORY_TYPE_LPDDR4, + + /* MC/EMC clock source configuration */ + .pllm_input_divider = 0x00000001, // M div. + .pllm_feedback_divider = 0x00000022, // N div. + .pllm_stable_time = 0x0000012C, + .pllm_setup_control = 0x00000000, + .pllm_post_divider = 0x00000000, // P div. + .pllm_kcp = 0x00000000, + .pllm_kvco = 0x00000000, + + /* Spare BCT params */ + .emc_bct_spare0 = 0x00000000, + .emc_bct_spare1 = 0x00000000, + .emc_bct_spare2 = 0x00000000, + .emc_bct_spare3 = 0x00000000, + .emc_bct_spare4 = 0x7001BC68, // EMC_PMACRO_COMMON_PAD_TX_CTRL. + .emc_bct_spare5 = 0x0000000A, + .emc_bct_spare6 = 0x7001B404, // EMC_SWIZZLE_RANK0_BYTE0. + .emc_bct_spare7 = 0x76543201, + .emc_bct_spare8 = 0x7000E6C8, // APBDEV_PMC_WEAK_BIAS. + .emc_bct_spare9 = 0x00000000, + .emc_bct_spare10 = 0x00000000, + .emc_bct_spare11 = 0x00000000, + .emc_bct_spare12 = 0x00000000, // Used to hold EMC_PMACRO_BG_BIAS_CTRL. + .emc_bct_spare13 = 0x00000034, + + /* EMC clock configuration */ + .emc_clock_source = 0x40188002, + .emc_clock_source_dll = 0x40000000, + + .clk_rst_pllm_misc20_override = 0x00000000, + .clk_rst_pllm_misc20_override_enable = 0x00000000, + + .clear_clock2_mc1 = 0x00000000, + + /* Auto-calibration of EMC pads */ + .emc_auto_cal_interval = 0x001FFFFF, + + .emc_auto_cal_config = 0xA01A51D8, + .emc_auto_cal_config2 = 0x05500000, + .emc_auto_cal_config3 = 0x00770000, + + .emc_auto_cal_config4 = 0x00770000, + .emc_auto_cal_config5 = 0x00770000, + .emc_auto_cal_config6 = 0x00770000, + .emc_auto_cal_config7 = 0x00770000, + .emc_auto_cal_config8 = 0x00770000, + + .emc_auto_cal_vref_sel0 = 0xB3AFA6A6, + .emc_auto_cal_vref_sel1 = 0x00009E3C, + + .emc_auto_cal_channel = 0xC1E00303, + + .emc_pmacro_auto_cal_cfg0 = 0x04040404, + .emc_pmacro_auto_cal_cfg1 = 0x04040404, + .emc_pmacro_auto_cal_cfg2 = 0x00000000, + + .emc_pmacro_rx_term = 0x1F1F1F1F, + .emc_pmacro_dq_tx_drive = 0x1F1F1F1F, + .emc_pmacro_ca_tx_drive = 0x1F1F1F1F, + .emc_pmacro_cmd_tx_drive = 0x00001F1F, + .emc_pmacro_auto_cal_common = 0x00000804, + .emc_pmacro_zcrtl = 0x00000550, + + /* Specifies the time for the calibration to stabilize (in microseconds) */ + .emc_auto_cal_wait = 0x000001A1, + + .emc_xm2_comp_pad_ctrl = 0x00000032, + .emc_xm2_comp_pad_ctrl2 = 0x00000000, + .emc_xm2_comp_pad_ctrl3 = 0x00000000, + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + .emc_adr_cfg = 0x00000001, + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + .emc_pin_program_wait = 0x00000002, + /* Specifies the extra delay before/after pin RESET/CKE command */ + .emc_pin_extra_wait = 0x00000000, + + .emc_pin_gpio_enable = 0x00000003, + .emc_pin_gpio = 0x00000003, + + /* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */ + .emc_timing_control_wait = 0x0000001E, + + /* Timing parameters required for the SDRAM */ + .emc_rc = 0x0000000D, + .emc_rfc = 0x00000025, + .emc_rfc_pb = 0x00000013, + .emc_ref_ctrl2 = 0x00000000, + .emc_rfc_slr = 0x00000000, + .emc_ras = 0x00000009, + .emc_rp = 0x00000004, + .emc_r2r = 0x00000000, + .emc_w2w = 0x00000000, + .emc_r2w = 0x0000000B, + .emc_w2r = 0x0000000D, + .emc_r2p = 0x00000008, + .emc_w2p = 0x0000000B, + .emc_tppd = 0x00000004, + .emc_ccdmw = 0x00000020, + .emc_rd_rcd = 0x00000006, + .emc_wr_rcd = 0x00000006, + .emc_rrd = 0x00000006, + .emc_rext = 0x00000003, + .emc_wext = 0x00000000, + .emc_wdv = 0x00000004, + .emc_wdv_chk = 0x00000006, + .emc_wsv = 0x00000002, + .emc_wev = 0x00000000, + .emc_wdv_mask = 0x00000004, + .emc_ws_duration = 0x00000008, + .emc_we_duration = 0x0000000D, + .emc_quse = 0x00000005, + .emc_quse_width = 0x00000006, + .emc_ibdly = 0x00000000, + .emc_obdly = 0x00000000, + .emc_einput = 0x00000002, + .emc_einput_duration = 0x0000000D, + .emc_puterm_extra = 0x00000000, + .emc_puterm_width = 0x0000000B, + .emc_qrst = 0x00010000, + .emc_qsafe = 0x00000012, + .emc_rdv = 0x00000014, + .emc_rdv_mask = 0x00000016, + .emc_rdv_early = 0x00000012, + .emc_rdv_early_mask = 0x00000014, + .emc_qpop = 0x0000000A, + .emc_refresh = 0x00000304, + .emc_burst_refresh_num = 0x00000000, + .emc_prerefresh_req_cnt = 0x000000C1, + .emc_pdex2wr = 0x00000008, + .emc_pdex2rd = 0x00000008, + .emc_pchg2pden = 0x00000003, + .emc_act2pden = 0x00000003, + .emc_ar2pden = 0x00000003, + .emc_rw2pden = 0x00000014, + .emc_cke2pden = 0x00000005, + .emc_pdex2che = 0x00000002, + .emc_pdex2mrr = 0x0000000D, + .emc_txsr = 0x00000027, + .emc_txsr_dll = 0x00000027, + .emc_tcke = 0x00000005, + .emc_tckesr = 0x00000005, + .emc_tpd = 0x00000004, + .emc_tfaw = 0x00000009, + .emc_trpab = 0x00000005, + .emc_tclkstable = 0x00000004, + .emc_tclkstop = 0x00000009, + .emc_trefbw = 0x0000031C, + + /* FBIO configuration values */ + .emc_fbio_cfg5 = 0x9160A00D, + .emc_fbio_cfg7 = 0x00003BBF, + .emc_fbio_cfg8 = 0x0CF30000, + + /* Command mapping for CMD brick 0 */ + .emc_cmd_mapping_cmd0_0 = 0x061B0504, + .emc_cmd_mapping_cmd0_1 = 0x1C070302, + .emc_cmd_mapping_cmd0_2 = 0x05252523, + .emc_cmd_mapping_cmd1_0 = 0x0A091D08, + .emc_cmd_mapping_cmd1_1 = 0x0D1E0B24, + .emc_cmd_mapping_cmd1_2 = 0x0326260C, + .emc_cmd_mapping_cmd2_0 = 0x231C1B02, + .emc_cmd_mapping_cmd2_1 = 0x05070403, + .emc_cmd_mapping_cmd2_2 = 0x02252506, + .emc_cmd_mapping_cmd3_0 = 0x0D1D0B0A, + .emc_cmd_mapping_cmd3_1 = 0x1E090C08, + .emc_cmd_mapping_cmd3_2 = 0x08262624, + .emc_cmd_mapping_byte = 0x9A070624, + + .emc_fbio_spare = 0x00000012, + .emc_cfg_rsv = 0xFF00FF00, + + /* MRS command values */ + .emc_mrs = 0x00000000, + .emc_emrs = 0x00000000, + .emc_emrs2 = 0x00000000, + .emc_emrs3 = 0x00000000, + .emc_mrw1 = 0x08010004, + .emc_mrw2 = 0x08020000, + .emc_mrw3 = 0x080D0000, + .emc_mrw4 = 0xC0000000, + .emc_mrw6 = 0x08037171, + .emc_mrw8 = 0x080B0000, + .emc_mrw9 = 0x0C0E7272, + .emc_mrw10 = 0x00000000, + .emc_mrw12 = 0x0C0D0808, + .emc_mrw13 = 0x0C0D0000, + .emc_mrw14 = 0x08161414, + .emc_mrw_extra = 0x08010004, + .emc_warm_boot_mrw_extra = 0x08110000, + .emc_warm_boot_extramode_reg_write_enable = 0x00000001, + .emc_extramode_reg_write_enable = 0x00000000, + .emc_mrw_reset_command = 0x00000000, + .emc_mrw_reset_ninit_wait = 0x00000000, + .emc_mrs_wait_cnt = 0x00CC0015, + .emc_mrs_wait_cnt2 = 0x0033000A, + + /* EMC miscellaneous configurations */ + .emc_cfg = 0xF3200000, + .emc_cfg2 = 0x00110805, + .emc_cfg_pipe = 0x0FFF0FFF, + .emc_cfg_pipe_clk = 0x00000000, + .emc_fdpd_ctrl_cmd_no_ramp = 0x00000001, + .emc_cfg_update = 0x70000301, + .emc_dbg = 0x01000C00, + .emc_dbg_write_mux = 0x00000001, + .emc_cmd_q = 0x10004408, + .emc_mc2emc_q = 0x06000404, + .emc_dyn_self_ref_control = 0x80000713, + .ahb_arbitration_xbar_ctrl_meminit_done = 0x00000001, + .emc_cfg_dig_dll = 0x002C00A0, + .emc_cfg_dig_dll_1 = 0x00003701, + .emc_cfg_dig_dll_period = 0x00008000, + .emc_dev_select = 0x00000000, + .emc_sel_dpd_ctrl = 0x00040008, + + /* Pads trimmer delays */ + .emc_fdpd_ctrl_dq = 0x8020221F, + .emc_fdpd_ctrl_cmd = 0x0220F40F, + .emc_pmacro_ib_vref_dq_0 = 0x28282828, + .emc_pmacro_ib_vref_dq_1 = 0x28282828, + .emc_pmacro_ib_vref_dqs_0 = 0x11111111, + .emc_pmacro_ib_vref_dqs_1 = 0x11111111, + .emc_pmacro_ib_rxrt = 0x000000BE, + .emc_cfg_pipe1 = 0x0FFF0FFF, + .emc_cfg_pipe2 = 0x0FFF0FFF, + + .emc_pmacro_quse_ddll_rank0_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank0_5 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_0 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_1 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_2 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_3 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_4 = 0x00000000, + .emc_pmacro_quse_ddll_rank1_5 = 0x00000000, + + .emc_pmacro_ob_ddll_long_dq_rank0_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank0_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank0_5 = 0x00140010, + .emc_pmacro_ob_ddll_long_dq_rank1_0 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_1 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_2 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_3 = 0x00000000, + .emc_pmacro_ob_ddll_long_dq_rank1_4 = 0x00120014, + .emc_pmacro_ob_ddll_long_dq_rank1_5 = 0x00140010, + + .emc_pmacro_ob_ddll_long_dqs_rank0_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank0_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank0_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank0_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank0_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank0_5 = 0x00000000, + .emc_pmacro_ob_ddll_long_dqs_rank1_0 = 0x002E0030, + .emc_pmacro_ob_ddll_long_dqs_rank1_1 = 0x00300033, + .emc_pmacro_ob_ddll_long_dqs_rank1_2 = 0x00350033, + .emc_pmacro_ob_ddll_long_dqs_rank1_3 = 0x00320030, + .emc_pmacro_ob_ddll_long_dqs_rank1_4 = 0x00000005, + .emc_pmacro_ob_ddll_long_dqs_rank1_5 = 0x00000000, + + .emc_pmacro_ib_ddll_long_dqs_rank0_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank0_3 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_0 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_1 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_2 = 0x00280028, + .emc_pmacro_ib_ddll_long_dqs_rank1_3 = 0x00280028, + + .emc_pmacro_ddll_long_cmd_0 = 0x00140014, + .emc_pmacro_ddll_long_cmd_1 = 0x00120012, + .emc_pmacro_ddll_long_cmd_2 = 0x00100010, + .emc_pmacro_ddll_long_cmd_3 = 0x00140014, + .emc_pmacro_ddll_long_cmd_4 = 0x00000014, + .emc_pmacro_ddll_short_cmd_0 = 0x00000000, + .emc_pmacro_ddll_short_cmd_1 = 0x00000000, + .emc_pmacro_ddll_short_cmd_2 = 0x00000000, + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + .warm_boot_wait = 0x00000001, + + .emc_odt_write = 0x00000000, + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + .emc_zcal_interval = 0x00064000, + .emc_zcal_wait_cnt = 0x000900CC, + .emc_zcal_mrw_cmd = 0x0051004F, + + /* DRAM initialization sequence flow control */ + .emc_mrs_reset_dll = 0x00000000, + .emc_zcal_init_dev0 = 0x80000001, + .emc_zcal_init_dev1 = 0x40000001, + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + .emc_zcal_init_wait = 0x00000001, + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + .emc_zcal_warm_cold_boot_enables = 0x00000003, + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + .emc_mrw_lpddr2zcal_warm_boot = 0x040A00AB, + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + .emc_zqcal_ddr3_warm_boot = 0x00000011, + .emc_zqcal_lpddr4_warm_boot = 0x00000001, + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + .emc_zcal_warm_boot_wait = 0x00000001, + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + .emc_mrs_warm_boot_enable = 0x00000001, + .emc_mrs_reset_dll_wait = 0x00000000, + .emc_mrs_extra = 0x00000000, + .emc_warm_boot_mrs_extra = 0x00000000, + .emc_emrs_ddr2_dll_enable = 0x00000000, + .emc_mrs_ddr2_dll_reset = 0x00000000, + .emc_emrs_ddr2_ocd_calib = 0x00000000, + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + .emc_ddr2_wait = 0x00000000, + .emc_clken_override = 0x00000000, + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + .emc_extra_refresh_num = 0x00000002, + .emc_clken_override_allwarm_boot = 0x00000000, + .mc_clken_override_allwarm_boot = 0x00000000, + /* Specifies digital dll period, choosing between 4 to 64 ms */ + .emc_cfg_dig_dll_period_warm_boot = 0x00000003, + + /* Pad controls */ + .pmc_vddp_sel = 0x00000001, + .pmc_vddp_sel_wait = 0x00000002, + .pmc_ddr_pwr = 0x0000000F, + .pmc_ddr_cfg = 0x04220100, + .pmc_io_dpd3_req = 0x4FAFFFFF, + .pmc_io_dpd3_req_wait = 0x00000001, + .pmc_io_dpd4_req_wait = 0x00000002, + .pmc_reg_short = 0x00000000, + .pmc_no_io_power = 0x00000000, + .pmc_ddr_ctrl_wait = 0x00000000, + .pmc_ddr_ctrl = 0x0007FF8B, + .emc_acpd_control = 0x00000000, + + .emc_swizzle_rank0_byte0 = 0x76543201, + .emc_swizzle_rank0_byte1 = 0x65324710, + .emc_swizzle_rank0_byte2 = 0x25763410, + .emc_swizzle_rank0_byte3 = 0x25673401, + .emc_swizzle_rank1_byte0 = 0x32647501, + .emc_swizzle_rank1_byte1 = 0x34567201, + .emc_swizzle_rank1_byte2 = 0x56742310, + .emc_swizzle_rank1_byte3 = 0x67324501, + + .emc_txdsrvttgen = 0x00000000, + + .emc_data_brlshft0 = 0x00249249, + .emc_data_brlshft1 = 0x00249249, + + .emc_dqs_brlshft0 = 0x00000000, + .emc_dqs_brlshft1 = 0x00000000, + + .emc_cmd_brlshft0 = 0x00000000, + .emc_cmd_brlshft1 = 0x00000000, + .emc_cmd_brlshft2 = 0x0000001B, + .emc_cmd_brlshft3 = 0x0000001B, + + .emc_quse_brlshft0 = 0x00000000, + .emc_quse_brlshft1 = 0x00000000, + .emc_quse_brlshft2 = 0x00000000, + .emc_quse_brlshft3 = 0x00000000, + + .emc_dll_cfg0 = 0x1F13412F, + .emc_dll_cfg1 = 0x00010014, + + .emc_pmc_scratch1 = 0x4FAFFFFF, + .emc_pmc_scratch2 = 0x7FFFFFFF, + .emc_pmc_scratch3 = 0x4006D70B, + + .emc_pmacro_pad_cfg_ctrl = 0x00020000, + .emc_pmacro_vttgen_ctrl0 = 0x00030808, + .emc_pmacro_vttgen_ctrl1 = 0x00015C00, + .emc_pmacro_vttgen_ctrl2 = 0x00101010, + .emc_pmacro_brick_ctrl_rfu1 = 0x00001600, + .emc_pmacro_cmd_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_brick_ctrl_rfu2 = 0x00000000, + .emc_pmacro_data_brick_ctrl_fdpd = 0x00000000, + .emc_pmacro_bg_bias_ctrl0 = 0x00000034, + .emc_pmacro_data_pad_rx_ctrl = 0x00050037, + .emc_pmacro_cmd_pad_rx_ctrl = 0x00000000, + .emc_pmacro_data_rx_term_mode = 0x00000010, + .emc_pmacro_cmd_rx_term_mode = 0x00003000, + .emc_pmacro_data_pad_tx_ctrl = 0x02000111, + .emc_pmacro_common_pad_tx_ctrl = 0x00000008, + .emc_pmacro_cmd_pad_tx_ctrl = 0x0A000000, + + .emc_cfg3 = 0x00000040, + + .emc_pmacro_tx_pwrd0 = 0x10000000, + .emc_pmacro_tx_pwrd1 = 0x08000000, + .emc_pmacro_tx_pwrd2 = 0x08000000, + .emc_pmacro_tx_pwrd3 = 0x00000000, + .emc_pmacro_tx_pwrd4 = 0x00000000, + .emc_pmacro_tx_pwrd5 = 0x00001000, + + .emc_config_sample_delay = 0x00000020, + + .emc_pmacro_brick_mapping0 = 0x28091081, + .emc_pmacro_brick_mapping1 = 0x44A53293, + .emc_pmacro_brick_mapping2 = 0x76678A5B, + + .emc_pmacro_tx_sel_clk_src0 = 0x00000000, + .emc_pmacro_tx_sel_clk_src1 = 0x00000000, + .emc_pmacro_tx_sel_clk_src2 = 0x00000000, + .emc_pmacro_tx_sel_clk_src3 = 0x00000000, + .emc_pmacro_tx_sel_clk_src4 = 0x00000000, + .emc_pmacro_tx_sel_clk_src5 = 0x00000000, + + .emc_pmacro_ddll_bypass = 0xEFFFEFFF, + + .emc_pmacro_ddll_pwrd0 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd1 = 0xC0C0C0C0, + .emc_pmacro_ddll_pwrd2 = 0xDCDCDCDC, + + .emc_pmacro_cmd_ctrl0 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl1 = 0x0A0A0A0A, + .emc_pmacro_cmd_ctrl2 = 0x0A0A0A0A, + + /* DRAM size information */ + .mc_emem_adr_cfg = 0x00000001, + .mc_emem_adr_cfg_dev0 = 0x00070302, + .mc_emem_adr_cfg_dev1 = 0x00070302, + .mc_emem_adr_cfg_channel_mask = 0xFFFF2400, + .mc_emem_adr_cfg_bank_mask0 = 0x6E574400, + .mc_emem_adr_cfg_bank_mask1 = 0x39722800, + .mc_emem_adr_cfg_bank_mask2 = 0x4B9C1000, + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + .mc_emem_cfg = 0x00001000, + + /* MC arbitration configuration */ + .mc_emem_arb_cfg = 0x08000001, + .mc_emem_arb_outstanding_req = 0x8000004C, + .emc_emem_arb_refpb_hp_ctrl = 0x000A1020, + .emc_emem_arb_refpb_bank_ctrl = 0x80001028, + + .mc_emem_arb_timing_rcd = 0x00000001, + .mc_emem_arb_timing_rp = 0x00000000, + .mc_emem_arb_timing_rc = 0x00000003, + .mc_emem_arb_timing_ras = 0x00000001, + .mc_emem_arb_timing_faw = 0x00000002, + .mc_emem_arb_timing_rrd = 0x00000001, + .mc_emem_arb_timing_rap2pre = 0x00000002, + .mc_emem_arb_timing_wap2pre = 0x00000005, + .mc_emem_arb_timing_r2r = 0x00000002, + .mc_emem_arb_timing_w2w = 0x00000001, + .mc_emem_arb_timing_r2w = 0x00000004, + .mc_emem_arb_timing_w2r = 0x00000005, + .mc_emem_arb_timing_rfcpb = 0x00000004, + + .mc_emem_arb_da_turns = 0x02020001, + .mc_emem_arb_da_covers = 0x00030201, + .mc_emem_arb_misc0 = 0x71C30504, + .mc_emem_arb_misc1 = 0x70000F0F, + .mc_emem_arb_misc2 = 0x00000000, + + .mc_emem_arb_ring1_throttle = 0x001F0000, + .mc_emem_arb_override = 0x10000000, + .mc_emem_arb_override1 = 0x00000000, + .mc_emem_arb_rsv = 0xFF00FF00, + + .mc_da_cfg0 = 0x00000001, + .mc_emem_arb_timing_ccdmw = 0x00000008, + + .mc_clken_override = 0x00008000, + + .mc_stat_control = 0x00000000, + .mc_video_protect_bom = 0xFFF00000, + .mc_video_protect_bom_adr_hi = 0x00000000, + .mc_video_protect_size_mb = 0x00000000, + .mc_video_protect_vpr_override = 0xE4BAC343, + .mc_video_protect_vpr_override1 = 0x00001ED3, + .mc_video_protect_gpu_override0 = 0x00000000, + .mc_video_protect_gpu_override1 = 0x00000000, + .mc_sec_carveout_bom = 0xFFF00000, + .mc_sec_carveout_adr_hi = 0x00000000, + .mc_sec_carveout_size_mb = 0x00000000, + .mc_video_protect_write_access = 0x00000000, + .mc_sec_carveout_protect_write_access = 0x00000000, + + .mc_generalized_carveout1_bom = 0x00000000, + .mc_generalized_carveout1_bom_hi = 0x00000000, + .mc_generalized_carveout1_size_128kb = 0x00000008, + .mc_generalized_carveout1_access0 = 0x00000000, + .mc_generalized_carveout1_access1 = 0x00000000, + .mc_generalized_carveout1_access2 = 0x00300000, + .mc_generalized_carveout1_access3 = 0x03000000, + .mc_generalized_carveout1_access4 = 0x00000000, + .mc_generalized_carveout1_force_internal_access0 = 0x00000000, + .mc_generalized_carveout1_force_internal_access1 = 0x00000000, + .mc_generalized_carveout1_force_internal_access2 = 0x00000000, + .mc_generalized_carveout1_force_internal_access3 = 0x00000000, + .mc_generalized_carveout1_force_internal_access4 = 0x00000000, + .mc_generalized_carveout1_cfg0 = 0x04000C76, + + .mc_generalized_carveout2_bom = 0x00000000, + .mc_generalized_carveout2_bom_hi = 0x00000000, + .mc_generalized_carveout2_size_128kb = 0x00000002, + .mc_generalized_carveout2_access0 = 0x00000000, + .mc_generalized_carveout2_access1 = 0x00000000, + .mc_generalized_carveout2_access2 = 0x03000000, + .mc_generalized_carveout2_access3 = 0x00000000, + .mc_generalized_carveout2_access4 = 0x00000300, + .mc_generalized_carveout2_force_internal_access0 = 0x00000000, + .mc_generalized_carveout2_force_internal_access1 = 0x00000000, + .mc_generalized_carveout2_force_internal_access2 = 0x00000000, + .mc_generalized_carveout2_force_internal_access3 = 0x00000000, + .mc_generalized_carveout2_force_internal_access4 = 0x00000000, + .mc_generalized_carveout2_cfg0 = 0x0440167E, + + .mc_generalized_carveout3_bom = 0x00000000, + .mc_generalized_carveout3_bom_hi = 0x00000000, + .mc_generalized_carveout3_size_128kb = 0x00000000, + .mc_generalized_carveout3_access0 = 0x00000000, + .mc_generalized_carveout3_access1 = 0x00000000, + .mc_generalized_carveout3_access2 = 0x03000000, + .mc_generalized_carveout3_access3 = 0x00000000, + .mc_generalized_carveout3_access4 = 0x00000300, + .mc_generalized_carveout3_force_internal_access0 = 0x00000000, + .mc_generalized_carveout3_force_internal_access1 = 0x00000000, + .mc_generalized_carveout3_force_internal_access2 = 0x00000000, + .mc_generalized_carveout3_force_internal_access3 = 0x00000000, + .mc_generalized_carveout3_force_internal_access4 = 0x00000000, + .mc_generalized_carveout3_cfg0 = 0x04401E7E, + + .mc_generalized_carveout4_bom = 0x00000000, + .mc_generalized_carveout4_bom_hi = 0x00000000, + .mc_generalized_carveout4_size_128kb = 0x00000008, + .mc_generalized_carveout4_access0 = 0x00000000, + .mc_generalized_carveout4_access1 = 0x00000000, + .mc_generalized_carveout4_access2 = 0x00300000, + .mc_generalized_carveout4_access3 = 0x00000000, + .mc_generalized_carveout4_access4 = 0x000000C0, + .mc_generalized_carveout4_force_internal_access0 = 0x00000000, + .mc_generalized_carveout4_force_internal_access1 = 0x00000000, + .mc_generalized_carveout4_force_internal_access2 = 0x00000000, + .mc_generalized_carveout4_force_internal_access3 = 0x00000000, + .mc_generalized_carveout4_force_internal_access4 = 0x00000000, + .mc_generalized_carveout4_cfg0 = 0x04002446, + + .mc_generalized_carveout5_bom = 0x00000000, + .mc_generalized_carveout5_bom_hi = 0x00000000, + .mc_generalized_carveout5_size_128kb = 0x00000008, + .mc_generalized_carveout5_access0 = 0x00000000, + .mc_generalized_carveout5_access1 = 0x00000000, + .mc_generalized_carveout5_access2 = 0x00300000, + .mc_generalized_carveout5_access3 = 0x00000000, + .mc_generalized_carveout5_access4 = 0x00000000, + .mc_generalized_carveout5_force_internal_access0 = 0x00000000, + .mc_generalized_carveout5_force_internal_access1 = 0x00000000, + .mc_generalized_carveout5_force_internal_access2 = 0x00000000, + .mc_generalized_carveout5_force_internal_access3 = 0x00000000, + .mc_generalized_carveout5_force_internal_access4 = 0x00000000, + .mc_generalized_carveout5_cfg0 = 0x04002C46, + + /* Specifies enable for CA training */ + .emc_ca_training_enable = 0x00000000, + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + .swizzle_rank_byte_encode = 0x000000EC, + + /* Specifies enable and offset for patched boot rom write */ + .boot_rom_patch_control = 0x00000000, + /* Specifies data for patched boot rom write */ + .boot_rom_patch_data = 0x00000000, + + .mc_mts_carveout_bom = 0xFFF00000, + .mc_mts_carveout_adr_hi = 0x00000000, + .mc_mts_carveout_size_mb = 0x00000000, + .mc_mts_carveout_reg_ctrl = 0x00000000 +}; + +static const sdram_vendor_patch_t sdram_cfg_vendor_patches[] = { + // Hynix timing config. + { 0x0000000D, 67, DRAM_ID(1) | DRAM_ID(5) }, // emc_r2w. + { 0x00000001, 91, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_extra. + { 0x80000000, 92, DRAM_ID(1) | DRAM_ID(5) }, // emc_puterm_width. + { 0x00000210, 317, DRAM_ID(1) | DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode. + { 0x00000005, 368, DRAM_ID(1) | DRAM_ID(5) }, // mc_emem_arb_timing_r2w. + + // Samsung 6GB density config. + { 0x000C0302, 347, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB sub-partition density. + { 0x000C0302, 348, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB sub-partition density. + { 0x00001800, 353, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. + +#ifdef CONFIG_SDRAM_COPPER_SUPPORT + // Copper prototype Samsung/Hynix/Micron timing configs. + { 0x0000003A, 59, DRAM_ID(6) }, // emc_rfc. Auto refresh. + { 0x0000001D, 60, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. + { 0x00000012, 108, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. + { 0x0000003B, 112, DRAM_ID(6) }, // emc_txsr. + { 0x0000003B, 113, DRAM_ID(6) }, // emc_txsr_dll. + { 0x00000003, 119, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_tclkstable. + { 0x00120015, 205, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_4. + { 0x00160012, 206, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_5. + { 0x00120015, 211, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_4. + { 0x00160012, 212, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_5. + { 0x002F0032, 213, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0. + { 0x00310032, 214, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1. + { 0x00360034, 215, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2. + { 0x0033002F, 216, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3. + { 0x00000006, 217, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4. + { 0x002F0032, 219, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0. + { 0x00310032, 220, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1. + { 0x00360034, 221, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2. + { 0x0033002F, 222, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3. + { 0x00000006, 223, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4. + { 0x00150015, 233, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_0. + { 0x00120012, 235, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_2. + { 0x00160016, 236, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_3. + { 0x00000015, 237, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4. + { 0x00000012, 295, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2. + { 0x00000012, 296, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3. + { 0x00000007, 370, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh. + { 0x72A30504, 373, DRAM_ID(6) }, // mc_emem_arb_misc0. +#endif +}; diff --git a/ariane/src/bdk/mem/sdram_config_lz.inl b/ariane/src/bdk/mem/sdram_config_lz.inl new file mode 100644 index 0000000..832b5b4 --- /dev/null +++ b/ariane/src/bdk/mem/sdram_config_lz.inl @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +static const u8 _dram_cfg_lz[1262] = { + 0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x2C, 0x17, 0x04, 0x09, 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, + 0x17, 0x10, 0x10, 0x00, 0x00, 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0xB4, 0x01, 0x70, 0x01, 0x32, 0x54, 0x76, 0xC8, 0xE6, 0x00, + 0x70, 0x17, 0x10, 0x24, 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, + 0x00, 0x00, 0x00, 0x17, 0x04, 0x04, 0x17, 0x09, 0x18, 0xFF, 0xFF, 0x1F, + 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x77, + 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08, 0x17, 0x08, 0x08, 0xA6, 0xA6, + 0xAF, 0xB3, 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x04, 0x04, + 0x04, 0x04, 0x17, 0x04, 0x04, 0x17, 0x04, 0x3C, 0x1F, 0x1F, 0x1F, 0x1F, + 0x17, 0x04, 0x04, 0x17, 0x06, 0x06, 0x00, 0x00, 0x04, 0x08, 0x17, 0x06, + 0x46, 0xA1, 0x01, 0x00, 0x00, 0x32, 0x17, 0x0B, 0x64, 0x01, 0x17, 0x04, + 0x7C, 0x17, 0x07, 0x0C, 0x03, 0x17, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, + 0x17, 0x0B, 0x2C, 0x09, 0x00, 0x00, 0x00, 0x17, 0x05, 0x5D, 0x17, 0x07, + 0x10, 0x0B, 0x17, 0x07, 0x28, 0x08, 0x17, 0x07, 0x0C, 0x17, 0x04, 0x1C, + 0x20, 0x00, 0x00, 0x00, 0x06, 0x17, 0x04, 0x04, 0x17, 0x07, 0x08, 0x17, + 0x04, 0x50, 0x17, 0x04, 0x2C, 0x17, 0x04, 0x1C, 0x17, 0x04, 0x10, 0x17, + 0x08, 0x6C, 0x17, 0x04, 0x10, 0x17, 0x04, 0x38, 0x17, 0x04, 0x40, 0x05, + 0x17, 0x07, 0x1C, 0x17, 0x08, 0x58, 0x17, 0x04, 0x24, 0x17, 0x04, 0x18, + 0x17, 0x08, 0x64, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x17, 0x09, 0x0C, 0x17, 0x05, 0x82, + 0x58, 0x17, 0x07, 0x61, 0xC1, 0x17, 0x07, 0x50, 0x17, 0x04, 0x04, 0x17, + 0x08, 0x81, 0x48, 0x17, 0x04, 0x04, 0x17, 0x04, 0x28, 0x17, 0x04, 0x60, + 0x17, 0x08, 0x54, 0x27, 0x17, 0x04, 0x04, 0x17, 0x07, 0x14, 0x17, 0x04, + 0x04, 0x04, 0x17, 0x07, 0x81, 0x58, 0x17, 0x0C, 0x0C, 0x1C, 0x03, 0x00, + 0x00, 0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x17, 0x04, 0x5A, 0xF3, 0x0C, + 0x04, 0x05, 0x1B, 0x06, 0x02, 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, + 0x08, 0x1D, 0x09, 0x0A, 0x24, 0x0B, 0x1E, 0x0D, 0x0C, 0x26, 0x26, 0x03, + 0x02, 0x1B, 0x1C, 0x23, 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, + 0x0A, 0x0B, 0x1D, 0x0D, 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, + 0x24, 0x06, 0x07, 0x9A, 0x12, 0x17, 0x05, 0x83, 0x41, 0x00, 0xFF, 0x17, + 0x10, 0x83, 0x6C, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, + 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, + 0x00, 0x0B, 0x08, 0x72, 0x72, 0x0E, 0x0C, 0x17, 0x04, 0x20, 0x08, 0x08, + 0x0D, 0x0C, 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, 0x16, 0x08, 0x17, 0x06, + 0x2C, 0x11, 0x08, 0x17, 0x10, 0x84, 0x67, 0x15, 0x00, 0xCC, 0x00, 0x0A, + 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x05, 0x08, 0x11, 0x00, 0xFF, + 0x0F, 0xFF, 0x0F, 0x17, 0x08, 0x83, 0x4C, 0x01, 0x03, 0x00, 0x70, 0x00, + 0x0C, 0x00, 0x01, 0x17, 0x04, 0x0C, 0x08, 0x44, 0x00, 0x10, 0x04, 0x04, + 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, 0x17, 0x04, 0x10, 0xA0, 0x00, 0x2C, + 0x00, 0x01, 0x37, 0x00, 0x00, 0x00, 0x80, 0x17, 0x06, 0x48, 0x08, 0x00, + 0x04, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x28, 0x28, + 0x28, 0x28, 0x17, 0x04, 0x04, 0x11, 0x11, 0x11, 0x11, 0x17, 0x04, 0x04, + 0xBE, 0x00, 0x00, 0x17, 0x05, 0x58, 0x17, 0x08, 0x5C, 0x17, 0x22, 0x85, + 0x6A, 0x17, 0x1A, 0x1A, 0x14, 0x00, 0x12, 0x00, 0x10, 0x17, 0x05, 0x83, + 0x0A, 0x17, 0x16, 0x18, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, + 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x17, 0x05, 0x83, 0x0C, 0x17, + 0x04, 0x20, 0x17, 0x18, 0x18, 0x28, 0x00, 0x28, 0x17, 0x04, 0x04, 0x17, + 0x08, 0x08, 0x17, 0x10, 0x10, 0x00, 0x14, 0x17, 0x05, 0x5A, 0x17, 0x04, + 0x5C, 0x17, 0x04, 0x5E, 0x17, 0x04, 0x0E, 0x17, 0x0E, 0x78, 0x17, 0x09, + 0x82, 0x50, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, + 0x17, 0x08, 0x18, 0x80, 0x01, 0x00, 0x00, 0x40, 0x17, 0x04, 0x20, 0x03, + 0x00, 0x00, 0x00, 0xAB, 0x00, 0x0A, 0x04, 0x11, 0x17, 0x08, 0x82, 0x58, + 0x17, 0x0C, 0x38, 0x17, 0x1B, 0x81, 0x6C, 0x17, 0x08, 0x85, 0x60, 0x17, + 0x08, 0x86, 0x50, 0x17, 0x08, 0x86, 0x60, 0x17, 0x06, 0x83, 0x21, 0x22, + 0x04, 0xFF, 0xFF, 0xAF, 0x4F, 0x17, 0x0C, 0x86, 0x74, 0x17, 0x08, 0x2C, + 0x8B, 0xFF, 0x07, 0x17, 0x06, 0x81, 0x04, 0x32, 0x54, 0x76, 0x10, 0x47, + 0x32, 0x65, 0x10, 0x34, 0x76, 0x25, 0x01, 0x34, 0x67, 0x25, 0x01, 0x75, + 0x64, 0x32, 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, 0x74, 0x56, 0x01, 0x45, + 0x32, 0x67, 0x17, 0x04, 0x24, 0x49, 0x92, 0x24, 0x17, 0x04, 0x04, 0x17, + 0x11, 0x7C, 0x1B, 0x17, 0x04, 0x04, 0x17, 0x13, 0x81, 0x14, 0x2F, 0x41, + 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x17, 0x04, 0x7C, 0xFF, 0xFF, 0xFF, + 0x7F, 0x0B, 0xD7, 0x06, 0x40, 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x03, + 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x17, 0x06, 0x86, 0x59, + 0x17, 0x0F, 0x89, 0x14, 0x37, 0x17, 0x07, 0x82, 0x72, 0x10, 0x17, 0x06, + 0x83, 0x0D, 0x00, 0x11, 0x01, 0x17, 0x05, 0x85, 0x39, 0x17, 0x04, 0x0E, + 0x0A, 0x17, 0x07, 0x89, 0x29, 0x17, 0x04, 0x1B, 0x17, 0x08, 0x86, 0x77, + 0x17, 0x09, 0x12, 0x20, 0x00, 0x00, 0x00, 0x81, 0x10, 0x09, 0x28, 0x93, + 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, 0x17, 0x18, 0x82, 0x2C, 0xFF, + 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0x17, 0x04, 0x04, 0xDC, 0xDC, + 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x17, 0x04, 0x04, 0x17, 0x04, 0x04, + 0x17, 0x05, 0x82, 0x24, 0x03, 0x07, 0x17, 0x04, 0x04, 0x00, 0x00, 0x24, + 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, + 0x9C, 0x4B, 0x17, 0x04, 0x64, 0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, + 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x17, 0x06, 0x85, 0x60, 0x17, + 0x10, 0x82, 0x74, 0x17, 0x08, 0x08, 0x17, 0x08, 0x88, 0x00, 0x17, 0x04, + 0x10, 0x04, 0x17, 0x0B, 0x87, 0x6C, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, + 0x03, 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x17, 0x08, 0x8B, 0x18, + 0x1F, 0x17, 0x09, 0x81, 0x73, 0x00, 0xFF, 0x00, 0xFF, 0x17, 0x05, 0x86, + 0x48, 0x17, 0x04, 0x0C, 0x17, 0x07, 0x86, 0x34, 0x00, 0x00, 0xF0, 0x17, + 0x09, 0x87, 0x54, 0x43, 0xC3, 0xBA, 0xE4, 0xD3, 0x1E, 0x17, 0x0C, 0x81, + 0x52, 0x17, 0x0A, 0x1C, 0x17, 0x10, 0x81, 0x6C, 0x17, 0x0A, 0x82, 0x21, + 0x17, 0x07, 0x82, 0x4D, 0x17, 0x0A, 0x8A, 0x1B, 0x17, 0x11, 0x2C, 0x76, + 0x0C, 0x17, 0x0A, 0x8A, 0x67, 0x17, 0x0F, 0x84, 0x28, 0x17, 0x06, 0x34, + 0x17, 0x17, 0x3A, 0x7E, 0x16, 0x40, 0x17, 0x0C, 0x8B, 0x1F, 0x17, 0x2A, + 0x38, 0x1E, 0x17, 0x0A, 0x38, 0x17, 0x13, 0x81, 0x28, 0x00, 0xC0, 0x17, + 0x17, 0x55, 0x46, 0x24, 0x17, 0x0A, 0x81, 0x28, 0x17, 0x14, 0x38, 0x17, + 0x18, 0x81, 0x60, 0x46, 0x2C, 0x17, 0x06, 0x38, 0xEC, 0x17, 0x0D, 0x16, + 0x17, 0x0E, 0x82, 0x3C, 0x17, 0x82, 0x0C, 0x8E, 0x68, 0x17, 0x04, 0x24, + 0x17, 0x5C, 0x8E, 0x68, 0x17, 0x07, 0x82, 0x5F, 0x80, 0x17, 0x87, 0x01, + 0x8E, 0x68, 0x02, 0x17, 0x81, 0x4A, 0x8E, 0x68, 0x17, 0x0C, 0x87, 0x78, + 0x17, 0x85, 0x28, 0x8E, 0x68, 0x17, 0x8E, 0x68, 0x9D, 0x50, 0x17, 0x81, + 0x24, 0x8E, 0x68, 0x17, 0x04, 0x2C, 0x17, 0x28, 0x8E, 0x68, 0x17, 0x04, + 0x30, 0x17, 0x85, 0x3C, 0x8E, 0x68, 0x12, 0x17, 0x07, 0x85, 0x70, 0x17, + 0x88, 0x74, 0x8E, 0x68, 0x17, 0x87, 0x3E, 0x9D, 0x50, 0x0C, 0x17, 0x04, + 0x04, 0x17, 0x12, 0x8E, 0x68, 0x18, 0x17, 0x87, 0x12, 0xBB, 0x20, 0x17, + 0x83, 0x04, 0x9D, 0x50, 0x15, 0x17, 0x05, 0x8D, 0x76, 0x17, 0x0F, 0x8B, + 0x49, 0x17, 0x0B, 0x18, 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, + 0x34, 0x00, 0x36, 0x00, 0x2F, 0x00, 0x33, 0x17, 0x09, 0x84, 0x0C, 0x17, + 0x18, 0x18, 0x17, 0x20, 0x8E, 0x68, 0x15, 0x17, 0x07, 0x5A, 0x17, 0x06, + 0x5E, 0x16, 0x00, 0x15, 0x17, 0x82, 0x40, 0x9D, 0x50, 0x17, 0x86, 0x5F, + 0xBB, 0x20, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x17, 0x81, 0x4F, 0xAC, 0x38, + 0x3B, 0x17, 0x04, 0x04, 0x17, 0x86, 0x30, 0x8E, 0x68, 0x17, 0x81, 0x53, + 0xAC, 0x38, 0x07, 0x17, 0x0D, 0x8E, 0x68, 0xA3, 0x72, 0x17, 0x83, 0x10, + 0x8E, 0x68 +}; diff --git a/ariane/src/hwinit/sdram_lp0.c b/ariane/src/bdk/mem/sdram_lp0.c similarity index 99% rename from ariane/src/hwinit/sdram_lp0.c rename to ariane/src/bdk/mem/sdram_lp0.c index 8346009..2a83c27 100644 --- a/ariane/src/hwinit/sdram_lp0.c +++ b/ariane/src/bdk/mem/sdram_lp0.c @@ -1,6 +1,8 @@ /* * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -12,9 +14,9 @@ * more details. */ -#include "t210.h" -#include "pmc.h" -#include "sdram_param_t210.h" +#include +#include +#include /* * This function reads SDRAM parameters from the common BCT format and @@ -45,7 +47,7 @@ void sdram_lp0_save_params(const void *params) #define c32(value, pmcreg) pmc->pmcreg = value //TODO: pkg1.1 (1.X - 3.X) reads them from MC. - //Patch carveout parameters. + // Patch carveout parameters. /*sdram->McGeneralizedCarveout1Bom = 0; sdram->McGeneralizedCarveout1BomHi = 0; sdram->McGeneralizedCarveout1Size128kb = 0; @@ -118,14 +120,14 @@ void sdram_lp0_save_params(const void *params) sdram->McGeneralizedCarveout5Cfg0 = 0x8F;*/ //TODO: this is 4.X+ behaviour which seems to work fine for < 4.X. - //Patch carveout parameters. + // Patch carveout parameters. sdram->McGeneralizedCarveout1Cfg0 = 0; sdram->McGeneralizedCarveout2Cfg0 = 0; sdram->McGeneralizedCarveout3Cfg0 = 0; sdram->McGeneralizedCarveout4Cfg0 = 0; sdram->McGeneralizedCarveout5Cfg0 = 0; - //Patch SDRAM parameters. + // Patch SDRAM parameters. u32 t0 = sdram->EmcSwizzleRank0Byte0 << 5 >> 29 > sdram->EmcSwizzleRank0Byte0 << 1 >> 29; u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->EmcSwizzleRank1Byte0 << 5 >> 29 > sdram->EmcSwizzleRank1Byte0 << 1 >> 29) << 4); u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->EmcSwizzleRank0Byte1 << 5 >> 29 > sdram->EmcSwizzleRank0Byte1 << 1 >> 29) << 1); @@ -835,7 +837,8 @@ void sdram_lp0_save_params(const void *params) s(EmcAutoCalWait, 9:0, scratch101, 31:22); s(SwizzleRankByteEncode, 15:0, scratch190, 15:0); - switch (sdram->MemoryType) { + switch (sdram->MemoryType) + { case NvBootMemoryType_LpDdr2: case NvBootMemoryType_LpDdr4: s(EmcMrwLpddr2ZcalWarmBoot, 23:16, scratch5, 7:0); diff --git a/ariane/src/bdk/mem/sdram_lp0_param_t210.h b/ariane/src/bdk/mem/sdram_lp0_param_t210.h new file mode 100644 index 0000000..1422ed3 --- /dev/null +++ b/ariane/src/bdk/mem/sdram_lp0_param_t210.h @@ -0,0 +1,964 @@ +/* + * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright 2014 Google Inc. + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * Defines the SDRAM parameter structure. + * + * Note that PLLM is used by EMC. The field names are in camel case to ease + * directly converting BCT config files (*.cfg) into C structure. + */ + +#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ +#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ + +#include + +enum +{ + /* Specifies the memory type to be undefined */ + NvBootMemoryType_None = 0, + + /* Specifies the memory type to be DDR SDRAM */ + NvBootMemoryType_Ddr = 0, + + /* Specifies the memory type to be LPDDR SDRAM */ + NvBootMemoryType_LpDdr = 0, + + /* Specifies the memory type to be DDR2 SDRAM */ + NvBootMemoryType_Ddr2 = 0, + + /* Specifies the memory type to be LPDDR2 SDRAM */ + NvBootMemoryType_LpDdr2, + + /* Specifies the memory type to be DDR3 SDRAM */ + NvBootMemoryType_Ddr3, + + /* Specifies the memory type to be LPDDR4 SDRAM */ + NvBootMemoryType_LpDdr4, + + NvBootMemoryType_Num, + + /* Specifies an entry in the ram_code table that's not in use */ + NvBootMemoryType_Unused = 0X7FFFFFF, +}; + +/** + * Defines the SDRAM parameter structure + */ +struct sdram_params +{ + + /* Specifies the type of memory device */ + u32 MemoryType; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 PllMInputDivider; + /* Specifies the N value for PllM */ + u32 PllMFeedbackDivider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 PllMStableTime; + /* Specifies misc. control bits */ + u32 PllMSetupControl; + /* Specifies the P value for PLLM */ + u32 PllMPostDivider; + /* Specifies value for Charge Pump Gain Control */ + u32 PllMKCP; + /* Specifies VCO gain */ + u32 PllMKVCO; + /* Spare BCT param */ + u32 EmcBctSpare0; + /* Spare BCT param */ + u32 EmcBctSpare1; + /* Spare BCT param */ + u32 EmcBctSpare2; + /* Spare BCT param */ + u32 EmcBctSpare3; + /* Spare BCT param */ + u32 EmcBctSpare4; + /* Spare BCT param */ + u32 EmcBctSpare5; + /* Spare BCT param */ + u32 EmcBctSpare6; + /* Spare BCT param */ + u32 EmcBctSpare7; + /* Spare BCT param */ + u32 EmcBctSpare8; + /* Spare BCT param */ + u32 EmcBctSpare9; + /* Spare BCT param */ + u32 EmcBctSpare10; + /* Spare BCT param */ + u32 EmcBctSpare11; + /* Spare BCT param */ + u32 EmcBctSpare12; + /* Spare BCT param */ + u32 EmcBctSpare13; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 EmcClockSource; + u32 EmcClockSourceDll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 ClkRstControllerPllmMisc2Override; + /* enables override for PLLLM_MISC2 */ + u32 ClkRstControllerPllmMisc2OverrideEnable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 ClearClk2Mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 EmcAutoCalInterval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 EmcAutoCalConfig; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 EmcAutoCalConfig2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 EmcAutoCalConfig3; + + /* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */ + u32 EmcAutoCalConfig4; + u32 EmcAutoCalConfig5; + u32 EmcAutoCalConfig6; + u32 EmcAutoCalConfig7; + u32 EmcAutoCalConfig8; + + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 EmcAutoCalVrefSel0; + u32 EmcAutoCalVrefSel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 EmcAutoCalChannel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 EmcPmacroAutocalCfg0; + u32 EmcPmacroAutocalCfg1; + u32 EmcPmacroAutocalCfg2; + u32 EmcPmacroRxTerm; + u32 EmcPmacroDqTxDrv; + u32 EmcPmacroCaTxDrv; + u32 EmcPmacroCmdTxDrv; + u32 EmcPmacroAutocalCfgCommon; + u32 EmcPmacroZctrl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 EmcAutoCalWait; + + u32 EmcXm2CompPadCtrl; + u32 EmcXm2CompPadCtrl2; + u32 EmcXm2CompPadCtrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 EmcAdrCfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 EmcPinProgramWait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 EmcPinExtraWait; + + u32 EmcPinGpioEn; + u32 EmcPinGpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 EmcTimingControlWait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 EmcRc; + /* Specifies the value for EMC_RFC */ + u32 EmcRfc; + /* Specifies the value for EMC_RFC_PB */ + u32 EmcRfcPb; + /* Specifies the value for EMC_RFC_CTRL2 */ + u32 EmcRefctrl2; + /* Specifies the value for EMC_RFC_SLR */ + u32 EmcRfcSlr; + /* Specifies the value for EMC_RAS */ + u32 EmcRas; + /* Specifies the value for EMC_RP */ + u32 EmcRp; + /* Specifies the value for EMC_R2R */ + u32 EmcR2r; + /* Specifies the value for EMC_W2W */ + u32 EmcW2w; + /* Specifies the value for EMC_R2W */ + u32 EmcR2w; + /* Specifies the value for EMC_W2R */ + u32 EmcW2r; + /* Specifies the value for EMC_R2P */ + u32 EmcR2p; + /* Specifies the value for EMC_W2P */ + u32 EmcW2p; + + u32 EmcTppd; + u32 EmcCcdmw; + + /* Specifies the value for EMC_RD_RCD */ + u32 EmcRdRcd; + /* Specifies the value for EMC_WR_RCD */ + u32 EmcWrRcd; + /* Specifies the value for EMC_RRD */ + u32 EmcRrd; + /* Specifies the value for EMC_REXT */ + u32 EmcRext; + /* Specifies the value for EMC_WEXT */ + u32 EmcWext; + /* Specifies the value for EMC_WDV */ + u32 EmcWdv; + + u32 EmcWdvChk; + u32 EmcWsv; + u32 EmcWev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 EmcWdvMask; + + u32 EmcWsDuration; + u32 EmcWeDuration; + + /* Specifies the value for EMC_QUSE */ + u32 EmcQUse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 EmcQuseWidth; + /* Specifies the value for EMC_IBDLY */ + u32 EmcIbdly; + /* Specifies the value for EMC_OBDLY */ + u32 EmcObdly; + /* Specifies the value for EMC_EINPUT */ + u32 EmcEInput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 EmcEInputDuration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 EmcPutermExtra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 EmcPutermWidth; + /* Specifies the value for EMC_PUTERM_ADJ */ + ////u32 EmcPutermAdj; + + /* Specifies the value for EMC_QRST */ + u32 EmcQRst; + /* Specifies the value for EMC_QSAFE */ + u32 EmcQSafe; + /* Specifies the value for EMC_RDV */ + u32 EmcRdv; + /* Specifies the value for EMC_RDV_MASK */ + u32 EmcRdvMask; + /* Specifies the value for EMC_RDV_EARLY */ + u32 EmcRdvEarly; + /* Specifies the value for EMC_RDV_EARLY_MASK */ + u32 EmcRdvEarlyMask; + /* Specifies the value for EMC_QPOP */ + u32 EmcQpop; + + /* Specifies the value for EMC_REFRESH */ + u32 EmcRefresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 EmcBurstRefreshNum; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 EmcPreRefreshReqCnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 EmcPdEx2Wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 EmcPdEx2Rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 EmcPChg2Pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 EmcAct2Pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 EmcAr2Pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 EmcRw2Pden; + /* Specifies the value for EMC_CKE2PDEN */ + u32 EmcCke2Pden; + /* Specifies the value for EMC_PDEX2CKE */ + u32 EmcPdex2Cke; + /* Specifies the value for EMC_PDEX2MRR */ + u32 EmcPdex2Mrr; + /* Specifies the value for EMC_TXSR */ + u32 EmcTxsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 EmcTxsrDll; + /* Specifies the value for EMC_TCKE */ + u32 EmcTcke; + /* Specifies the value for EMC_TCKESR */ + u32 EmcTckesr; + /* Specifies the value for EMC_TPD */ + u32 EmcTpd; + /* Specifies the value for EMC_TFAW */ + u32 EmcTfaw; + /* Specifies the value for EMC_TRPAB */ + u32 EmcTrpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 EmcTClkStable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 EmcTClkStop; + /* Specifies the value for EMC_TREFBW */ + u32 EmcTRefBw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 EmcFbioCfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 EmcFbioCfg7; + /* Specifies the value for EMC_FBIO_CFG8 */ + u32 EmcFbioCfg8; + + /* Command mapping for CMD brick 0 */ + u32 EmcCmdMappingCmd0_0; + u32 EmcCmdMappingCmd0_1; + u32 EmcCmdMappingCmd0_2; + u32 EmcCmdMappingCmd1_0; + u32 EmcCmdMappingCmd1_1; + u32 EmcCmdMappingCmd1_2; + u32 EmcCmdMappingCmd2_0; + u32 EmcCmdMappingCmd2_1; + u32 EmcCmdMappingCmd2_2; + u32 EmcCmdMappingCmd3_0; + u32 EmcCmdMappingCmd3_1; + u32 EmcCmdMappingCmd3_2; + u32 EmcCmdMappingByte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 EmcFbioSpare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 EmcCfgRsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 EmcMrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 EmcEmrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 EmcEmrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 EmcEmrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 EmcMrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 EmcMrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 EmcMrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 EmcMrw4; + /* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */ + u32 EmcMrw6; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 EmcMrw8; + /* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */ + u32 EmcMrw9; + /* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */ + u32 EmcMrw10; + /* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */ + u32 EmcMrw12; + /* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */ + u32 EmcMrw13; + /* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */ + u32 EmcMrw14; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 EmcMrwExtra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 EmcWarmBootMrwExtra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 EmcWarmBootExtraModeRegWriteEnable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 EmcExtraModeRegWriteEnable; + + /* Specifies the EMC_MRW reset command value */ + u32 EmcMrwResetCommand; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 EmcMrwResetNInitWait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 EmcMrsWaitCnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 EmcMrsWaitCnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 EmcCfg; + /* Specifies the value for EMC_CFG_2 */ + u32 EmcCfg2; + /* Specifies the pipe bypass controls */ + u32 EmcCfgPipe; + u32 EmcCfgPipeClk; + u32 EmcFdpdCtrlCmdNoRamp; + u32 EmcCfgUpdate; + + /* Specifies the value for EMC_DBG */ + u32 EmcDbg; + u32 EmcDbgWriteMux; + + /* Specifies the value for EMC_CMDQ */ + u32 EmcCmdQ; + /* Specifies the value for EMC_MC2EMCQ */ + u32 EmcMc2EmcQ; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 EmcDynSelfRefControl; + + /* Specifies the value for MEM_INIT_DONE */ + u32 AhbArbitrationXbarCtrlMemInitDone; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 EmcCfgDigDll; + u32 EmcCfgDigDll_1; + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 EmcCfgDigDllPeriod; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 EmcDevSelect; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 EmcSelDpdCtrl; + + /* Pads trimmer delays */ + u32 EmcFdpdCtrlDq; + u32 EmcFdpdCtrlCmd; + u32 EmcPmacroIbVrefDq_0; + u32 EmcPmacroIbVrefDq_1; + u32 EmcPmacroIbVrefDqs_0; + u32 EmcPmacroIbVrefDqs_1; + u32 EmcPmacroIbRxrt; + u32 EmcCfgPipe1; + u32 EmcCfgPipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 EmcPmacroQuseDdllRank0_0; + u32 EmcPmacroQuseDdllRank0_1; + u32 EmcPmacroQuseDdllRank0_2; + u32 EmcPmacroQuseDdllRank0_3; + u32 EmcPmacroQuseDdllRank0_4; + u32 EmcPmacroQuseDdllRank0_5; + u32 EmcPmacroQuseDdllRank1_0; + u32 EmcPmacroQuseDdllRank1_1; + u32 EmcPmacroQuseDdllRank1_2; + u32 EmcPmacroQuseDdllRank1_3; + u32 EmcPmacroQuseDdllRank1_4; + u32 EmcPmacroQuseDdllRank1_5; + + u32 EmcPmacroObDdllLongDqRank0_0; + u32 EmcPmacroObDdllLongDqRank0_1; + u32 EmcPmacroObDdllLongDqRank0_2; + u32 EmcPmacroObDdllLongDqRank0_3; + u32 EmcPmacroObDdllLongDqRank0_4; + u32 EmcPmacroObDdllLongDqRank0_5; + u32 EmcPmacroObDdllLongDqRank1_0; + u32 EmcPmacroObDdllLongDqRank1_1; + u32 EmcPmacroObDdllLongDqRank1_2; + u32 EmcPmacroObDdllLongDqRank1_3; + u32 EmcPmacroObDdllLongDqRank1_4; + u32 EmcPmacroObDdllLongDqRank1_5; + + u32 EmcPmacroObDdllLongDqsRank0_0; + u32 EmcPmacroObDdllLongDqsRank0_1; + u32 EmcPmacroObDdllLongDqsRank0_2; + u32 EmcPmacroObDdllLongDqsRank0_3; + u32 EmcPmacroObDdllLongDqsRank0_4; + u32 EmcPmacroObDdllLongDqsRank0_5; + u32 EmcPmacroObDdllLongDqsRank1_0; + u32 EmcPmacroObDdllLongDqsRank1_1; + u32 EmcPmacroObDdllLongDqsRank1_2; + u32 EmcPmacroObDdllLongDqsRank1_3; + u32 EmcPmacroObDdllLongDqsRank1_4; + u32 EmcPmacroObDdllLongDqsRank1_5; + + u32 EmcPmacroIbDdllLongDqsRank0_0; + u32 EmcPmacroIbDdllLongDqsRank0_1; + u32 EmcPmacroIbDdllLongDqsRank0_2; + u32 EmcPmacroIbDdllLongDqsRank0_3; + u32 EmcPmacroIbDdllLongDqsRank1_0; + u32 EmcPmacroIbDdllLongDqsRank1_1; + u32 EmcPmacroIbDdllLongDqsRank1_2; + u32 EmcPmacroIbDdllLongDqsRank1_3; + + u32 EmcPmacroDdllLongCmd_0; + u32 EmcPmacroDdllLongCmd_1; + u32 EmcPmacroDdllLongCmd_2; + u32 EmcPmacroDdllLongCmd_3; + u32 EmcPmacroDdllLongCmd_4; + u32 EmcPmacroDdllShortCmd_0; + u32 EmcPmacroDdllShortCmd_1; + u32 EmcPmacroDdllShortCmd_2; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 WarmBootWait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 EmcOdtWrite; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 EmcZcalInterval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 EmcZcalWaitCnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 EmcZcalMrwCmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 EmcMrsResetDll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 EmcZcalInitDev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 EmcZcalInitDev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 EmcZcalInitWait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 EmcZcalWarmColdBootEnables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 EmcMrwLpddr2ZcalWarmBoot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 EmcZqCalDdr3WarmBoot; + u32 EmcZqCalLpDdr4WarmBoot; + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 EmcZcalWarmBootWait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 EmcMrsWarmBootEnable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 EmcMrsResetDllWait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 EmcMrsExtra; + /* Specifies the extra MRS command at warm boot */ + u32 EmcWarmBootMrsExtra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 EmcEmrsDdr2DllEnable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 EmcMrsDdr2DllReset; + /* Specifies the EMRS command to set OCD calibration */ + u32 EmcEmrsDdr2OcdCalib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 EmcDdr2Wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 EmcClkenOverride; + + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 EmcExtraRefreshNum; + /* Specifies the master override for all EMC clocks */ + u32 EmcClkenOverrideAllWarmBoot; + /* Specifies the master override for all MC clocks */ + u32 McClkenOverrideAllWarmBoot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 EmcCfgDigDllPeriodWarmBoot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 PmcVddpSel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 PmcVddpSelWait; + /* Specifies the value for PMC_DDR_PWR */ + u32 PmcDdrPwr; + /* Specifies the value for PMC_DDR_CFG */ + u32 PmcDdrCfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 PmcIoDpd3Req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 PmcIoDpd3ReqWait; + u32 PmcIoDpd4ReqWait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 PmcRegShort; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 PmcNoIoPower; + + u32 PmcDdrCntrlWait; + u32 PmcDdrCntrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 EmcAcpdControl; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */ + ////u32 EmcSwizzleRank0ByteCfg; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 EmcSwizzleRank0Byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 EmcSwizzleRank0Byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 EmcSwizzleRank0Byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 EmcSwizzleRank0Byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */ + ////u32 EmcSwizzleRank1ByteCfg; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 EmcSwizzleRank1Byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 EmcSwizzleRank1Byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 EmcSwizzleRank1Byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 EmcSwizzleRank1Byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 EmcTxdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 EmcDataBrlshft0; + u32 EmcDataBrlshft1; + + u32 EmcDqsBrlshft0; + u32 EmcDqsBrlshft1; + + u32 EmcCmdBrlshft0; + u32 EmcCmdBrlshft1; + u32 EmcCmdBrlshft2; + u32 EmcCmdBrlshft3; + + u32 EmcQuseBrlshft0; + u32 EmcQuseBrlshft1; + u32 EmcQuseBrlshft2; + u32 EmcQuseBrlshft3; + + u32 EmcDllCfg0; + u32 EmcDllCfg1; + + u32 EmcPmcScratch1; + u32 EmcPmcScratch2; + u32 EmcPmcScratch3; + + u32 EmcPmacroPadCfgCtrl; + + u32 EmcPmacroVttgenCtrl0; + u32 EmcPmacroVttgenCtrl1; + u32 EmcPmacroVttgenCtrl2; + + u32 EmcPmacroBrickCtrlRfu1; + u32 EmcPmacroCmdBrickCtrlFdpd; + u32 EmcPmacroBrickCtrlRfu2; + u32 EmcPmacroDataBrickCtrlFdpd; + u32 EmcPmacroBgBiasCtrl0; + u32 EmcPmacroDataPadRxCtrl; + u32 EmcPmacroCmdPadRxCtrl; + u32 EmcPmacroDataRxTermMode; + u32 EmcPmacroCmdRxTermMode; + u32 EmcPmacroDataPadTxCtrl; + u32 EmcPmacroCommonPadTxCtrl; + u32 EmcPmacroCmdPadTxCtrl; + u32 EmcCfg3; + + u32 EmcPmacroTxPwrd0; + u32 EmcPmacroTxPwrd1; + u32 EmcPmacroTxPwrd2; + u32 EmcPmacroTxPwrd3; + u32 EmcPmacroTxPwrd4; + u32 EmcPmacroTxPwrd5; + + u32 EmcConfigSampleDelay; + + u32 EmcPmacroBrickMapping0; + u32 EmcPmacroBrickMapping1; + u32 EmcPmacroBrickMapping2; + + u32 EmcPmacroTxSelClkSrc0; + u32 EmcPmacroTxSelClkSrc1; + u32 EmcPmacroTxSelClkSrc2; + u32 EmcPmacroTxSelClkSrc3; + u32 EmcPmacroTxSelClkSrc4; + u32 EmcPmacroTxSelClkSrc5; + + u32 EmcPmacroDdllBypass; + + u32 EmcPmacroDdllPwrd0; + u32 EmcPmacroDdllPwrd1; + u32 EmcPmacroDdllPwrd2; + + u32 EmcPmacroCmdCtrl0; + u32 EmcPmacroCmdCtrl1; + u32 EmcPmacroCmdCtrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 McEmemAdrCfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 McEmemAdrCfgDev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 McEmemAdrCfgDev1; + u32 McEmemAdrCfgChannelMask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */ + u32 McEmemAdrCfgBankMask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 McEmemAdrCfgBankMask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 McEmemAdrCfgBankMask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 McEmemCfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 McEmemArbCfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 McEmemArbOutstandingReq; + + u32 McEmemArbRefpbHpCtrl; + u32 McEmemArbRefpbBankCtrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 McEmemArbTimingRcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 McEmemArbTimingRp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 McEmemArbTimingRc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 McEmemArbTimingRas; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 McEmemArbTimingFaw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 McEmemArbTimingRrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 McEmemArbTimingRap2Pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 McEmemArbTimingWap2Pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 McEmemArbTimingR2R; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 McEmemArbTimingW2W; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 McEmemArbTimingR2W; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 McEmemArbTimingW2R; + + u32 McEmemArbTimingRFCPB; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 McEmemArbDaTurns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 McEmemArbDaCovers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 McEmemArbMisc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 McEmemArbMisc1; + u32 McEmemArbMisc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 McEmemArbRing1Throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 McEmemArbOverride; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 McEmemArbOverride1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 McEmemArbRsv; + + u32 McDaCfg0; + u32 McEmemArbTimingCcdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 McClkenOverride; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 McStatControl; + + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 McVideoProtectBom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 McVideoProtectBomAdrHi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 McVideoProtectSizeMb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 McVideoProtectVprOverride; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 McVideoProtectVprOverride1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 McVideoProtectGpuOverride0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 McVideoProtectGpuOverride1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 McSecCarveoutBom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 McSecCarveoutAdrHi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 McSecCarveoutSizeMb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL. + VIDEO_PROTECT_WRITEAccess */ + u32 McVideoProtectWriteAccess; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL. + SEC_CARVEOUT_WRITEAccess */ + u32 McSecCarveoutProtectWriteAccess; + + /* Write-Protect Regions (WPR) */ + u32 McGeneralizedCarveout1Bom; + u32 McGeneralizedCarveout1BomHi; + u32 McGeneralizedCarveout1Size128kb; + u32 McGeneralizedCarveout1Access0; + u32 McGeneralizedCarveout1Access1; + u32 McGeneralizedCarveout1Access2; + u32 McGeneralizedCarveout1Access3; + u32 McGeneralizedCarveout1Access4; + u32 McGeneralizedCarveout1ForceInternalAccess0; + u32 McGeneralizedCarveout1ForceInternalAccess1; + u32 McGeneralizedCarveout1ForceInternalAccess2; + u32 McGeneralizedCarveout1ForceInternalAccess3; + u32 McGeneralizedCarveout1ForceInternalAccess4; + u32 McGeneralizedCarveout1Cfg0; + + u32 McGeneralizedCarveout2Bom; + u32 McGeneralizedCarveout2BomHi; + u32 McGeneralizedCarveout2Size128kb; + u32 McGeneralizedCarveout2Access0; + u32 McGeneralizedCarveout2Access1; + u32 McGeneralizedCarveout2Access2; + u32 McGeneralizedCarveout2Access3; + u32 McGeneralizedCarveout2Access4; + u32 McGeneralizedCarveout2ForceInternalAccess0; + u32 McGeneralizedCarveout2ForceInternalAccess1; + u32 McGeneralizedCarveout2ForceInternalAccess2; + u32 McGeneralizedCarveout2ForceInternalAccess3; + u32 McGeneralizedCarveout2ForceInternalAccess4; + u32 McGeneralizedCarveout2Cfg0; + + u32 McGeneralizedCarveout3Bom; + u32 McGeneralizedCarveout3BomHi; + u32 McGeneralizedCarveout3Size128kb; + u32 McGeneralizedCarveout3Access0; + u32 McGeneralizedCarveout3Access1; + u32 McGeneralizedCarveout3Access2; + u32 McGeneralizedCarveout3Access3; + u32 McGeneralizedCarveout3Access4; + u32 McGeneralizedCarveout3ForceInternalAccess0; + u32 McGeneralizedCarveout3ForceInternalAccess1; + u32 McGeneralizedCarveout3ForceInternalAccess2; + u32 McGeneralizedCarveout3ForceInternalAccess3; + u32 McGeneralizedCarveout3ForceInternalAccess4; + u32 McGeneralizedCarveout3Cfg0; + + u32 McGeneralizedCarveout4Bom; + u32 McGeneralizedCarveout4BomHi; + u32 McGeneralizedCarveout4Size128kb; + u32 McGeneralizedCarveout4Access0; + u32 McGeneralizedCarveout4Access1; + u32 McGeneralizedCarveout4Access2; + u32 McGeneralizedCarveout4Access3; + u32 McGeneralizedCarveout4Access4; + u32 McGeneralizedCarveout4ForceInternalAccess0; + u32 McGeneralizedCarveout4ForceInternalAccess1; + u32 McGeneralizedCarveout4ForceInternalAccess2; + u32 McGeneralizedCarveout4ForceInternalAccess3; + u32 McGeneralizedCarveout4ForceInternalAccess4; + u32 McGeneralizedCarveout4Cfg0; + + u32 McGeneralizedCarveout5Bom; + u32 McGeneralizedCarveout5BomHi; + u32 McGeneralizedCarveout5Size128kb; + u32 McGeneralizedCarveout5Access0; + u32 McGeneralizedCarveout5Access1; + u32 McGeneralizedCarveout5Access2; + u32 McGeneralizedCarveout5Access3; + u32 McGeneralizedCarveout5Access4; + u32 McGeneralizedCarveout5ForceInternalAccess0; + u32 McGeneralizedCarveout5ForceInternalAccess1; + u32 McGeneralizedCarveout5ForceInternalAccess2; + u32 McGeneralizedCarveout5ForceInternalAccess3; + u32 McGeneralizedCarveout5ForceInternalAccess4; + u32 McGeneralizedCarveout5Cfg0; + + /* Specifies enable for CA training */ + u32 EmcCaTrainingEnable; + + /* Set if bit 6 select is greater than bit 7 select; uses aremc. + spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 SwizzleRankByteEncode; + /* Specifies enable and offset for patched boot ROM write */ + u32 BootRomPatchControl; + /* Specifies data for patched boot ROM write */ + u32 BootRomPatchData; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 McMtsCarveoutBom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 McMtsCarveoutAdrHi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 McMtsCarveoutSizeMb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 McMtsCarveoutRegCtrl; + + /* End */ +}; + +#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ */ diff --git a/ariane/src/bdk/mem/sdram_param_t210.h b/ariane/src/bdk/mem/sdram_param_t210.h new file mode 100644 index 0000000..4c6c60a --- /dev/null +++ b/ariane/src/bdk/mem/sdram_param_t210.h @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * See file CREDITS for list of people who contributed to this + * project. + */ + +/** + * Defines the SDRAM parameter structure. + * + * Note that PLLM is used by EMC. + */ + +#ifndef _SDRAM_PARAM_T210_H_ +#define _SDRAM_PARAM_T210_H_ + +#define MEMORY_TYPE_NONE 0 +#define MEMORY_TYPE_DDR 0 +#define MEMORY_TYPE_LPDDR 0 +#define MEMORY_TYPE_DDR2 0 +#define MEMORY_TYPE_LPDDR2 1 +#define MEMORY_TYPE_DDR3L 2 +#define MEMORY_TYPE_LPDDR4 3 + +/** + * Defines the SDRAM parameter structure + */ +typedef struct _sdram_params +{ + /* Specifies the type of memory device */ + u32 memory_type; + + /* MC/EMC clock source configuration */ + + /* Specifies the M value for PllM */ + u32 pllm_input_divider; + /* Specifies the N value for PllM */ + u32 pllm_feedback_divider; + /* Specifies the time to wait for PLLM to lock (in microseconds) */ + u32 pllm_stable_time; + /* Specifies misc. control bits */ + u32 pllm_setup_control; + /* Specifies the P value for PLLM */ + u32 pllm_post_divider; + /* Specifies value for Charge Pump Gain Control */ + u32 pllm_kcp; + /* Specifies VCO gain */ + u32 pllm_kvco; + /* Spare BCT param */ + u32 emc_bct_spare0; + /* Spare BCT param */ + u32 emc_bct_spare1; + /* Spare BCT param */ + u32 emc_bct_spare2; + /* Spare BCT param */ + u32 emc_bct_spare3; + /* Spare BCT param */ + u32 emc_bct_spare4; + /* Spare BCT param */ + u32 emc_bct_spare5; + /* Spare BCT param */ + u32 emc_bct_spare6; + /* Spare BCT param */ + u32 emc_bct_spare7; + /* Spare BCT param */ + u32 emc_bct_spare8; + /* Spare BCT param */ + u32 emc_bct_spare9; + /* Spare BCT param */ + u32 emc_bct_spare10; + /* Spare BCT param */ + u32 emc_bct_spare11; + /* Spare BCT param */ + u32 emc_bct_spare12; + /* Spare BCT param */ + u32 emc_bct_spare13; + + /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ + u32 emc_clock_source; + u32 emc_clock_source_dll; + + /* Defines possible override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override; + /* enables override for PLLLM_MISC2 */ + u32 clk_rst_pllm_misc20_override_enable; + /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ + u32 clear_clock2_mc1; + + /* Auto-calibration of EMC pads */ + + /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ + u32 emc_auto_cal_interval; + /* + * Specifies the value for EMC_AUTO_CAL_CONFIG + * Note: Trigger bits are set by the SDRAM code. + */ + u32 emc_auto_cal_config; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ + u32 emc_auto_cal_config2; + + /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ + u32 emc_auto_cal_config3; + u32 emc_auto_cal_config4; + u32 emc_auto_cal_config5; + u32 emc_auto_cal_config6; + u32 emc_auto_cal_config7; + u32 emc_auto_cal_config8; + /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ + u32 emc_auto_cal_vref_sel0; + u32 emc_auto_cal_vref_sel1; + + /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ + u32 emc_auto_cal_channel; + + /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ + u32 emc_pmacro_auto_cal_cfg0; + u32 emc_pmacro_auto_cal_cfg1; + u32 emc_pmacro_auto_cal_cfg2; + + u32 emc_pmacro_rx_term; + u32 emc_pmacro_dq_tx_drive; + u32 emc_pmacro_ca_tx_drive; + u32 emc_pmacro_cmd_tx_drive; + u32 emc_pmacro_auto_cal_common; + u32 emc_pmacro_zcrtl; + + /* + * Specifies the time for the calibration + * to stabilize (in microseconds) + */ + u32 emc_auto_cal_wait; + + u32 emc_xm2_comp_pad_ctrl; + u32 emc_xm2_comp_pad_ctrl2; + u32 emc_xm2_comp_pad_ctrl3; + + /* + * DRAM size information + * Specifies the value for EMC_ADR_CFG + */ + u32 emc_adr_cfg; + + /* + * Specifies the time to wait after asserting pin + * CKE (in microseconds) + */ + u32 emc_pin_program_wait; + /* Specifies the extra delay before/after pin RESET/CKE command */ + u32 emc_pin_extra_wait; + + u32 emc_pin_gpio_enable; + u32 emc_pin_gpio; + + /* + * Specifies the extra delay after the first writing + * of EMC_TIMING_CONTROL + */ + u32 emc_timing_control_wait; + + /* Timing parameters required for the SDRAM */ + + /* Specifies the value for EMC_RC */ + u32 emc_rc; + /* Specifies the value for EMC_RFC */ + u32 emc_rfc; + + u32 emc_rfc_pb; + u32 emc_ref_ctrl2; + + /* Specifies the value for EMC_RFC_SLR */ + u32 emc_rfc_slr; + /* Specifies the value for EMC_RAS */ + u32 emc_ras; + /* Specifies the value for EMC_RP */ + u32 emc_rp; + /* Specifies the value for EMC_R2R */ + u32 emc_r2r; + /* Specifies the value for EMC_W2W */ + u32 emc_w2w; + /* Specifies the value for EMC_R2W */ + u32 emc_r2w; + /* Specifies the value for EMC_W2R */ + u32 emc_w2r; + /* Specifies the value for EMC_R2P */ + u32 emc_r2p; + /* Specifies the value for EMC_W2P */ + u32 emc_w2p; + /* Specifies the value for EMC_RD_RCD */ + + u32 emc_tppd; + u32 emc_ccdmw; + + u32 emc_rd_rcd; + /* Specifies the value for EMC_WR_RCD */ + u32 emc_wr_rcd; + /* Specifies the value for EMC_RRD */ + u32 emc_rrd; + /* Specifies the value for EMC_REXT */ + u32 emc_rext; + /* Specifies the value for EMC_WEXT */ + u32 emc_wext; + /* Specifies the value for EMC_WDV */ + u32 emc_wdv; + + u32 emc_wdv_chk; + u32 emc_wsv; + u32 emc_wev; + + /* Specifies the value for EMC_WDV_MASK */ + u32 emc_wdv_mask; + + u32 emc_ws_duration; + u32 emc_we_duration; + + /* Specifies the value for EMC_QUSE */ + u32 emc_quse; + /* Specifies the value for EMC_QUSE_WIDTH */ + u32 emc_quse_width; + /* Specifies the value for EMC_IBDLY */ + u32 emc_ibdly; + + u32 emc_obdly; + + /* Specifies the value for EMC_EINPUT */ + u32 emc_einput; + /* Specifies the value for EMC_EINPUT_DURATION */ + u32 emc_einput_duration; + /* Specifies the value for EMC_PUTERM_EXTRA */ + u32 emc_puterm_extra; + /* Specifies the value for EMC_PUTERM_WIDTH */ + u32 emc_puterm_width; + + u32 emc_qrst; + u32 emc_qsafe; + u32 emc_rdv; + u32 emc_rdv_mask; + + u32 emc_rdv_early; + u32 emc_rdv_early_mask; + + /* Specifies the value for EMC_QPOP */ + u32 emc_qpop; + + /* Specifies the value for EMC_REFRESH */ + u32 emc_refresh; + /* Specifies the value for EMC_BURST_REFRESH_NUM */ + u32 emc_burst_refresh_num; + /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ + u32 emc_prerefresh_req_cnt; + /* Specifies the value for EMC_PDEX2WR */ + u32 emc_pdex2wr; + /* Specifies the value for EMC_PDEX2RD */ + u32 emc_pdex2rd; + /* Specifies the value for EMC_PCHG2PDEN */ + u32 emc_pchg2pden; + /* Specifies the value for EMC_ACT2PDEN */ + u32 emc_act2pden; + /* Specifies the value for EMC_AR2PDEN */ + u32 emc_ar2pden; + /* Specifies the value for EMC_RW2PDEN */ + u32 emc_rw2pden; + + u32 emc_cke2pden; + u32 emc_pdex2che; + u32 emc_pdex2mrr; + + /* Specifies the value for EMC_TXSR */ + u32 emc_txsr; + /* Specifies the value for EMC_TXSRDLL */ + u32 emc_txsr_dll; + /* Specifies the value for EMC_TCKE */ + u32 emc_tcke; + /* Specifies the value for EMC_TCKESR */ + u32 emc_tckesr; + /* Specifies the value for EMC_TPD */ + u32 emc_tpd; + /* Specifies the value for EMC_TFAW */ + u32 emc_tfaw; + /* Specifies the value for EMC_TRPAB */ + u32 emc_trpab; + /* Specifies the value for EMC_TCLKSTABLE */ + u32 emc_tclkstable; + /* Specifies the value for EMC_TCLKSTOP */ + u32 emc_tclkstop; + /* Specifies the value for EMC_TREFBW */ + u32 emc_trefbw; + + /* FBIO configuration values */ + + /* Specifies the value for EMC_FBIO_CFG5 */ + u32 emc_fbio_cfg5; + /* Specifies the value for EMC_FBIO_CFG7 */ + u32 emc_fbio_cfg7; + u32 emc_fbio_cfg8; + + /* Command mapping for CMD brick 0 */ + u32 emc_cmd_mapping_cmd0_0; + u32 emc_cmd_mapping_cmd0_1; + u32 emc_cmd_mapping_cmd0_2; + u32 emc_cmd_mapping_cmd1_0; + u32 emc_cmd_mapping_cmd1_1; + u32 emc_cmd_mapping_cmd1_2; + u32 emc_cmd_mapping_cmd2_0; + u32 emc_cmd_mapping_cmd2_1; + u32 emc_cmd_mapping_cmd2_2; + u32 emc_cmd_mapping_cmd3_0; + u32 emc_cmd_mapping_cmd3_1; + u32 emc_cmd_mapping_cmd3_2; + u32 emc_cmd_mapping_byte; + + /* Specifies the value for EMC_FBIO_SPARE */ + u32 emc_fbio_spare; + + /* Specifies the value for EMC_CFG_RSV */ + u32 emc_cfg_rsv; + + /* MRS command values */ + + /* Specifies the value for EMC_MRS */ + u32 emc_mrs; + /* Specifies the MP0 command to initialize mode registers */ + u32 emc_emrs; + /* Specifies the MP2 command to initialize mode registers */ + u32 emc_emrs2; + /* Specifies the MP3 command to initialize mode registers */ + u32 emc_emrs3; + /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ + u32 emc_mrw1; + /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ + u32 emc_mrw2; + /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ + u32 emc_mrw3; + /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ + u32 emc_mrw4; + + /* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */ + u32 emc_mrw6; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw8; + /* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */ + u32 emc_mrw9; + /* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */ + u32 emc_mrw10; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw12; + /* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */ + u32 emc_mrw13; + /* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */ + u32 emc_mrw14; + + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at cold boot + */ + u32 emc_mrw_extra; + /* + * Specifies the programming to extra LPDDR2 Mode Register + * at warm boot + */ + u32 emc_warm_boot_mrw_extra; + /* + * Specify the enable of extra Mode Register programming at + * warm boot + */ + u32 emc_warm_boot_extramode_reg_write_enable; + /* + * Specify the enable of extra Mode Register programming at + * cold boot + */ + u32 emc_extramode_reg_write_enable; + + /* Specifies the EMC_MRW reset command value */ + u32 emc_mrw_reset_command; + /* Specifies the EMC Reset wait time (in microseconds) */ + u32 emc_mrw_reset_ninit_wait; + /* Specifies the value for EMC_MRS_WAIT_CNT */ + u32 emc_mrs_wait_cnt; + /* Specifies the value for EMC_MRS_WAIT_CNT2 */ + u32 emc_mrs_wait_cnt2; + + /* EMC miscellaneous configurations */ + + /* Specifies the value for EMC_CFG */ + u32 emc_cfg; + /* Specifies the value for EMC_CFG_2 */ + u32 emc_cfg2; + /* Specifies the pipe bypass controls */ + u32 emc_cfg_pipe; + + u32 emc_cfg_pipe_clk; + u32 emc_fdpd_ctrl_cmd_no_ramp; + u32 emc_cfg_update; + + /* Specifies the value for EMC_DBG */ + u32 emc_dbg; + + u32 emc_dbg_write_mux; + + /* Specifies the value for EMC_CMDQ */ + u32 emc_cmd_q; + /* Specifies the value for EMC_MC2EMCQ */ + u32 emc_mc2emc_q; + /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ + u32 emc_dyn_self_ref_control; + + /* Specifies the value for MEM_INIT_DONE */ + u32 ahb_arbitration_xbar_ctrl_meminit_done; + + /* Specifies the value for EMC_CFG_DIG_DLL */ + u32 emc_cfg_dig_dll; + u32 emc_cfg_dig_dll_1; + + /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ + u32 emc_cfg_dig_dll_period; + /* Specifies the value of *DEV_SELECTN of various EMC registers */ + u32 emc_dev_select; + + /* Specifies the value for EMC_SEL_DPD_CTRL */ + u32 emc_sel_dpd_ctrl; + + /* Pads trimmer delays */ + u32 emc_fdpd_ctrl_dq; + u32 emc_fdpd_ctrl_cmd; + u32 emc_pmacro_ib_vref_dq_0; + u32 emc_pmacro_ib_vref_dq_1; + u32 emc_pmacro_ib_vref_dqs_0; + u32 emc_pmacro_ib_vref_dqs_1; + u32 emc_pmacro_ib_rxrt; + u32 emc_cfg_pipe1; + u32 emc_cfg_pipe2; + + /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ + u32 emc_pmacro_quse_ddll_rank0_0; + u32 emc_pmacro_quse_ddll_rank0_1; + u32 emc_pmacro_quse_ddll_rank0_2; + u32 emc_pmacro_quse_ddll_rank0_3; + u32 emc_pmacro_quse_ddll_rank0_4; + u32 emc_pmacro_quse_ddll_rank0_5; + u32 emc_pmacro_quse_ddll_rank1_0; + u32 emc_pmacro_quse_ddll_rank1_1; + u32 emc_pmacro_quse_ddll_rank1_2; + u32 emc_pmacro_quse_ddll_rank1_3; + u32 emc_pmacro_quse_ddll_rank1_4; + u32 emc_pmacro_quse_ddll_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dq_rank0_0; + u32 emc_pmacro_ob_ddll_long_dq_rank0_1; + u32 emc_pmacro_ob_ddll_long_dq_rank0_2; + u32 emc_pmacro_ob_ddll_long_dq_rank0_3; + u32 emc_pmacro_ob_ddll_long_dq_rank0_4; + u32 emc_pmacro_ob_ddll_long_dq_rank0_5; + u32 emc_pmacro_ob_ddll_long_dq_rank1_0; + u32 emc_pmacro_ob_ddll_long_dq_rank1_1; + u32 emc_pmacro_ob_ddll_long_dq_rank1_2; + u32 emc_pmacro_ob_ddll_long_dq_rank1_3; + u32 emc_pmacro_ob_ddll_long_dq_rank1_4; + u32 emc_pmacro_ob_ddll_long_dq_rank1_5; + + u32 emc_pmacro_ob_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank0_5; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_3; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_4; + u32 emc_pmacro_ob_ddll_long_dqs_rank1_5; + + u32 emc_pmacro_ib_ddll_long_dqs_rank0_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank0_3; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_0; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_1; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_2; + u32 emc_pmacro_ib_ddll_long_dqs_rank1_3; + + u32 emc_pmacro_ddll_long_cmd_0; + u32 emc_pmacro_ddll_long_cmd_1; + u32 emc_pmacro_ddll_long_cmd_2; + u32 emc_pmacro_ddll_long_cmd_3; + u32 emc_pmacro_ddll_long_cmd_4; + u32 emc_pmacro_ddll_short_cmd_0; + u32 emc_pmacro_ddll_short_cmd_1; + u32 emc_pmacro_ddll_short_cmd_2; + + /* + * Specifies the delay after asserting CKE pin during a WarmBoot0 + * sequence (in microseconds) + */ + u32 warm_boot_wait; + + /* Specifies the value for EMC_ODT_WRITE */ + u32 emc_odt_write; + + /* Periodic ZQ calibration */ + + /* + * Specifies the value for EMC_ZCAL_INTERVAL + * Value 0 disables ZQ calibration + */ + u32 emc_zcal_interval; + /* Specifies the value for EMC_ZCAL_WAIT_CNT */ + u32 emc_zcal_wait_cnt; + /* Specifies the value for EMC_ZCAL_MRW_CMD */ + u32 emc_zcal_mrw_cmd; + + /* DRAM initialization sequence flow control */ + + /* Specifies the MRS command value for resetting DLL */ + u32 emc_mrs_reset_dll; + /* Specifies the command for ZQ initialization of device 0 */ + u32 emc_zcal_init_dev0; + /* Specifies the command for ZQ initialization of device 1 */ + u32 emc_zcal_init_dev1; + /* + * Specifies the wait time after programming a ZQ initialization + * command (in microseconds) + */ + u32 emc_zcal_init_wait; + /* + * Specifies the enable for ZQ calibration at cold boot [bit 0] + * and warm boot [bit 1] + */ + u32 emc_zcal_warm_cold_boot_enables; + + /* + * Specifies the MRW command to LPDDR2 for ZQ calibration + * on warmboot + */ + /* Is issued to both devices separately */ + u32 emc_mrw_lpddr2zcal_warm_boot; + /* + * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot + * Is issued to both devices separately + */ + u32 emc_zqcal_ddr3_warm_boot; + + u32 emc_zqcal_lpddr4_warm_boot; + + /* + * Specifies the wait time for ZQ calibration on warmboot + * (in microseconds) + */ + u32 emc_zcal_warm_boot_wait; + /* + * Specifies the enable for DRAM Mode Register programming + * at warm boot + */ + u32 emc_mrs_warm_boot_enable; + /* + * Specifies the wait time after sending an MRS DLL reset command + * in microseconds) + */ + u32 emc_mrs_reset_dll_wait; + /* Specifies the extra MRS command to initialize mode registers */ + u32 emc_mrs_extra; + /* Specifies the extra MRS command at warm boot */ + u32 emc_warm_boot_mrs_extra; + /* Specifies the EMRS command to enable the DDR2 DLL */ + u32 emc_emrs_ddr2_dll_enable; + /* Specifies the MRS command to reset the DDR2 DLL */ + u32 emc_mrs_ddr2_dll_reset; + /* Specifies the EMRS command to set OCD calibration */ + u32 emc_emrs_ddr2_ocd_calib; + /* + * Specifies the wait between initializing DDR and setting OCD + * calibration (in microseconds) + */ + u32 emc_ddr2_wait; + /* Specifies the value for EMC_CLKEN_OVERRIDE */ + u32 emc_clken_override; + /* + * Specifies LOG2 of the extra refresh numbers after booting + * Program 0 to disable + */ + u32 emc_extra_refresh_num; + /* Specifies the master override for all EMC clocks */ + u32 emc_clken_override_allwarm_boot; + /* Specifies the master override for all MC clocks */ + u32 mc_clken_override_allwarm_boot; + /* Specifies digital dll period, choosing between 4 to 64 ms */ + u32 emc_cfg_dig_dll_period_warm_boot; + + /* Pad controls */ + + /* Specifies the value for PMC_VDDP_SEL */ + u32 pmc_vddp_sel; + /* Specifies the wait time after programming PMC_VDDP_SEL */ + u32 pmc_vddp_sel_wait; + /* Specifies the value for PMC_DDR_PWR */ + u32 pmc_ddr_pwr; + /* Specifies the value for PMC_DDR_CFG */ + u32 pmc_ddr_cfg; + /* Specifies the value for PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req; + /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ + u32 pmc_io_dpd3_req_wait; + + u32 pmc_io_dpd4_req_wait; + + /* Specifies the value for PMC_REG_SHORT */ + u32 pmc_reg_short; + /* Specifies the value for PMC_NO_IOPOWER */ + u32 pmc_no_io_power; + + u32 pmc_ddr_ctrl_wait; + u32 pmc_ddr_ctrl; + + /* Specifies the value for EMC_ACPD_CONTROL */ + u32 emc_acpd_control; + + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ + u32 emc_swizzle_rank0_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ + u32 emc_swizzle_rank0_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ + u32 emc_swizzle_rank0_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ + u32 emc_swizzle_rank0_byte3; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ + u32 emc_swizzle_rank1_byte0; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ + u32 emc_swizzle_rank1_byte1; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ + u32 emc_swizzle_rank1_byte2; + /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ + u32 emc_swizzle_rank1_byte3; + + /* Specifies the value for EMC_TXDSRVTTGEN */ + u32 emc_txdsrvttgen; + + /* Specifies the value for EMC_DATA_BRLSHFT_0 */ + u32 emc_data_brlshft0; + u32 emc_data_brlshft1; + + u32 emc_dqs_brlshft0; + u32 emc_dqs_brlshft1; + + u32 emc_cmd_brlshft0; + u32 emc_cmd_brlshft1; + u32 emc_cmd_brlshft2; + u32 emc_cmd_brlshft3; + + u32 emc_quse_brlshft0; + u32 emc_quse_brlshft1; + u32 emc_quse_brlshft2; + u32 emc_quse_brlshft3; + + u32 emc_dll_cfg0; + u32 emc_dll_cfg1; + + u32 emc_pmc_scratch1; + u32 emc_pmc_scratch2; + u32 emc_pmc_scratch3; + + u32 emc_pmacro_pad_cfg_ctrl; + + u32 emc_pmacro_vttgen_ctrl0; + u32 emc_pmacro_vttgen_ctrl1; + u32 emc_pmacro_vttgen_ctrl2; + + u32 emc_pmacro_brick_ctrl_rfu1; + u32 emc_pmacro_cmd_brick_ctrl_fdpd; + u32 emc_pmacro_brick_ctrl_rfu2; + u32 emc_pmacro_data_brick_ctrl_fdpd; + u32 emc_pmacro_bg_bias_ctrl0; + u32 emc_pmacro_data_pad_rx_ctrl; + u32 emc_pmacro_cmd_pad_rx_ctrl; + u32 emc_pmacro_data_rx_term_mode; + u32 emc_pmacro_cmd_rx_term_mode; + u32 emc_pmacro_data_pad_tx_ctrl; + u32 emc_pmacro_common_pad_tx_ctrl; + u32 emc_pmacro_cmd_pad_tx_ctrl; + u32 emc_cfg3; + + u32 emc_pmacro_tx_pwrd0; + u32 emc_pmacro_tx_pwrd1; + u32 emc_pmacro_tx_pwrd2; + u32 emc_pmacro_tx_pwrd3; + u32 emc_pmacro_tx_pwrd4; + u32 emc_pmacro_tx_pwrd5; + + u32 emc_config_sample_delay; + + u32 emc_pmacro_brick_mapping0; + u32 emc_pmacro_brick_mapping1; + u32 emc_pmacro_brick_mapping2; + + u32 emc_pmacro_tx_sel_clk_src0; + u32 emc_pmacro_tx_sel_clk_src1; + u32 emc_pmacro_tx_sel_clk_src2; + u32 emc_pmacro_tx_sel_clk_src3; + u32 emc_pmacro_tx_sel_clk_src4; + u32 emc_pmacro_tx_sel_clk_src5; + + u32 emc_pmacro_ddll_bypass; + + u32 emc_pmacro_ddll_pwrd0; + u32 emc_pmacro_ddll_pwrd1; + u32 emc_pmacro_ddll_pwrd2; + + u32 emc_pmacro_cmd_ctrl0; + u32 emc_pmacro_cmd_ctrl1; + u32 emc_pmacro_cmd_ctrl2; + + /* DRAM size information */ + + /* Specifies the value for MC_EMEM_ADR_CFG */ + u32 mc_emem_adr_cfg; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ + u32 mc_emem_adr_cfg_dev0; + /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ + u32 mc_emem_adr_cfg_dev1; + + u32 mc_emem_adr_cfg_channel_mask; + + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */ + u32 mc_emem_adr_cfg_bank_mask0; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ + u32 mc_emem_adr_cfg_bank_mask1; + /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ + u32 mc_emem_adr_cfg_bank_mask2; + + /* + * Specifies the value for MC_EMEM_CFG which holds the external memory + * size (in KBytes) + */ + u32 mc_emem_cfg; + + /* MC arbitration configuration */ + + /* Specifies the value for MC_EMEM_ARB_CFG */ + u32 mc_emem_arb_cfg; + /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ + u32 mc_emem_arb_outstanding_req; + + u32 emc_emem_arb_refpb_hp_ctrl; + u32 emc_emem_arb_refpb_bank_ctrl; + + /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ + u32 mc_emem_arb_timing_rcd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ + u32 mc_emem_arb_timing_rp; + /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ + u32 mc_emem_arb_timing_rc; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ + u32 mc_emem_arb_timing_ras; + /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ + u32 mc_emem_arb_timing_faw; + /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ + u32 mc_emem_arb_timing_rrd; + /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ + u32 mc_emem_arb_timing_rap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ + u32 mc_emem_arb_timing_wap2pre; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ + u32 mc_emem_arb_timing_r2r; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ + u32 mc_emem_arb_timing_w2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ + u32 mc_emem_arb_timing_r2w; + /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ + u32 mc_emem_arb_timing_w2r; + + u32 mc_emem_arb_timing_rfcpb; + + /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ + u32 mc_emem_arb_da_turns; + /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ + u32 mc_emem_arb_da_covers; + /* Specifies the value for MC_EMEM_ARB_MISC0 */ + u32 mc_emem_arb_misc0; + /* Specifies the value for MC_EMEM_ARB_MISC1 */ + u32 mc_emem_arb_misc1; + u32 mc_emem_arb_misc2; + + /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ + u32 mc_emem_arb_ring1_throttle; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ + u32 mc_emem_arb_override; + /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ + u32 mc_emem_arb_override1; + /* Specifies the value for MC_EMEM_ARB_RSV */ + u32 mc_emem_arb_rsv; + + u32 mc_da_cfg0; + u32 mc_emem_arb_timing_ccdmw; + + /* Specifies the value for MC_CLKEN_OVERRIDE */ + u32 mc_clken_override; + + /* Specifies the value for MC_STAT_CONTROL */ + u32 mc_stat_control; + /* Specifies the value for MC_VIDEO_PROTECT_BOM */ + u32 mc_video_protect_bom; + /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ + u32 mc_video_protect_bom_adr_hi; + /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ + u32 mc_video_protect_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ + u32 mc_video_protect_vpr_override; + /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ + u32 mc_video_protect_vpr_override1; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ + u32 mc_video_protect_gpu_override0; + /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ + u32 mc_video_protect_gpu_override1; + /* Specifies the value for MC_SEC_CARVEOUT_BOM */ + u32 mc_sec_carveout_bom; + /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ + u32 mc_sec_carveout_adr_hi; + /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ + u32 mc_sec_carveout_size_mb; + /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */ + u32 mc_video_protect_write_access; + /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */ + u32 mc_sec_carveout_protect_write_access; + + u32 mc_generalized_carveout1_bom; + u32 mc_generalized_carveout1_bom_hi; + u32 mc_generalized_carveout1_size_128kb; + u32 mc_generalized_carveout1_access0; + u32 mc_generalized_carveout1_access1; + u32 mc_generalized_carveout1_access2; + u32 mc_generalized_carveout1_access3; + u32 mc_generalized_carveout1_access4; + u32 mc_generalized_carveout1_force_internal_access0; + u32 mc_generalized_carveout1_force_internal_access1; + u32 mc_generalized_carveout1_force_internal_access2; + u32 mc_generalized_carveout1_force_internal_access3; + u32 mc_generalized_carveout1_force_internal_access4; + u32 mc_generalized_carveout1_cfg0; + + u32 mc_generalized_carveout2_bom; + u32 mc_generalized_carveout2_bom_hi; + u32 mc_generalized_carveout2_size_128kb; + u32 mc_generalized_carveout2_access0; + u32 mc_generalized_carveout2_access1; + u32 mc_generalized_carveout2_access2; + u32 mc_generalized_carveout2_access3; + u32 mc_generalized_carveout2_access4; + u32 mc_generalized_carveout2_force_internal_access0; + u32 mc_generalized_carveout2_force_internal_access1; + u32 mc_generalized_carveout2_force_internal_access2; + u32 mc_generalized_carveout2_force_internal_access3; + u32 mc_generalized_carveout2_force_internal_access4; + u32 mc_generalized_carveout2_cfg0; + + u32 mc_generalized_carveout3_bom; + u32 mc_generalized_carveout3_bom_hi; + u32 mc_generalized_carveout3_size_128kb; + u32 mc_generalized_carveout3_access0; + u32 mc_generalized_carveout3_access1; + u32 mc_generalized_carveout3_access2; + u32 mc_generalized_carveout3_access3; + u32 mc_generalized_carveout3_access4; + u32 mc_generalized_carveout3_force_internal_access0; + u32 mc_generalized_carveout3_force_internal_access1; + u32 mc_generalized_carveout3_force_internal_access2; + u32 mc_generalized_carveout3_force_internal_access3; + u32 mc_generalized_carveout3_force_internal_access4; + u32 mc_generalized_carveout3_cfg0; + + u32 mc_generalized_carveout4_bom; + u32 mc_generalized_carveout4_bom_hi; + u32 mc_generalized_carveout4_size_128kb; + u32 mc_generalized_carveout4_access0; + u32 mc_generalized_carveout4_access1; + u32 mc_generalized_carveout4_access2; + u32 mc_generalized_carveout4_access3; + u32 mc_generalized_carveout4_access4; + u32 mc_generalized_carveout4_force_internal_access0; + u32 mc_generalized_carveout4_force_internal_access1; + u32 mc_generalized_carveout4_force_internal_access2; + u32 mc_generalized_carveout4_force_internal_access3; + u32 mc_generalized_carveout4_force_internal_access4; + u32 mc_generalized_carveout4_cfg0; + + u32 mc_generalized_carveout5_bom; + u32 mc_generalized_carveout5_bom_hi; + u32 mc_generalized_carveout5_size_128kb; + u32 mc_generalized_carveout5_access0; + u32 mc_generalized_carveout5_access1; + u32 mc_generalized_carveout5_access2; + u32 mc_generalized_carveout5_access3; + u32 mc_generalized_carveout5_access4; + u32 mc_generalized_carveout5_force_internal_access0; + u32 mc_generalized_carveout5_force_internal_access1; + u32 mc_generalized_carveout5_force_internal_access2; + u32 mc_generalized_carveout5_force_internal_access3; + u32 mc_generalized_carveout5_force_internal_access4; + u32 mc_generalized_carveout5_cfg0; + + /* Specifies enable for CA training */ + u32 emc_ca_training_enable; + /* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */ + u32 swizzle_rank_byte_encode; + /* Specifies enable and offset for patched boot rom write */ + u32 boot_rom_patch_control; + /* Specifies data for patched boot rom write */ + u32 boot_rom_patch_data; + + /* Specifies the value for MC_MTS_CARVEOUT_BOM */ + u32 mc_mts_carveout_bom; + /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ + u32 mc_mts_carveout_adr_hi; + /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ + u32 mc_mts_carveout_size_mb; + /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ + u32 mc_mts_carveout_reg_ctrl; +} sdram_params_t; + +#endif diff --git a/ariane/src/bdk/mem/smmu.c b/ariane/src/bdk/mem/smmu.c new file mode 100644 index 0000000..6ee99b9 --- /dev/null +++ b/ariane/src/bdk/mem/smmu.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include + +bool smmu_used = false; +u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR; + +//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1; +u8 smmu_payload[] __attribute__((aligned(16))) = { + 0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010 + 0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1 + 0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1] + 0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS + 0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH + 0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop + 0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0 + 0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1] + 0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000 + 0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0 + 0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG + 0x00, 0x00, 0x00, 0x00, // 0x2C: + 0x00, 0x00, 0x00, 0x00, // 0x30: secmon address + 0x00, 0x00, 0x00, 0x00 // 0x34: +}; + +void *page_alloc(u32 num) +{ + u8 *res = _pageheap; + _pageheap += 0x1000 * num; + memset(res, 0, 0x1000 * num); + return res; +} + +u32 *smmu_alloc_pdir() +{ + u32 *pdir = (u32 *)page_alloc(1); + for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) + pdir[pdn] = _PDE_VACANT(pdn); + return pdir; +} + +void smmu_flush_regs() +{ + (void)MC(MC_SMMU_PTB_DATA); +} + +void smmu_flush_all() +{ + MC(MC_SMMU_PTC_FLUSH) = 0; + smmu_flush_regs(); + MC(MC_SMMU_TLB_FLUSH) = 0; + smmu_flush_regs(); +} + +void smmu_init(u32 secmon_base) +{ + MC(MC_SMMU_PTB_ASID) = 0; + MC(MC_SMMU_PTB_DATA) = 0; + MC(MC_SMMU_TLB_CONFIG) = 0x30000030; + MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F; + MC(MC_SMMU_PTC_FLUSH) = 0; + MC(MC_SMMU_TLB_FLUSH) = 0; + + // Set the secmon address + *(u32 *)(smmu_payload + 0x30) = secmon_base; +} + +void smmu_enable() +{ + if (smmu_used) + return; + + ccplex_boot_cpu0((u32)smmu_payload); + smmu_used = true; + msleep(150); + + smmu_flush_all(); +} + +bool smmu_is_used() +{ + return smmu_used; +} + +void smmu_exit() +{ + *(u32 *)(smmu_payload + 0x14) = _NOP(); +} + +u32 *smmu_init_domain4(u32 dev_base, u32 asid) +{ + u32 *pdir = smmu_alloc_pdir(); + + MC(MC_SMMU_PTB_ASID) = asid; + MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR); + smmu_flush_regs(); + + MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid); + smmu_flush_regs(); + + return pdir; +} + +u32 *smmu_get_pte(u32 *pdir, u32 iova) +{ + u32 ptn = SMMU_ADDR_TO_PFN(iova); + u32 pdn = SMMU_ADDR_TO_PDN(iova); + u32 *ptbl; + + if (pdir[pdn] != _PDE_VACANT(pdn)) + ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT); + else + { + ptbl = (u32 *)page_alloc(1); + u32 addr = SMMU_PDN_TO_ADDR(pdn); + for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE) + ptbl[pn] = _PTE_VACANT(addr); + pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT); + smmu_flush_all(); + } + + return &ptbl[ptn % SMMU_PTBL_COUNT]; +} + +void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr) +{ + for (int i = 0; i < cnt; i++) + { + u32 *pte = smmu_get_pte(pdir, addr); + *pte = SMMU_ADDR_TO_PFN(page) | attr; + addr += 0x1000; + page += 0x1000; + } + smmu_flush_all(); +} + +u32 *smmu_init_for_tsec() +{ + return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1); +} + +void smmu_deinit_for_tsec() +{ + MC(MC_SMMU_PTB_ASID) = 1; + MC(MC_SMMU_PTB_DATA) = 0; + MC(MC_SMMU_TSEC_ASID) = 0; + smmu_flush_regs(); +} + diff --git a/ariane/src/bdk/mem/smmu.h b/ariane/src/bdk/mem/smmu.h new file mode 100644 index 0000000..7846253 --- /dev/null +++ b/ariane/src/bdk/mem/smmu.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#define SMMU_HEAP_ADDR 0xA0000000 + +#define MC_INTSTATUS 0x0 +#define MC_INTMASK 0x4 +#define MC_ERR_STATUS 0x8 +#define MC_ERR_ADR 0xc +#define MC_SMMU_CONFIG 0x10 +#define MC_SMMU_TLB_CONFIG 0x14 +#define MC_SMMU_PTC_CONFIG 0x18 +#define MC_SMMU_PTB_ASID 0x1c +#define MC_SMMU_PTB_DATA 0x20 +#define MC_SMMU_TLB_FLUSH 0x30 +#define MC_SMMU_PTC_FLUSH 0x34 +#define MC_SMMU_ASID_SECURITY 0x38 +#define MC_SMMU_TSEC_ASID 0x294 +#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 +#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c +#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 +#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 +#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 + +#define SMMU_PDE_NEXT_SHIFT 28 +#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29 +#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30 +#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31 +#define SMMU_PAGE_SHIFT 12 +#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) +#define SMMU_PDIR_COUNT 1024 +#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT) +#define SMMU_PTBL_COUNT 1024 +#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT) +#define SMMU_PDIR_SHIFT 12 +#define SMMU_PDE_SHIFT 12 +#define SMMU_PTE_SHIFT 12 +#define SMMU_PFN_MASK 0x000FFFFF +#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) +#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) +#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22) +#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT) +#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT) +#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT) +#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT) +#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE) +#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE) +#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE) +#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR) +#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE) +#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR) +#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr)) +#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr)) + +void *page_alloc(u32 num); +u32 *smmu_alloc_pdir(); +void smmu_flush_regs(); +void smmu_flush_all(); +void smmu_init(u32 secmon_base); +void smmu_enable(); +bool smmu_is_used(); +void smmu_exit(); +u32 *smmu_init_domain4(u32 dev_base, u32 asid); +u32 *smmu_get_pte(u32 *pdir, u32 iova); +void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr); +u32 *smmu_init_for_tsec(); +void smmu_deinit_for_tsec(); diff --git a/ariane/src/bdk/memory_map.h b/ariane/src/bdk/memory_map.h new file mode 100644 index 0000000..f45269a --- /dev/null +++ b/ariane/src/bdk/memory_map.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MEMORY_MAP_H_ +#define _MEMORY_MAP_H_ + +//#define IPL_STACK_TOP 0x4003FF00 +/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ +/* --- IPL: 0x40008000 - 0x40028000 --- */ +#define IPL_LOAD_ADDR 0x40008000 +#define IPL_SZ_MAX 0x20000 // 128KB. +//#define IRAM_LIB_ADDR 0x4002B000 +#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. +#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32. + +/* --- DRAM START --- */ +#define DRAM_START 0x80000000 +#define HOS_RSVD 0x1000000 // Do not write anything in this area. + +#define NYX_LOAD_ADDR 0x81000000 +#define NYX_SZ_MAX 0x1000000 // 16MB +/* --- Gap: 0x82000000 - 0x82FFFFFF --- */ + +/* Stack theoretical max: 33MB */ +#define IPL_STACK_TOP 0x83100000 +#define IPL_HEAP_START 0x84000000 +#define IPL_HEAP_SZ 0x20000000 // 512MB. +/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */ + +// Virtual disk / Chainloader buffers. +#define RAM_DISK_ADDR 0xA4000000 +#define RAM_DISK_SZ 0x41000000 // 1040MB. + +//#define DRAM_LIB_ADDR 0xE0000000 +/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. + +// SDMMC DMA buffers 1 +#define SDMMC_UPPER_BUFFER 0xE5000000 +#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. + +// Nyx buffers. +#define NYX_STORAGE_ADDR 0xED000000 +#define NYX_RES_ADDR 0xEE000000 +#define NYX_RES_SZ 0x1000000 // 16MB. + +// SDMMC DMA buffers 2 +#define SDXC_BUF_ALIGNED 0xEF000000 +#define MIXD_BUF_ALIGNED 0xF0000000 +#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED +#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). + +// Nyx LvGL buffers. +#define NYX_LV_VDB_ADR 0xF1000000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. +#define NYX_LV_MEM_ADR 0xF1400000 +#define NYX_LV_MEM_SZ 0x6600000 // 70MB. + +// Framebuffer addresses. +#define IPL_FB_ADDRESS 0xF5A00000 +#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. +#define LOG_FB_ADDRESS 0xF5E00000 +#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. +#define NYX_FB_ADDRESS 0xF6200000 +#define NYX_FB2_ADDRESS 0xF6600000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. + +#define DRAM_MEM_HOLE_ADR 0xF6A00000 +#define DRAM_MEM_HOLE_SZ 0x8140000 +/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */ +#define DRAM_START2 0xFEB40000 + +// NX BIS driver sector cache. +#define NX_BIS_CACHE_ADDR 0xFEE00000 +#define NX_BIS_CACHE_SZ 0x100000 + +// USB buffers. +#define USBD_ADDR 0xFEF00000 +#define USB_DESCRIPTOR_ADDR 0xFEF40000 +#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000 +#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000 +#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000 +#define USB_EP_BULK_OUT_MAX_XFER 0x800000 + +// #define EXT_PAYLOAD_ADDR 0xC0000000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - rom_size) + +#endif diff --git a/ariane/src/bdk/module.h b/ariane/src/bdk/module.h new file mode 100644 index 0000000..6ec303f --- /dev/null +++ b/ariane/src/bdk/module.h @@ -0,0 +1,41 @@ +/* + * Common Module Header + * Copyright (c) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef _MODULE_H_ +#define _MODULE_H_ + +#include +#include + +// Module Callback +typedef void (*cbMainModule_t)(const char *s); +typedef void (*memcpy_t)(void *, void *, size_t); +typedef void (*memset_t)(void *, int, size_t); + +typedef struct _bdkParams_t +{ + void *gfxCon; + void *gfxCtx; + heap_t *sharedHeap; + memcpy_t memcpy; + memset_t memset; +} *bdkParams_t; + +// Module Entrypoint +typedef void (*moduleEntrypoint_t)(void *, bdkParams_t); + +#endif diff --git a/ariane/src/bdk/power/bq24193.c b/ariane/src/bdk/power/bq24193.c new file mode 100644 index 0000000..2b2e744 --- /dev/null +++ b/ariane/src/bdk/power/bq24193.c @@ -0,0 +1,178 @@ +/* + * Battery charger driver for Nintendo Switch's TI BQ24193 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "bq24193.h" +#include +#include + +static u8 bq24193_get_reg(u8 reg) +{ + return i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg); +} + +int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) +{ + u8 data; + + switch (prop) { + case BQ24193_InputVoltageLimit: // Input voltage limit (mV). + data = bq24193_get_reg(BQ24193_InputSource); + data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; + *value = 0; + *value += ((data >> 0) & 1) ? 80 : 0; + *value += ((data >> 1) & 1) ? 160 : 0; + *value += ((data >> 2) & 1) ? 320 : 0; + *value += ((data >> 3) & 1) ? 640 : 0; + *value += 3880; + break; + case BQ24193_InputCurrentLimit: // Input current limit (mA). + data = bq24193_get_reg(BQ24193_InputSource); + data &= BQ24193_INCONFIG_INLIMIT_MASK; + switch (data) + { + case 0: + *value = 100; + break; + case 1: + *value = 150; + break; + case 2: + *value = 500; + break; + case 3: + *value = 900; + break; + case 4: + *value = 1200; + break; + case 5: + *value = 1500; + break; + case 6: + *value = 2000; + break; + case 7: + *value = 3000; + break; + } + break; + case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). + data = bq24193_get_reg(BQ24193_PORConfig); + *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; + *value *= 100; + *value += 3000; + break; + case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). + data = bq24193_get_reg(BQ24193_ChrgCurr); + data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 64 : 0; + *value += ((data >> 1) & 1) ? 128 : 0; + *value += ((data >> 2) & 1) ? 256 : 0; + *value += ((data >> 3) & 1) ? 512 : 0; + *value += ((data >> 4) & 1) ? 1024 : 0; + *value += ((data >> 5) & 1) ? 2048 : 0; + *value += 512; + data = bq24193_get_reg(BQ24193_ChrgCurr); + data &= BQ24193_CHRGCURR_20PCT_MASK; + if (data) + *value = *value * 20 / 100; // Fast charge current limit is 20%. + break; + case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data = (data & BQ24193_CHRGVOLT_VREG) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 16 : 0; + *value += ((data >> 1) & 1) ? 32 : 0; + *value += ((data >> 2) & 1) ? 64 : 0; + *value += ((data >> 3) & 1) ? 128 : 0; + *value += ((data >> 4) & 1) ? 256 : 0; + *value += ((data >> 5) & 1) ? 512 : 0; + *value += 3504; + break; + case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data &= BQ24193_IRTHERMAL_THERM_MASK; + if (data) + *value = 300; + else + *value = 100; + break; + case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). + data = bq24193_get_reg(BQ24193_IRCompThermal); + data &= BQ24193_IRTHERMAL_THERM_MASK; + switch (data) + { + case 0: + *value = 60; + break; + case 1: + *value = 80; + break; + case 2: + *value = 100; + break; + case 3: + *value = 120; + break; + } + break; + case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done + data = bq24193_get_reg(BQ24193_Status); + *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; + break; + case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. + data = bq24193_get_reg(BQ24193_FaultReg); + *value = data & BQ24193_FAULT_THERM_MASK; + break; + case BQ24193_DevID: // Dev ID. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = data & BQ24193_VENDORPART_DEV_MASK; + break; + case BQ24193_ProductNumber: // Product number. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; + break; + default: + return -1; + } + return 0; +} + +void bq24193_enable_charger() +{ + u8 reg = bq24193_get_reg(BQ24193_PORConfig); + + reg &= ~BQ24193_PORCONFIG_CHGCONFIG_MASK; + reg |= BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN; + + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg); +} + +void bq24193_fake_battery_removal() +{ + // Disable watchdog to keep BATFET disabled. + u8 value = bq24193_get_reg(BQ24193_ChrgTermTimer); + value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK; + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value); + + // Force BATFET to disabled state. This disconnects the battery from the system. + value = bq24193_get_reg(BQ24193_Misc); + value |= BQ24193_MISC_BATFET_DI_MASK; + i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value); +} diff --git a/ariane/src/bdk/power/bq24193.h b/ariane/src/bdk/power/bq24193.h new file mode 100644 index 0000000..1b6e717 --- /dev/null +++ b/ariane/src/bdk/power/bq24193.h @@ -0,0 +1,121 @@ +/* + * Battery charger driver for Nintendo Switch's TI BQ24193 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __BQ24193_H_ +#define __BQ24193_H_ + +#define BQ24193_I2C_ADDR 0x6B + +// REG 0 masks. +#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0) +#define BQ24193_INCONFIG_VINDPM_MASK 0x78 +#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7) + +// REG 1 masks. +#define BQ24193_PORCONFIG_BOOST_MASK (1<<0) +#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1) +#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4) +#define BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN (1<<4) +#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6) +#define BQ24193_PORCONFIG_RESET_MASK (1<<7) + +// REG 2 masks. +#define BQ24193_CHRGCURR_20PCT_MASK (1<<0) +#define BQ24193_CHRGCURR_ICHG_MASK 0xFC + +// REG 3 masks. +#define BQ24193_PRECHRG_ITERM 0x0F +#define BQ24193_PRECHRG_IPRECHG 0xF0 + +// REG 4 masks. +#define BQ24193_CHRGVOLT_VTHRES (1<<0) +#define BQ24193_CHRGVOLT_BATTLOW (1<<1) +#define BQ24193_CHRGVOLT_VREG 0xFC + +// REG 5 masks. +#define BQ24193_CHRGTERM_ISET_MASK (1<<0) +#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1) +#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3) +#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4) +#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6) +#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7) + +// REG 6 masks. +#define BQ24193_IRTHERMAL_THERM_MASK (3<<0) +#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2) +#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5) + +// REG 7 masks. +#define BQ24193_MISC_INT_MASK (3<<0) +#define BQ24193_MISC_VSET_MASK (1<<4) +#define BQ24193_MISC_BATFET_DI_MASK (1<<5) +#define BQ24193_MISC_TMR2X_EN_MASK (1<<6) +#define BQ24193_MISC_DPDM_EN_MASK (1<<7) + +// REG 8 masks. +#define BQ24193_STATUS_VSYS_MASK (1<<0) +#define BQ24193_STATUS_THERM_MASK (1<<1) +#define BQ24193_STATUS_PG_MASK (1<<2) +#define BQ24193_STATUS_DPM_MASK (1<<3) +#define BQ24193_STATUS_CHRG_MASK (3<<4) +#define BQ24193_STATUS_VBUS_MASK (3<<6) + +// REG 9 masks. +#define BQ24193_FAULT_THERM_MASK (7<<0) +#define BQ24193_FAULT_BATT_OVP_MASK (1<<3) +#define BQ24193_FAULT_CHARGE_MASK (3<<4) +#define BQ24193_FAULT_BOOST_MASK (1<<6) +#define BQ24193_FAULT_WATCHDOG_MASK (1<<7) + +// REG A masks. +#define BQ24193_VENDORPART_DEV_MASK (3<<0) +#define BQ24193_VENDORPART_PN_MASK (7<<3) + +enum BQ24193_reg { + BQ24193_InputSource = 0x00, + BQ24193_PORConfig = 0x01, + BQ24193_ChrgCurr = 0x02, + BQ24193_PreChrgTerm = 0x03, + BQ24193_ChrgVolt = 0x04, + BQ24193_ChrgTermTimer = 0x05, + BQ24193_IRCompThermal = 0x06, + BQ24193_Misc = 0x07, + BQ24193_Status = 0x08, + BQ24193_FaultReg = 0x09, + BQ24193_VendorPart = 0x0A, +}; + +enum BQ24193_reg_prop { + BQ24193_InputVoltageLimit, // REG 0. + BQ24193_InputCurrentLimit, // REG 0. + BQ24193_SystemMinimumVoltage, // REG 1. + BQ24193_FastChargeCurrentLimit, // REG 2. + BQ24193_ChargeVoltageLimit, // REG 4. + BQ24193_RechargeThreshold, // REG 4. + BQ24193_ThermalRegulation, // REG 6. + BQ24193_ChargeStatus, // REG 8. + BQ24193_TempStatus, // REG 9. + BQ24193_DevID, // REG A. + BQ24193_ProductNumber, // REG A. +}; + +int bq24193_get_property(enum BQ24193_reg_prop prop, int *value); +void bq24193_enable_charger(); +void bq24193_fake_battery_removal(); + +#endif /* __BQ24193_H_ */ diff --git a/ariane/src/bdk/power/max17050.c b/ariane/src/bdk/power/max17050.c new file mode 100644 index 0000000..2491466 --- /dev/null +++ b/ariane/src/bdk/power/max17050.c @@ -0,0 +1,279 @@ +/* + * Fuel gauge driver for Nintendo Switch's Maxim 17050 + * + * Copyright (c) 2011 Samsung Electronics + * MyungJoo Ham + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max17040_battery.c + */ + +#include "max17050.h" +#include +#include + +/* Status register bits */ +#define STATUS_POR_BIT (1 << 1) +#define STATUS_BST_BIT (1 << 3) +#define STATUS_VMN_BIT (1 << 8) +#define STATUS_TMN_BIT (1 << 9) +#define STATUS_SMN_BIT (1 << 10) +#define STATUS_BI_BIT (1 << 11) +#define STATUS_VMX_BIT (1 << 12) +#define STATUS_TMX_BIT (1 << 13) +#define STATUS_SMX_BIT (1 << 14) +#define STATUS_BR_BIT (1 << 15) + +#define VFSOC0_LOCK 0x0000 +#define VFSOC0_UNLOCK 0x0080 + +#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ + +static u32 battery_voltage = 0; +u32 max17050_get_cached_batt_volt() +{ + return battery_voltage; +} + +static u16 max17050_get_reg(u8 reg) +{ + u16 data = 0; + + i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, reg); + + return data; +} + +int max17050_get_property(enum MAX17050_reg reg, int *value) +{ + u16 data; + + switch (reg) + { + case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap). + data = max17050_get_reg(MAX17050_Age); + *value = data >> 8; /* Show MSB. 1% increments */ + break; + case MAX17050_Cycles: // Cycle count. + *value = max17050_get_reg(MAX17050_Cycles); + break; + case MAX17050_MinVolt: // Voltage max/min + data = max17050_get_reg(MAX17050_MinMaxVolt); + *value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */ + break; + case MAX17050_MaxVolt: // Voltage max/min + data = max17050_get_reg(MAX17050_MinMaxVolt); + *value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */ + break; + case MAX17050_V_empty: // Voltage min design. + data = max17050_get_reg(MAX17050_V_empty); + *value = (data >> 7) * 10; /* Units of LSB = 10mV */ + break; + case MAX17050_VCELL: // Voltage now. + data = max17050_get_reg(MAX17050_VCELL); + *value = data * 625 / 8 / 1000; + battery_voltage = *value; + break; + case MAX17050_AvgVCELL: // Voltage avg. + data = max17050_get_reg(MAX17050_AvgVCELL); + *value = data * 625 / 8 / 1000; + break; + case MAX17050_OCVInternal: // Voltage ocv. + data = max17050_get_reg(MAX17050_OCVInternal); + *value = data * 625 / 8 / 1000; + break; + case MAX17050_RepSOC: // Capacity %. + *value = max17050_get_reg(MAX17050_RepSOC); + break; + case MAX17050_DesignCap: // Charge full design. + data = max17050_get_reg(MAX17050_DesignCap); + *value = data * 5 / 10; + break; + case MAX17050_FullCAP: // Charge full. + data = max17050_get_reg(MAX17050_FullCAP); + *value = data * 5 / 10; + break; + case MAX17050_RepCap: // Charge now. + data = max17050_get_reg(MAX17050_RepCap); + *value = data * 5 / 10; + break; + case MAX17050_TEMP: // Temp. + data = max17050_get_reg(MAX17050_TEMP); + *value = (s16)data; + *value = *value * 10 / 256; + break; + case MAX17050_Current: // Current now. + data = max17050_get_reg(MAX17050_Current); + *value = (s16)data; + *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + break; + case MAX17050_AvgCurrent: // Current avg. + data = max17050_get_reg(MAX17050_AvgCurrent); + *value = (s16)data; + *value *= 1562500 / MAX17050_DEFAULT_SNS_RESISTOR; + break; + default: + return -1; + } + return 0; +} + +static int _max17050_write_verify_reg(u8 reg, u16 value) +{ + int retries = 8; + int ret; + u16 read_value; + + do + { + ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); + read_value = max17050_get_reg(reg); + if (read_value != value) + { + ret = -1; + retries--; + } + } while (retries && read_value != value); + + return ret; +} + +static void _max17050_override_por(u8 reg, u16 value) +{ + if (value) + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2); +} + +static void _max17050_load_new_capacity_params() +{ + u16 fullcap, repSoc, dq_acc, dp_acc; + + fullcap = 0x2476; // 4667mAh design capacity. + dq_acc = 0x10bc; // From a healthy fuel gauge. + dp_acc = 0x5e09; // =||= + repSoc = 0x6400; // 100%. + + _max17050_write_verify_reg(MAX17050_RemCap, fullcap); + _max17050_write_verify_reg(MAX17050_RepCap, fullcap); + + _max17050_write_verify_reg(MAX17050_dQacc, dq_acc); + _max17050_write_verify_reg(MAX17050_dPacc, dp_acc); + + _max17050_write_verify_reg(MAX17050_FullCAP, fullcap); + //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, (u8 *)&fullcap, 2); + _max17050_write_verify_reg(MAX17050_FullCAPNom, fullcap); + /* Update SOC register with new SOC */ + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC, (u8 *)&repSoc, 2); +} + +static void _max17050_reset_vfsoc0_reg() +{ + u16 lockVal = 0; + u16 vfSoc = 0x6440; // >100% for fully charged battery + + lockVal = VFSOC0_UNLOCK; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2); + + _max17050_write_verify_reg(MAX17050_VFSOC0, vfSoc); + + lockVal = VFSOC0_LOCK; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2); +} + +static void _max17050_update_capacity_regs() +{ + u16 value = 0x2476; // Set to 4667mAh design capacity. + _max17050_write_verify_reg(MAX17050_FullCAP, value); + _max17050_write_verify_reg(MAX17050_FullCAPNom, value); + //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, config->design_cap, 2); +} + +static void _max17050_write_config_regs() +{ + u16 value = 0; + + value = 0x7254; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_CONFIG, (u8 *)&value, 2); + value = 0x2473; + i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_LearnCFG, (u8 *)&value, 2); + //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FilterCFG, (u8 *)&value, 2) + //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RelaxCFG, (u8 *)&value, 2) + //i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullSOCThr, (u8 *)&value, 2) +} + +/* + * Block write all the override values coming from platform data. + * This function MUST be called before the POR initialization proceedure + * specified by maxim. + */ +static void _max17050_override_por_values() +{ + u16 dq_acc = 0x10bc; // From a healthy fuel gauge. + u16 dp_acc = 0x5e09; // =||= + + _max17050_override_por(MAX17050_dQacc, dq_acc); + _max17050_override_por(MAX17050_dPacc, dp_acc); + + //_max17050_override_por(MAX17050_RCOMP0, config->rcomp0); //0x58 + //_max17050_override_por(MAX17050_TempCo, config->tcompc0); //0x1b22 + + //u16 k_empty0 = 0x439; + //_max17050_override_por(map, MAX17050_K_empty0, k_empty0); // Unknown cell data +} + +static void _max17050_set_por_bit(u16 value) +{ + _max17050_write_verify_reg(MAX17050_STATUS, value); +} + +int max17050_fix_configuration() +{ + /* Init phase, set the POR bit */ + _max17050_set_por_bit(STATUS_POR_BIT); + + /* Override POR values */ + _max17050_override_por_values(); + /* After Power up, the MAX17050 requires 500ms in order + * to perform signal debouncing and initial SOC reporting + */ + msleep(500); + + /* Initialize configaration */ + _max17050_write_config_regs(); + + /* update capacity params */ + _max17050_update_capacity_regs(); + + /* delay must be atleast 350mS to allow VFSOC + * to be calculated from the new configuration + */ + msleep(350); + + /* reset vfsoc0 reg */ + _max17050_reset_vfsoc0_reg(); + + /* load new capacity params */ + _max17050_load_new_capacity_params(); + + /* Init complete, Clear the POR bit */ + //_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR? + + // Sets POR, BI, BR. + _max17050_set_por_bit(0x8801); + + return 0; +} diff --git a/ariane/src/bdk/power/max17050.h b/ariane/src/bdk/power/max17050.h new file mode 100644 index 0000000..254aca3 --- /dev/null +++ b/ariane/src/bdk/power/max17050.h @@ -0,0 +1,135 @@ +/* + * Fuel gauge driver for Nintendo Switch's Maxim 17050 + * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. + * + * Copyright (c) 2011 Samsung Electronics + * MyungJoo Ham + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MAX17050_H_ +#define __MAX17050_H_ + +#include + +#define MAX17050_STATUS_BattAbsent (1 << 3) +#define MAX17050_DEFAULT_SNS_RESISTOR 10000 + +/* Consider RepCap which is less then 10 units below FullCAP full */ +#define MAX17050_FULL_THRESHOLD 10 + +#define MAX17050_CHARACTERIZATION_DATA_SIZE 48 + +#define MAXIM17050_I2C_ADDR 0x36 + +enum MAX17050_reg { + MAX17050_STATUS = 0x00, + MAX17050_VALRT_Th = 0x01, + MAX17050_TALRT_Th = 0x02, + MAX17050_SALRT_Th = 0x03, + MAX17050_AtRate = 0x04, + MAX17050_RepCap = 0x05, + MAX17050_RepSOC = 0x06, + MAX17050_Age = 0x07, + MAX17050_TEMP = 0x08, + MAX17050_VCELL = 0x09, + MAX17050_Current = 0x0A, + MAX17050_AvgCurrent = 0x0B, + + MAX17050_SOC = 0x0D, + MAX17050_AvSOC = 0x0E, + MAX17050_RemCap = 0x0F, + MAX17050_FullCAP = 0x10, + MAX17050_TTE = 0x11, + MAX17050_QRTbl00 = 0x12, + MAX17050_FullSOCThr = 0x13, + MAX17050_RSLOW = 0x14, + + MAX17050_AvgTA = 0x16, + MAX17050_Cycles = 0x17, + MAX17050_DesignCap = 0x18, + MAX17050_AvgVCELL = 0x19, + MAX17050_MinMaxTemp = 0x1A, + MAX17050_MinMaxVolt = 0x1B, + MAX17050_MinMaxCurr = 0x1C, + MAX17050_CONFIG = 0x1D, + MAX17050_ICHGTerm = 0x1E, + MAX17050_AvCap = 0x1F, + MAX17050_ManName = 0x20, + MAX17050_DevName = 0x21, + MAX17050_QRTbl10 = 0x22, + MAX17050_FullCAPNom = 0x23, + MAX17050_TempNom = 0x24, + MAX17050_TempLim = 0x25, + MAX17050_TempHot = 0x26, + MAX17050_AIN = 0x27, + MAX17050_LearnCFG = 0x28, + MAX17050_FilterCFG = 0x29, + MAX17050_RelaxCFG = 0x2A, + MAX17050_MiscCFG = 0x2B, + MAX17050_TGAIN = 0x2C, + MAX17050_TOFF = 0x2D, + MAX17050_CGAIN = 0x2E, + MAX17050_COFF = 0x2F, + + MAX17050_QRTbl20 = 0x32, + MAX17050_SOC_empty = 0x33, + MAX17050_T_empty = 0x34, + MAX17050_FullCAP0 = 0x35, + MAX17050_LAvg_empty = 0x36, + MAX17050_FCTC = 0x37, + MAX17050_RCOMP0 = 0x38, + MAX17050_TempCo = 0x39, + MAX17050_V_empty = 0x3A, + MAX17050_K_empty0 = 0x3B, + MAX17050_TaskPeriod = 0x3C, + MAX17050_FSTAT = 0x3D, + MAX17050_TIMER = 0x3E, + MAX17050_SHDNTIMER = 0x3F, + + MAX17050_QRTbl30 = 0x42, + + MAX17050_dQacc = 0x45, + MAX17050_dPacc = 0x46, + + MAX17050_VFSOC0 = 0x48, + + Max17050_QH0 = 0x4C, + MAX17050_QH = 0x4D, + MAX17050_QL = 0x4E, + + MAX17050_MinVolt = 0x50, // Custom ID. Not to be sent to i2c. + MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. + + MAX17050_VFSOC0Enable = 0x60, + MAX17050_MODELEnable1 = 0x62, + MAX17050_MODELEnable2 = 0x63, + + MAX17050_MODELChrTbl = 0x80, + + MAX17050_OCV = 0xEE, + + MAX17050_OCVInternal = 0xFB, + + MAX17050_VFSOC = 0xFF, +}; + +int max17050_get_property(enum MAX17050_reg reg, int *value); +int max17050_fix_configuration(); +u32 max17050_get_cached_batt_volt(); + +#endif /* __MAX17050_H_ */ diff --git a/ariane/src/bdk/power/max77620.h b/ariane/src/bdk/power/max77620.h new file mode 100644 index 0000000..26ea855 --- /dev/null +++ b/ariane/src/bdk/power/max77620.h @@ -0,0 +1,340 @@ +/* + * Defining registers address and its bit definitions of MAX77620 and MAX20024 + * + * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef _MFD_MAX77620_H_ +#define _MFD_MAX77620_H_ + +#define MAX77620_I2C_ADDR 0x3C + +/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ +#define MAX77620_REG_CNFGGLBL1 0x00 +#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) +#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) +#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E +#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) +#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) + +#define MAX77620_REG_CNFGGLBL2 0x01 +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_WDTC_MASK 0x3 +#define MAX77620_WDTOFFC (1 << 4) +#define MAX77620_WDTSLPC (1 << 3) +#define MAX77620_WDTEN (1 << 2) +#define MAX77620_TWD_MASK 0x3 +#define MAX77620_TWD_2s 0x0 +#define MAX77620_TWD_16s 0x1 +#define MAX77620_TWD_64s 0x2 +#define MAX77620_TWD_128s 0x3 + +#define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) + +#define MAX77620_REG_CNFGBBC 0x04 +#define MAX77620_CNFGBBC_ENABLE (1 << 0) +#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 +#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 +#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 +#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) +#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 +#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 +#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) + +#define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) +#define MAX77620_IRQ_TOP_SD_MASK (1 << 6) +#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) +#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) +#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) +#define MAX77620_IRQ_TOP_32K_MASK (1 << 2) +#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) + +#define MAX77620_REG_INTLBT 0x06 +#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_IRQ_LBM_MASK (1 << 3) +#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) +#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) + +#define MAX77620_REG_IRQSD 0x07 +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A +#define MAX77620_REG_ONOFFIRQ 0x0B +#define MAX77620_REG_NVERC 0x0C + +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_GLBLM_MASK (1 << 0) + +#define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_REG_STATLBT 0x13 +#define MAX77620_REG_STATSD 0x14 +#define MAX77620_REG_ONOFFSTAT 0x15 + +/* SD and LDO Registers */ +#define MAX77620_REG_SD0 0x16 +#define MAX77620_REG_SD1 0x17 +#define MAX77620_REG_SD2 0x18 +#define MAX77620_REG_SD3 0x19 +#define MAX77620_REG_SD4 0x1A +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x3F +#define MAX77620_SD1_VOLT_MASK 0x7F +#define MAX77620_LDO_VOLT_MASK 0x3F +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_REG_LDO0_CFG 0x23 +#define MAX77620_REG_LDO0_CFG2 0x24 +#define MAX77620_REG_LDO1_CFG 0x25 +#define MAX77620_REG_LDO1_CFG2 0x26 +#define MAX77620_REG_LDO2_CFG 0x27 +#define MAX77620_REG_LDO2_CFG2 0x28 +#define MAX77620_REG_LDO3_CFG 0x29 +#define MAX77620_REG_LDO3_CFG2 0x2A +#define MAX77620_REG_LDO4_CFG 0x2B +#define MAX77620_REG_LDO4_CFG2 0x2C +#define MAX77620_REG_LDO5_CFG 0x2D +#define MAX77620_REG_LDO5_CFG2 0x2E +#define MAX77620_REG_LDO6_CFG 0x2F +#define MAX77620_REG_LDO6_CFG2 0x30 +#define MAX77620_REG_LDO7_CFG 0x31 +#define MAX77620_REG_LDO7_CFG2 0x32 +#define MAX77620_REG_LDO8_CFG 0x33 +#define MAX77620_REG_LDO8_CFG2 0x34 +#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +#define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_POWER_MODE_NORMAL 3 +#define MAX77620_POWER_MODE_LPM 2 +#define MAX77620_POWER_MODE_GLPM 1 +#define MAX77620_POWER_MODE_DISABLE 0 +#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW 0 + +#define MAX77620_REG_LDO_CFG3 0x35 +#define MAX77620_TRACK4_MASK (1 << 5) +#define MAX77620_TRACK4_SHIFT 5 + +#define MAX77620_LDO_SLEW_RATE_MASK 0x1 + +#define MAX77620_REG_GPIO0 0x36 +#define MAX77620_REG_GPIO1 0x37 +#define MAX77620_REG_GPIO2 0x38 +#define MAX77620_REG_GPIO3 0x39 +#define MAX77620_REG_GPIO4 0x3A +#define MAX77620_REG_GPIO5 0x3B +#define MAX77620_REG_GPIO6 0x3C +#define MAX77620_REG_GPIO7 0x3D +#define MAX77620_REG_PUE_GPIO 0x3E +#define MAX77620_REG_PDE_GPIO 0x3F +#define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) + +#define MAX77620_REG_ONOFFCNFG1 0x41 +#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) +#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) +#define MAX20024_ONOFFCNFG1_CLRSE 0x18 + +#define MAX77620_REG_ONOFFCNFG2 0x42 +#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) +#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) +#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) + +/* FPS Registers */ +#define MAX77620_REG_FPS_CFG0 0x43 +#define MAX77620_REG_FPS_CFG1 0x44 +#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_LDO0 0x46 +#define MAX77620_REG_FPS_LDO1 0x47 +#define MAX77620_REG_FPS_LDO2 0x48 +#define MAX77620_REG_FPS_LDO3 0x49 +#define MAX77620_REG_FPS_LDO4 0x4A +#define MAX77620_REG_FPS_LDO5 0x4B +#define MAX77620_REG_FPS_LDO6 0x4C +#define MAX77620_REG_FPS_LDO7 0x4D +#define MAX77620_REG_FPS_LDO8 0x4E +#define MAX77620_REG_FPS_SD0 0x4F +#define MAX77620_REG_FPS_SD1 0x50 +#define MAX77620_REG_FPS_SD2 0x51 +#define MAX77620_REG_FPS_SD3 0x52 +#define MAX77620_REG_FPS_SD4 0x53 +#define MAX77620_REG_FPS_NONE 0 +#define MAX77620_FPS_SRC_MASK 0xC0 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 + +/* Minimum and maximum FPS period time (in microseconds) are + * different for MAX77620 and Max20024. + */ +#define MAX77620_FPS_COUNT 3 + +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX20024_FPS_PERIOD_MIN_US 20 + +#define MAX77620_FPS_PERIOD_MAX_US 2560 +#define MAX20024_FPS_PERIOD_MAX_US 5120 + +#define MAX77620_REG_FPS_GPIO1 0x54 +#define MAX77620_REG_FPS_GPIO2 0x55 +#define MAX77620_REG_FPS_GPIO3 0x56 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 + +#define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_REG_CID0 0x58 +#define MAX77620_REG_CID1 0x59 +#define MAX77620_REG_CID2 0x5A +#define MAX77620_REG_CID3 0x5B +#define MAX77620_REG_CID4 0x5C +#define MAX77620_REG_CID5 0x5D + +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 + +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 + +/* CNCG2SD */ +#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) + +/* Device Identification Metal */ +#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) +/* Device Indentification OTP */ +#define MAX77620_CID5_DIDO(n) ((n) & 0xF) + +/* SD CNFG1 */ +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK (1 << 3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) +#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) + +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) + +/* Interrupts */ +enum { + MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ + MAX77620_IRQ_TOP_SD, /* SD power fail */ + MAX77620_IRQ_TOP_LDO, /* LDO power fail */ + MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ + MAX77620_IRQ_TOP_RTC, /* RTC */ + MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ + MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ + MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ +}; + +/* GPIOs */ +enum { + MAX77620_GPIO0, + MAX77620_GPIO1, + MAX77620_GPIO2, + MAX77620_GPIO3, + MAX77620_GPIO4, + MAX77620_GPIO5, + MAX77620_GPIO6, + MAX77620_GPIO7, + MAX77620_GPIO_NR, +}; + +/* FPS Source */ +enum max77620_fps_src { + MAX77620_FPS_SRC_0, + MAX77620_FPS_SRC_1, + MAX77620_FPS_SRC_2, + MAX77620_FPS_SRC_NONE, + MAX77620_FPS_SRC_DEF, +}; + +enum max77620_chip_id { + MAX77620, + MAX20024, +}; + +#endif /* _MFD_MAX77620_H_ */ diff --git a/ariane/src/bdk/power/max7762x.c b/ariane/src/bdk/power/max7762x.c new file mode 100644 index 0000000..425ce1f --- /dev/null +++ b/ariane/src/bdk/power/max7762x.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#define REGULATOR_SD 0 +#define REGULATOR_LDO 1 + +typedef struct _max77620_regulator_t +{ + u8 type; + const char *name; + u8 reg_sd; + + u32 mv_step; + u32 mv_min; + u32 mv_default; + u32 mv_max; + + u8 volt_addr; + u8 cfg_addr; + + u8 volt_mask; + u8 enable_mask; + u8 enable_shift; + u8 status_mask; + + u8 fps_addr; + u8 fps_src; + u8 pd_period; + u8 pu_period; +} max77620_regulator_t; + +static const max77620_regulator_t _pmic_regulators[] = { + { REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 }, + { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 }, + { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 }, + { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 }, + { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 }, + { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 }, + { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 }, + { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 }, + { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 }, + { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, + { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, + { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, + { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } +}; + +static void _max77620_try_set_reg(u8 reg, u8 val) +{ + u8 tmp; + do + { + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); + tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); + } while (val != tmp); +} + +int max77620_regulator_get_status(u32 id) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (reg->type == REGULATOR_SD) + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; + return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & 8) ? 1 : 0; +} + +int max77620_regulator_config_fps(u32 id) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + _max77620_try_set_reg(reg->fps_addr, + (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); + + return 1; +} + +int max77620_regulator_set_voltage(u32 id, u32 mv) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (mv < reg->mv_min || mv > reg->mv_max) + return 0; + + u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; + u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); + val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); + _max77620_try_set_reg(reg->volt_addr, val); + usleep(1000); + + return 1; +} + +int max77620_regulator_enable(u32 id, int enable) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr; + u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr); + if (enable) + val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); + else + val &= ~reg->enable_mask; + _max77620_try_set_reg(addr, val); + usleep(1000); + + return 1; +} + +// LDO only. +int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) +{ + if (id > REGULATOR_MAX) + return 0; + + const max77620_regulator_t *reg = &_pmic_regulators[id]; + + if (mv < reg->mv_min || mv > reg->mv_max) + return 0; + + u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; + u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); + _max77620_try_set_reg(reg->volt_addr, val); + usleep(1000); + + return 1; +} + +void max77620_config_default() +{ + for (u32 i = 1; i <= REGULATOR_MAX; i++) + { + i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4); + max77620_regulator_config_fps(i); + max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default); + if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) + max77620_regulator_enable(i, 1); + } + _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); +} + +void max77620_low_battery_monitor_config(bool enable) +{ + _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, + MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | + MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); +} diff --git a/ariane/src/hwinit/max7762x.h b/ariane/src/bdk/power/max7762x.h similarity index 70% rename from ariane/src/hwinit/max7762x.h rename to ariane/src/bdk/power/max7762x.h index 00a8ba5..f60c3b2 100644 --- a/ariane/src/hwinit/max7762x.h +++ b/ariane/src/bdk/power/max7762x.h @@ -1,39 +1,40 @@ /* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef _MAX7762X_H_ #define _MAX7762X_H_ -#include "types.h" +#include /* * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init *-------+---------------+---------+--------+------------+---------+------------------ -* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) -* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) +* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) +* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) * sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) * sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | -* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) -* ldo1 | XUSB | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) +* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | -* ldo3 | | 50000 | 800000 | 3100000 | 3100000 | +* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | | 50000 | 800000 | 1800000 | 1800000 | -* ldo6 | | 50000 | 800000 | 2900000 | 2900000 | +* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | */ @@ -43,8 +44,6 @@ * MAX77620_REG_GPIOx: 0x9 sets output and enable */ - - /*! MAX77620 partitions. */ #define REGULATOR_SD0 0 #define REGULATOR_SD1 1 @@ -65,7 +64,7 @@ #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_VOUT_REG 0 -#define MAX77621_VOUT_DVC_REG 1 +#define MAX77621_VOUT_DVS_REG 1 #define MAX77621_CONTROL1_REG 2 #define MAX77621_CONTROL2_REG 3 @@ -108,17 +107,12 @@ #define MAX77621_INDUCTOR_PLUS_30_PER 0x2 #define MAX77621_INDUCTOR_PLUS_60_PER 0x3 -u32 max77620_send_byte(u32 regAddr, u8 dataByte); -u8 max77620_recv_byte(u32 y); - -u32 max7762x_send_byte(u32 devAddr, u32 regAddr, u8 dataByte); -u8 max7762x_recv_byte(u32 devAddr, u32 y); - int max77620_regulator_get_status(u32 id); int max77620_regulator_config_fps(u32 id); int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); +int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); -void max77620_low_battery_monitor_config(); +void max77620_low_battery_monitor_config(bool enable); #endif diff --git a/ariane/src/bdk/power/regulator_5v.c b/ariane/src/bdk/power/regulator_5v.c new file mode 100644 index 0000000..c61db64 --- /dev/null +++ b/ariane/src/bdk/power/regulator_5v.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +static u8 reg_5v_dev = 0; + +void regulator_enable_5v(u8 dev) +{ + // The power supply selection from battery or USB is automatic. + if (!reg_5v_dev) + { + // Fan and Rail power from internal 5V regulator (battery). + PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1; + gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH); + + // Fan and Rail power from USB 5V VDD. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1; + gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH); + + // Make sure GPIO power is enabled. + PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN; + // Override power detect for GPIO AO IO rails. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN; + } + reg_5v_dev |= dev; +} + +void regulator_disable_5v(u8 dev) +{ + reg_5v_dev &= ~dev; + + if (!reg_5v_dev) + { + // Rail power from internal 5V regulator (battery). + gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW); + gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE); + gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO); + PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE; + + // Rail power from USB 5V VDD. + gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); + gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO); + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE; + + // GPIO AO IO rails. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN; + } +} + +bool regulator_get_5v_dev_enabled(u8 dev) +{ + return (reg_5v_dev & dev); +} diff --git a/ariane/src/bdk/power/regulator_5v.h b/ariane/src/bdk/power/regulator_5v.h new file mode 100644 index 0000000..e916fbd --- /dev/null +++ b/ariane/src/bdk/power/regulator_5v.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _REGULATOR_5V_H_ +#define _REGULATOR_5V_H_ + +#include + +enum +{ + REGULATOR_5V_FAN = (1 << 0), + REGULATOR_5V_JC_R = (1 << 1), + REGULATOR_5V_JC_L = (1 << 2), + REGULATOR_5V_ALL = 0xFF +}; + +void regulator_enable_5v(u8 dev); +void regulator_disable_5v(u8 dev); +bool regulator_get_5v_dev_enabled(u8 dev); + +#endif \ No newline at end of file diff --git a/ariane/src/bdk/rtc/max77620-rtc.c b/ariane/src/bdk/rtc/max77620-rtc.c new file mode 100644 index 0000000..164df75 --- /dev/null +++ b/ariane/src/bdk/rtc/max77620-rtc.c @@ -0,0 +1,147 @@ +/* + * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC + * + * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2019 shchmue + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +void max77620_rtc_get_time(rtc_time_t *time) +{ + u8 val = 0; + + // Update RTC regs from RTC clock. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); + + // Get control reg config. + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG); + // TODO: Check for binary format also? + + // Get time. + time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; + time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; + u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG); + time->hour = hour & 0x1F; + + if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK)) + time->hour = (time->hour & 0xF) + 12; + + // Get day of week. 1: Monday to 7: Sunday. + time->weekday = 0; + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG); + for (int i = 0; i < 8; i++) + { + time->weekday++; + if (val & 1) + break; + val >>= 1; + } + + // Get date. + time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; + time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; + time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; +} + +void max77620_rtc_stop_alarm() +{ + u8 val = 0; + + // Update RTC regs from RTC clock. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); + + // Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2. + for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++) + { + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i); + val &= ~MAX77620_RTC_ALARM_EN_MASK; + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val); + } + + // Update RTC clock from RTC regs. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); +} + +void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) +{ + u32 tmp, edays, year, month, day; + + // Set time. + time->sec = epoch % 60; + epoch /= 60; + time->min = epoch % 60; + epoch /= 60; + time->hour = epoch % 24; + epoch /= 24; + + // Calculate base date values. + tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15); + tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2)); + + year = (20 * tmp - 2442) / 7305; + edays = tmp - 365 * year - (year >> 2); + month = edays * 1000 / 30601; + day = edays - month * 30 - month * 601 / 1000; + + // Month/Year offset. + if(month < 14) + { + year -= 4716; + month--; + } + else + { + year -= 4715; + month -= 13; + } + + // Set date. + time->year = year; + time->month = month; + time->day = day; + + // Set weekday. + time->weekday = 0; //! TODO. +} + +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time) +{ + u32 year, month, epoch; + + //Year + year = time->year; + //Month of year + month = time->month; + + // Month/Year offset. + if(month < 3) + { + month += 12; + year--; + } + + epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days. + + epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. + epoch -= 719561; // Epoch time is 1/1/1970. + + epoch *= 86400; // Days to seconds. + epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds. + + return epoch; +} diff --git a/ariane/src/bdk/rtc/max77620-rtc.h b/ariane/src/bdk/rtc/max77620-rtc.h new file mode 100644 index 0000000..d9e216a --- /dev/null +++ b/ariane/src/bdk/rtc/max77620-rtc.h @@ -0,0 +1,77 @@ +/* + * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MFD_MAX77620_RTC_H_ +#define _MFD_MAX77620_RTC_H_ + +#include + +#define MAX77620_RTC_I2C_ADDR 0x68 + +#define MAX77620_RTC_NR_TIME_REGS 7 + +#define MAX77620_RTC_CONTROLM_REG 0x02 +#define MAX77620_RTC_CONTROL_REG 0x03 +#define MAX77620_RTC_BIN_FORMAT (1 << 0) +#define MAX77620_RTC_24H (1 << 1) + +#define MAX77620_RTC_UPDATE0_REG 0x04 +#define MAX77620_RTC_WRITE_UPDATE (1 << 0) +#define MAX77620_RTC_READ_UPDATE (1 << 4) + +#define MAX77620_RTC_SEC_REG 0x07 +#define MAX77620_RTC_MIN_REG 0x08 +#define MAX77620_RTC_HOUR_REG 0x09 +#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) +#define MAX77620_RTC_WEEKDAY_REG 0x0A +#define MAX77620_RTC_MONTH_REG 0x0B +#define MAX77620_RTC_YEAR_REG 0x0C +#define MAX77620_RTC_DATE_REG 0x0D + +#define MAX77620_ALARM1_SEC_REG 0x0E +#define MAX77620_ALARM1_MIN_REG 0x0F +#define MAX77620_ALARM1_HOUR_REG 0x10 +#define MAX77620_ALARM1_WEEKDAY_REG 0x11 +#define MAX77620_ALARM1_MONTH_REG 0x12 +#define MAX77620_ALARM1_YEAR_REG 0x13 +#define MAX77620_ALARM1_DATE_REG 0x14 +#define MAX77620_ALARM2_SEC_REG 0x15 +#define MAX77620_ALARM2_MIN_REG 0x16 +#define MAX77620_ALARM2_HOUR_REG 0x17 +#define MAX77620_ALARM2_WEEKDAY_REG 0x18 +#define MAX77620_ALARM2_MONTH_REG 0x19 +#define MAX77620_ALARM2_YEAR_REG 0x1A +#define MAX77620_ALARM2_DATE_REG 0x1B +#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) + +typedef struct _rtc_time_t { + u8 weekday; + u8 sec; + u8 min; + u8 hour; + u8 day; + u8 month; + u16 year; +} rtc_time_t; + +void max77620_rtc_get_time(rtc_time_t *time); +void max77620_rtc_stop_alarm(); +void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time); +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time); + +#endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/ariane/src/bdk/sec/se.c b/ariane/src/bdk/sec/se.c new file mode 100644 index 0000000..bc6fa44 --- /dev/null +++ b/ariane/src/bdk/sec/se.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "se.h" +#include "se_t210.h" +#include +#include +#include +#include + +typedef struct _se_ll_t +{ + vu32 num; + vu32 addr; + vu32 size; +} se_ll_t; + +static void _gf256_mul_x(void *block) +{ + u8 *pdata = (u8 *)block; + u32 carry = 0; + + for (int i = 0xF; i >= 0; i--) + { + u8 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 7; + } + + if (carry) + pdata[0xF] ^= 0x87; +} + +static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) +{ + ll->num = 0; + ll->addr = addr; + ll->size = size; +} + +static void _se_ll_set(se_ll_t *dst, se_ll_t *src) +{ + SE(SE_IN_LL_ADDR_REG_OFFSET) = (u32)src; + SE(SE_OUT_LL_ADDR_REG_OFFSET) = (u32)dst; +} + +static int _se_wait() +{ + while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET))) + ; + if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) || + SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN || + SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) + return 0; + return 1; +} + +se_ll_t *ll_dst, *ll_src; +static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot) +{ + ll_dst = NULL; + ll_src = NULL; + + if (dst) + { + ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); + _se_ll_init(ll_dst, (u32)dst, dst_size); + } + + if (src) + { + ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); + _se_ll_init(ll_src, (u32)src, src_size); + } + + _se_ll_set(ll_dst, ll_src); + + SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); + SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + + if (is_oneshot) + { + int res = _se_wait(); + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + if (src) + free(ll_src); + if (dst) + free(ll_dst); + + return res; + } + + return 1; +} + +static int _se_execute_finalize() +{ + int res = _se_wait(); + + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + if (ll_src) + { + free(ll_src); + ll_src = NULL; + } + if (ll_dst) + { + free(ll_dst); + ll_dst = NULL; + } + + return res; +} + +static int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + return _se_execute(op, dst, dst_size, src, src_size, true); +} + +static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (!src || !dst) + return 0; + + u8 *block = (u8 *)malloc(0x10); + memset(block, 0, 0x10); + + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + + memcpy(block, src, src_size); + int res = _se_execute_oneshot(op, block, 0x10, block, 0x10); + memcpy(dst, block, dst_size); + + free(block); + return res; +} + +static void _se_aes_ctr_set(void *ctr) +{ + u32 *data = (u32 *)ctr; + for (u32 i = 0; i < 4; i++) + SE(SE_CRYPTO_CTR_REG_OFFSET + 4 * i) = data[i]; +} + +void se_rsa_acc_ctrl(u32 rs, u32 flags) +{ + if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = + ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | + ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); + if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); +} + +void se_key_acc_ctrl(u32 ks, u32 flags) +{ + if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; + if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) + SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); +} + +u32 se_key_acc_ctrl_get(u32 ks) +{ + return SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks); +} + +void se_aes_key_set(u32 ks, void *key, u32 size) +{ + u32 *data = (u32 *)key; + for (u32 i = 0; i < size / 4; i++) + { + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i]; + } +} + +void se_aes_key_clear(u32 ks) +{ + for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++) + { + SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i; + SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0; + } +} + +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) +{ + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst); + + return _se_execute_oneshot(OP_START, NULL, 0, input, 0x10); +} + +int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); + } + else + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); + } + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) +{ + if (enc) + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP); + } + else + { + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) | + SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM); + } + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + return _se_execute_oneshot(OP_START, dst, dst_size, src, src_size); +} + +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) +{ + return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); +} + +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) +{ + SE(SE_SPARE_0_REG_OFFSET) = 1; + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); + _se_aes_ctr_set(ctr); + + u32 src_size_aligned = src_size & 0xFFFFFFF0; + u32 src_size_delta = src_size & 0xF; + + if (src_size_aligned) + { + SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1; + if (!_se_execute_oneshot(OP_START, dst, dst_size, src, src_size_aligned)) + return 0; + } + + if (src_size - src_size_aligned && src_size_aligned < dst_size) + return _se_execute_one_block(OP_START, dst + src_size_aligned, + MIN(src_size_delta, dst_size - src_size_aligned), + src + src_size_aligned, src_size_delta); + + return 1; +} + +int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize) +{ + int res = 0; + u8 *tweak = (u8 *)malloc(0x10); + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + //Generate tweak. + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) + goto out; + + //We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < secsize / 0x10; i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = psrc[j] ^ tweak[j]; + if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst)) + goto out; + for (u32 j = 0; j < 0x10; j++) + pdst[j] = pdst[j] ^ tweak[j]; + _gf256_mul_x(tweak); + psrc += 0x10; + pdst += 0x10; + } + + res = 1; + +out:; + free(tweak); + return res; +} + +int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs) +{ + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + for (u32 i = 0; i < num_secs; i++) + if (!se_aes_xts_crypt_sec(ks1, ks2, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize)) + return 0; + + return 1; +} + +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) +{ + int res; + u32 *hash32 = (u32 *)hash; + + if (src_size > 0xFFFFFF || (u32)hash % 4 || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. + return 0; + + // Setup config for SHA256. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); + SE(SE_SHA_CONFIG_REG_OFFSET) = sha_cfg; + SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; + + // Set total size to current buffer size if empty. + if (!total_size) + total_size = src_size; + + // Set total size: BITS(src_size), up to 2 EB. + SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; + + // Set size left to hash. + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(total_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = (u32)(total_size >> 29); + SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; + + // If we hash in chunks, copy over the intermediate. + if (sha_cfg == SHA_CONTINUE && msg_left) + { + // Restore message left to process. + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = msg_left[0]; + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = msg_left[1]; + + // Restore hash reg. + for (u32 i = 0; i < 8; i++) + SE(SE_HASH_RESULT_REG_OFFSET + (i << 2)) = byte_swap_32(hash32[i]); + } + + // Trigger the operation. + res = _se_execute(OP_START, NULL, 0, src, src_size, is_oneshot); + + if (is_oneshot) + { + // Backup message left. + if (msg_left) + { + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + } + + // Copy output hash. + for (u32 i = 0; i < 8; i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); + } + + return res; +} + +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size) +{ + return se_calc_sha256(hash, NULL, src, src_size, 0, SHA_INIT_HASH, true); +} + +int se_calc_sha256_finalize(void *hash, u32 *msg_left) +{ + u32 *hash32 = (u32 *)hash; + int res = _se_execute_finalize(); + + // Backup message left. + if (msg_left) + { + msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG_OFFSET); + msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG_OFFSET); + } + + // Copy output hash. + for (u32 i = 0; i < 8; i++) + hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG_OFFSET + (i << 2))); + + return res; +} + +int se_gen_prng128(void *dst) +{ + // Setup config for X931 PRNG. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL); + //SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = + // SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE); + SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 1; + + SE(SE_BLOCK_COUNT_REG_OFFSET) = (16 >> 4) - 1; + + // Trigger the operation. + return _se_execute_oneshot(OP_START, dst, 16, NULL, 0); +} + +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize) +{ + u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40); + + // Set Secure Random Key. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK); + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); + SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED); + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_START, NULL, 0, NULL, 0); + + // Save AES keys. + SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); + + for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | + (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); + memcpy(keys + i * keysize, aligned_buf, 0x10); + + if (keysize > 0x10) + { + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | + (i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7); + + SE(SE_CRYPTO_LAST_BLOCK) = 0; + _se_execute_oneshot(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); + memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10); + } + } + + // Save SRK to PMC secure scratches. + SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK); + SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK + _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + + // End context save. + SE(SE_CONFIG_REG_OFFSET) = 0; + _se_execute_oneshot(OP_CTX_SAVE, NULL, 0, NULL, 0); + + // Get SRK. + u32 srk[4]; + srk[0] = PMC(0xC0); + srk[1] = PMC(0xC4); + srk[2] = PMC(0x224); + srk[3] = PMC(0x228); + + // Decrypt context. + se_aes_key_clear(3); + se_aes_key_set(3, srk, 0x10); + se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize); + se_aes_key_clear(3); +} diff --git a/ariane/src/bdk/sec/se.h b/ariane/src/bdk/sec/se.h new file mode 100644 index 0000000..ba35088 --- /dev/null +++ b/ariane/src/bdk/sec/se.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _SE_H_ +#define _SE_H_ + +#include + +void se_rsa_acc_ctrl(u32 rs, u32 flags); +void se_key_acc_ctrl(u32 ks, u32 flags); +u32 se_key_acc_ctrl_get(u32 ks); +void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); +void se_aes_key_set(u32 ks, void *key, u32 size); +void se_aes_key_clear(u32 ks); +int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); +int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); +int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); +int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); +int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot); +int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); +int se_calc_sha256_finalize(void *hash, u32 *msg_left); +int se_gen_prng128(void *dst); + +#endif diff --git a/ariane/src/bdk/sec/se_t210.h b/ariane/src/bdk/sec/se_t210.h new file mode 100644 index 0000000..83557f7 --- /dev/null +++ b/ariane/src/bdk/sec/se_t210.h @@ -0,0 +1,391 @@ +/* +* Driver for Tegra Security Engine +* +* Copyright (c) 2011-2013, NVIDIA Corporation. All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _CRYPTO_TEGRA_SE_H +#define _CRYPTO_TEGRA_SE_H + +#include + +#define TEGRA_SE_CRA_PRIORITY 300 +#define TEGRA_SE_COMPOSITE_PRIORITY 400 +#define TEGRA_SE_CRYPTO_QUEUE_LENGTH 50 +#define SE_MAX_SRC_SG_COUNT 50 +#define SE_MAX_DST_SG_COUNT 50 + +#define TEGRA_SE_KEYSLOT_COUNT 16 +#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF + +/* SE register definitions */ +#define SE_SECURITY_0 0x000 +#define SE_KEY_SCHED_READ_SHIFT 3 + +#define SE_TZRAM_SECURITY_0 0x004 + +#define SE_CONFIG_REG_OFFSET 0x014 +#define SE_CONFIG_ENC_ALG_SHIFT 12 +#define SE_CONFIG_DEC_ALG_SHIFT 8 +#define ALG_AES_ENC 1 +#define ALG_RNG 2 +#define ALG_SHA 3 +#define ALG_RSA 4 +#define ALG_NOP 0 +#define ALG_AES_DEC 1 +#define SE_CONFIG_ENC_ALG(x) (x << SE_CONFIG_ENC_ALG_SHIFT) +#define SE_CONFIG_DEC_ALG(x) (x << SE_CONFIG_DEC_ALG_SHIFT) +#define SE_CONFIG_DST_SHIFT 2 +#define DST_MEMORY 0 +#define DST_HASHREG 1 +#define DST_KEYTAB 2 +#define DST_SRK 3 +#define DST_RSAREG 4 +#define SE_CONFIG_DST(x) (x << SE_CONFIG_DST_SHIFT) +#define SE_CONFIG_ENC_MODE_SHIFT 24 +#define SE_CONFIG_DEC_MODE_SHIFT 16 +#define MODE_KEY128 0 +#define MODE_KEY192 1 +#define MODE_KEY256 2 +#define MODE_SHA1 0 +#define MODE_SHA224 4 +#define MODE_SHA256 5 +#define MODE_SHA384 6 +#define MODE_SHA512 7 +#define SE_CONFIG_ENC_MODE(x) (x << SE_CONFIG_ENC_MODE_SHIFT) +#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT) + +#define SE_RNG_CONFIG_REG_OFFSET 0x340 +#define RNG_MODE_SHIFT 0 +#define RNG_MODE_NORMAL 0 +#define RNG_MODE_FORCE_INSTANTION 1 +#define RNG_MODE_FORCE_RESEED 2 +#define SE_RNG_CONFIG_MODE(x) (x << RNG_MODE_SHIFT) +#define RNG_SRC_SHIFT 2 +#define RNG_SRC_NONE 0 +#define RNG_SRC_ENTROPY 1 +#define RNG_SRC_LFSR 2 +#define SE_RNG_CONFIG_SRC(x) (x << RNG_SRC_SHIFT) + +#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344 +#define RNG_SRC_RO_ENT_SHIFT 1 +#define RNG_SRC_RO_ENT_ENABLE 1 +#define RNG_SRC_RO_ENT_DISABLE 0 +#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT) +#define RNG_SRC_RO_ENT_LOCK_SHIFT 0 +#define RNG_SRC_RO_ENT_LOCK_ENABLE 1 +#define RNG_SRC_RO_ENT_LOCK_DISABLE 0 +#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT) + +#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 + +#define SE_KEYTABLE_REG_OFFSET 0x31c +#define SE_KEYTABLE_SLOT_SHIFT 4 +#define SE_KEYTABLE_SLOT(x) (x << SE_KEYTABLE_SLOT_SHIFT) +#define SE_KEYTABLE_QUAD_SHIFT 2 +#define QUAD_KEYS_128 0 +#define QUAD_KEYS_192 1 +#define QUAD_KEYS_256 1 +#define QUAD_ORG_IV 2 +#define QUAD_UPDTD_IV 3 +#define SE_KEYTABLE_QUAD(x) (x << SE_KEYTABLE_QUAD_SHIFT) +#define SE_KEYTABLE_OP_TYPE_SHIFT 9 +#define OP_READ 0 +#define OP_WRITE 1 +#define SE_KEYTABLE_OP_TYPE(x) (x << SE_KEYTABLE_OP_TYPE_SHIFT) +#define SE_KEYTABLE_TABLE_SEL_SHIFT 8 +#define TABLE_KEYIV 0 +#define TABLE_SCHEDULE 1 +#define SE_KEYTABLE_TABLE_SEL(x) (x << SE_KEYTABLE_TABLE_SEL_SHIFT) +#define SE_KEYTABLE_PKT_SHIFT 0 +#define SE_KEYTABLE_PKT(x) (x << SE_KEYTABLE_PKT_SHIFT) + +#define SE_OP_DONE_SHIFT 4 +#define OP_DONE 1 +#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT)) + +#define SE_CRYPTO_LAST_BLOCK 0x080 + +#define SE_CRYPTO_REG_OFFSET 0x304 +#define SE_CRYPTO_HASH_SHIFT 0 +#define HASH_DISABLE 0 +#define HASH_ENABLE 1 +#define SE_CRYPTO_HASH(x) (x << SE_CRYPTO_HASH_SHIFT) +#define SE_CRYPTO_XOR_POS_SHIFT 1 +#define XOR_BYPASS 0 +#define XOR_TOP 2 +#define XOR_BOTTOM 3 +#define SE_CRYPTO_XOR_POS(x) (x << SE_CRYPTO_XOR_POS_SHIFT) +#define SE_CRYPTO_INPUT_SEL_SHIFT 3 +#define INPUT_AHB 0 +#define INPUT_RANDOM 1 +#define INPUT_AESOUT 2 +#define INPUT_LNR_CTR 3 +#define SE_CRYPTO_INPUT_SEL(x) (x << SE_CRYPTO_INPUT_SEL_SHIFT) +#define SE_CRYPTO_VCTRAM_SEL_SHIFT 5 +#define VCTRAM_AHB 0 +#define VCTRAM_AESOUT 2 +#define VCTRAM_PREVAHB 3 +#define SE_CRYPTO_VCTRAM_SEL(x) (x << SE_CRYPTO_VCTRAM_SEL_SHIFT) +#define SE_CRYPTO_IV_SEL_SHIFT 7 +#define IV_ORIGINAL 0 +#define IV_UPDATED 1 +#define SE_CRYPTO_IV_SEL(x) (x << SE_CRYPTO_IV_SEL_SHIFT) +#define SE_CRYPTO_CORE_SEL_SHIFT 8 +#define CORE_DECRYPT 0 +#define CORE_ENCRYPT 1 +#define SE_CRYPTO_CORE_SEL(x) (x << SE_CRYPTO_CORE_SEL_SHIFT) +#define SE_CRYPTO_CTR_VAL_SHIFT 11 +#define SE_CRYPTO_CTR_VAL(x) (x << SE_CRYPTO_CTR_VAL_SHIFT) +#define SE_CRYPTO_KEY_INDEX_SHIFT 24 +#define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT) +#define SE_CRYPTO_CTR_CNTN_SHIFT 11 +#define SE_CRYPTO_CTR_CNTN(x) (x << SE_CRYPTO_CTR_CNTN_SHIFT) + +#define SE_CRYPTO_CTR_REG_COUNT 4 +#define SE_CRYPTO_CTR_REG_OFFSET 0x308 + +#define SE_OPERATION_REG_OFFSET 0x008 +#define SE_OPERATION_SHIFT 0 +#define OP_ABORT 0 +#define OP_START 1 +#define OP_RESTART 2 +#define OP_CTX_SAVE 3 +#define OP_RESTART_IN 4 +#define SE_OPERATION(x) (x << SE_OPERATION_SHIFT) + +#define SE_CONTEXT_SAVE_CONFIG_REG_OFFSET 0x070 +#define SE_CONTEXT_SAVE_WORD_QUAD_SHIFT 0 +#define KEYS_0_3 0 +#define KEYS_4_7 1 +#define ORIG_IV 2 +#define UPD_IV 3 +#define SE_CONTEXT_SAVE_WORD_QUAD(x) (x << SE_CONTEXT_SAVE_WORD_QUAD_SHIFT) + +#define SE_CONTEXT_SAVE_KEY_INDEX_SHIFT 8 +#define SE_CONTEXT_SAVE_KEY_INDEX(x) (x << SE_CONTEXT_SAVE_KEY_INDEX_SHIFT) + +#define SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT 24 +#define STICKY_0_3 0 +#define STICKY_4_7 1 +#define SE_CONTEXT_SAVE_STICKY_WORD_QUAD(x) \ + (x << SE_CONTEXT_SAVAE_STICKY_WORD_QUAD_SHIFT) + +#define SE_CONTEXT_SAVE_SRC_SHIFT 29 +#define STICKY_BITS 0 +#define KEYTABLE 2 +#define MEM 4 +#define SRK 6 + +#define RSA_KEYTABLE 1 +#define AES_KEYTABLE 2 +#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT) + +#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16 +#define SE_CONTEXT_SAVE_RSA_KEY_INDEX(x) \ + (x << SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT) + +#define SE_CONTEXT_RSA_WORD_QUAD_SHIFT 12 +#define SE_CONTEXT_RSA_WORD_QUAD(x) \ + (x << SE_CONTEXT_RSA_WORD_QUAD_SHIFT) + +#define SE_INT_ENABLE_REG_OFFSET 0x00c +#define SE_INT_STATUS_REG_OFFSET 0x010 +#define INT_DISABLE 0 +#define INT_ENABLE 1 +#define INT_UNSET 0 +#define INT_SET 1 +#define SE_INT_OP_DONE_SHIFT 4 +#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT) +#define SE_INT_ERROR_SHIFT 16 +#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT) + +#define SE_STATUS_0 0x800 +#define SE_STATUS_0_STATE_WAIT_IN 3 + +#define SE_ERR_STATUS_0 0x804 +#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 + +#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 +#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 +#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \ + (x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) + +#define SE_KEY_INDEX_SHIFT 8 +#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) (x << SE_KEY_INDEX_SHIFT) + +#define SE_IN_LL_ADDR_REG_OFFSET 0x018 +#define SE_OUT_LL_ADDR_REG_OFFSET 0x024 + +#define SE_KEYTABLE_DATA0_REG_OFFSET 0x320 +#define SE_KEYTABLE_REG_MAX_DATA 16 + +#define SE_BLOCK_COUNT_REG_OFFSET 0x318 + +#define SE_SPARE_0_REG_OFFSET 0x80c + +#define SE_SHA_CONFIG_REG_OFFSET 0x200 +#define SHA_CONTINUE 0 +#define SHA_INIT_HASH 1 + +#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 +#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 +#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C +#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 +#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 +#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 +#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C +#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 + +#define SE_HASH_RESULT_REG_COUNT 16 +#define SE_HASH_RESULT_REG_OFFSET 0x030 +#define TEGRA_SE_KEY_256_SIZE 32 +#define TEGRA_SE_KEY_192_SIZE 24 +#define TEGRA_SE_KEY_128_SIZE 16 +#define TEGRA_SE_AES_BLOCK_SIZE 16 +#define TEGRA_SE_AES_MIN_KEY_SIZE 16 +#define TEGRA_SE_AES_MAX_KEY_SIZE 32 +#define TEGRA_SE_AES_IV_SIZE 16 +#define TEGRA_SE_RNG_IV_SIZE 16 +#define TEGRA_SE_RNG_DT_SIZE 16 +#define TEGRA_SE_RNG_KEY_SIZE 16 +#define TEGRA_SE_RNG_SEED_SIZE (TEGRA_SE_RNG_IV_SIZE + \ + TEGRA_SE_RNG_KEY_SIZE + \ + TEGRA_SE_RNG_DT_SIZE) + +#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16 +#define TEGRA_SE_RSA512_DIGEST_SIZE 64 +#define TEGRA_SE_RSA1024_DIGEST_SIZE 128 +#define TEGRA_SE_RSA1536_DIGEST_SIZE 192 +#define TEGRA_SE_RSA2048_DIGEST_SIZE 256 + +#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280 +#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + +#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 +#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) +#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F + +#define SE_KEY_READ_DISABLE_SHIFT 0 +#define SE_KEY_UPDATE_DISABLE_SHIFT 1 + +#define SE_CONTEXT_BUFER_SIZE 1072 +#define SE_CONTEXT_DRBG_BUFER_SIZE 2112 + +#define SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET 0 +#define SE_CONTEXT_SAVE_RANDOM_DATA_SIZE 16 +#define SE_CONTEXT_SAVE_STICKY_BITS_OFFSET \ + (SE_CONTEXT_SAVE_RANDOM_DATA_OFFSET + SE_CONTEXT_SAVE_RANDOM_DATA_SIZE) +#define SE_CONTEXT_SAVE_STICKY_BITS_SIZE 16 + +#define SE_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE) +#define SE11_CONTEXT_SAVE_KEYS_OFFSET (SE_CONTEXT_SAVE_STICKY_BITS_OFFSET + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE + \ + SE_CONTEXT_SAVE_STICKY_BITS_SIZE) + +#define SE_CONTEXT_SAVE_KEY_LENGTH 512 +#define SE_CONTEXT_ORIGINAL_IV_OFFSET (SE_CONTEXT_SAVE_KEYS_OFFSET + \ + SE_CONTEXT_SAVE_KEY_LENGTH) +#define SE11_CONTEXT_ORIGINAL_IV_OFFSET (SE11_CONTEXT_SAVE_KEYS_OFFSET + \ + SE_CONTEXT_SAVE_KEY_LENGTH) + +#define SE_CONTEXT_ORIGINAL_IV_LENGTH 256 + +#define SE_CONTEXT_UPDATED_IV_OFFSET (SE_CONTEXT_ORIGINAL_IV_OFFSET + \ + SE_CONTEXT_ORIGINAL_IV_LENGTH) +#define SE11_CONTEXT_UPDATED_IV_OFFSET (SE11_CONTEXT_ORIGINAL_IV_OFFSET + \ + SE_CONTEXT_ORIGINAL_IV_LENGTH) + +#define SE_CONTEXT_UPDATED_IV_LENGTH 256 + +#define SE_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET (SE_CONTEXT_UPDATED_IV_OFFSET + \ + SE_CONTEXT_UPDATED_IV_LENGTH) +#define SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET \ + (SE11_CONTEXT_UPDATED_IV_OFFSET + \ + SE_CONTEXT_UPDATED_IV_LENGTH) + +#define SE_CONTEXT_SAVE_RSA_KEYS_OFFSET SE11_CONTEXT_SAVE_KNOWN_PATTERN_OFFSET + +#define SE_CONTEXT_SAVE_RSA_KEY_LENGTH 1024 + +#define SE_CONTEXT_SAVE_RSA_KNOWN_PATTERN_OFFSET \ + (SE_CONTEXT_SAVE_RSA_KEYS_OFFSET + SE_CONTEXT_SAVE_RSA_KEY_LENGTH) + +#define SE_CONTEXT_KNOWN_PATTERN_SIZE 16 + +#define TEGRA_SE_RSA_KEYSLOT_COUNT 2 + +#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C +#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + +#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F + +#define SE_RSA_KEYTABLE_ADDR 0x420 +#define SE_RSA_KEYTABLE_DATA 0x424 +#define SE_RSA_OUTPUT 0x428 + +#define RSA_KEY_READ 0 +#define RSA_KEY_WRITE 1 +#define SE_RSA_KEY_OP_SHIFT 10 +#define SE_RSA_KEY_OP(x) (x << SE_RSA_KEY_OP_SHIFT) + +#define RSA_KEY_INPUT_MODE_REG 0 +#define RSA_KEY_INPUT_MODE_DMA 1 +#define RSA_KEY_INPUT_MODE_SHIFT 8 +#define RSA_KEY_INPUT_MODE(x) (x << RSA_KEY_INPUT_MODE_SHIFT) + +#define RSA_KEY_SLOT_ONE 0 +#define RSA_KEY_SLOT_TW0 1 +#define RSA_KEY_NUM_SHIFT 7 +#define RSA_KEY_NUM(x) (x << RSA_KEY_NUM_SHIFT) + +#define RSA_KEY_TYPE_EXP 0 +#define RSA_KEY_TYPE_MOD 1 +#define RSA_KEY_TYPE_SHIFT 6 +#define RSA_KEY_TYPE(x) (x << RSA_KEY_TYPE_SHIFT) + +#define SE_RSA_KEY_SIZE_REG_OFFSET 0x404 +#define SE_RSA_EXP_SIZE_REG_OFFSET 0x408 + +#define RSA_KEY_SLOT_SHIFT 24 +#define RSA_KEY_SLOT(x) (x << RSA_KEY_SLOT_SHIFT) +#define SE_RSA_CONFIG 0x400 + +#define RSA_KEY_PKT_WORD_ADDR_SHIFT 0 +#define RSA_KEY_PKT_WORD_ADDR(x) (x << RSA_KEY_PKT_WORD_ADDR_SHIFT) + +#define RSA_KEY_WORD_ADDR_SHIFT 0 +#define RSA_KEY_WORD_ADDR(x) (x << RSA_KEY_WORD_ADDR_SHIFT) + +#define SE_RSA_KEYTABLE_PKT_SHIFT 0 +#define SE_RSA_KEYTABLE_PKT(x) (x << SE_RSA_KEYTABLE_PKT_SHIFT) + +#endif /* _CRYPTO_TEGRA_SE_H */ diff --git a/ariane/src/bdk/sec/tsec.c b/ariane/src/bdk/sec/tsec.c new file mode 100644 index 0000000..b4485b1 --- /dev/null +++ b/ariane/src/bdk/sec/tsec.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "tsec.h" +#include "tsec_t210.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include + +#define PKG11_MAGIC 0x31314B50 +#define KB_TSEC_FW_EMU_COMPAT 6 // KB ID for HOS 6.2.0. + +static int _tsec_dma_wait_idle() +{ + u32 timeout = get_tmr_ms() + 10000; + + while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE)) + if (get_tmr_ms() > timeout) + return 0; + + return 1; +} + +static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offset) +{ + u32 cmd; + + if (not_imem) + cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes + else + cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory) + + TSEC(TSEC_DMATRFMOFFS) = i_offset; + TSEC(TSEC_DMATRFFBOFFS) = pa_offset; + TSEC(TSEC_DMATRFCMD) = cmd; + + return _tsec_dma_wait_idle(); +} + +int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) +{ + int res = 0; + u8 *fwbuf = NULL; + u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; + u32 *pkg11_magic_off; + + bpmp_mmu_disable(); + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + + // Enable clocks. + clock_enable_host1x(); + usleep(2); + clock_enable_tsec(); + clock_enable_sor_safe(); + clock_enable_sor0(); + clock_enable_sor1(); + clock_enable_kfuse(); + + kfuse_wait_ready(); + + // Configure Falcon. + TSEC(TSEC_DMACTL) = 0; + TSEC(TSEC_IRQMSET) = + TSEC_IRQMSET_EXT(0xFF) | + TSEC_IRQMSET_WDTMR | + TSEC_IRQMSET_HALT | + TSEC_IRQMSET_EXTERR | + TSEC_IRQMSET_SWGEN0 | + TSEC_IRQMSET_SWGEN1; + TSEC(TSEC_IRQDEST) = + TSEC_IRQDEST_EXT(0xFF) | + TSEC_IRQDEST_HALT | + TSEC_IRQDEST_EXTERR | + TSEC_IRQDEST_SWGEN0 | + TSEC_IRQDEST_SWGEN1; + TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN; + if (!_tsec_dma_wait_idle()) + { + res = -1; + goto out; + } + + // Load firmware or emulate memio environment for newer TSEC fw. + if (kb == KB_TSEC_FW_EMU_COMPAT) + TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; + else + { + fwbuf = (u8 *)malloc(0x4000); + u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100); + memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size); + TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8; + } + + for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100) + { + if (!_tsec_dma_pa_to_internal_100(false, addr, addr)) + { + res = -2; + goto out_free; + } + } + + if (kb == KB_TSEC_FW_EMU_COMPAT) + { + // Init SMMU translation for TSEC. + pdir = smmu_init_for_tsec(); + smmu_init(tsec_ctxt->secmon_base); + // Enable SMMU + if (!smmu_is_used()) + smmu_enable(); + + // Clock reset controller. + car = page_alloc(1); + memcpy(car, (void *)CLOCK_BASE, 0x1000); + car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; + smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); + + // Fuse driver. + fuse = page_alloc(1); + memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); + fuse[0x82C / 4] = 0; + fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1; + fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1; + smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); + + // Power management controller. + pmc = page_alloc(1); + smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); + + // Flow control. + flowctrl = page_alloc(1); + smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); + + // Security engine. + se = page_alloc(1); + memcpy(se, (void *)SE_BASE, 0x1000); + smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); + + // Memory controller. + mc = page_alloc(1); + memcpy(mc, (void *)MC_BASE, 0x1000); + mc[MC_IRAM_BOM / 4] = 0; + mc[MC_IRAM_TOM / 4] = 0x80000000; + smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); + + // IRAM + iram = page_alloc(0x30); + memcpy(iram, tsec_ctxt->pkg1, 0x30000); + // PKG1.1 magic offset. + pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); + smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); + + // Exception vectors + evec = page_alloc(1); + smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); + } + + // Execute firmware. + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; + TSEC(TSEC_STATUS) = 0; + TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. + TSEC(TSEC_BOOTVEC) = 0; + TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; + + if (kb == KB_TSEC_FW_EMU_COMPAT) + { + u32 start = get_tmr_us(); + u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + u32 key[16] = {0}; + u32 kidx = 0; + + while (*pkg11_magic_off != PKG11_MAGIC) + { + smmu_flush_all(); + + if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]) + { + k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4]; + key[kidx++] = k; + } + + // Failsafe. + if ((u32)get_tmr_us() - start > 125000) + break; + } + + if (kidx != 8) + { + res = -6; + smmu_deinit_for_tsec(); + + goto out_free; + } + + // Give some extra time to make sure PKG1.1 is decrypted. + msleep(50); + + memcpy(tsec_keys, &key, 0x20); + memcpy(tsec_ctxt->pkg1, iram, 0x30000); + + smmu_deinit_for_tsec(); + + // for (int i = 0; i < kidx; i++) + // gfx_printf("key %08X\n", key[i]); + + // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); + + // u32 errst = MC(MC_ERR_STATUS); + // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); + // gfx_printf(" type: %02X\n", errst >> 28); + // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3); + // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); + // gfx_printf(" cid: %02x\n", errst & 0xFF); + } + else + { + if (!_tsec_dma_wait_idle()) + { + res = -3; + goto out_free; + } + u32 timeout = get_tmr_ms() + 2000; + while (!TSEC(TSEC_STATUS)) + if (get_tmr_ms() > timeout) + { + res = -4; + goto out_free; + } + if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) + { + res = -5; + goto out_free; + } + + // Fetch result. + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; + u32 buf[4]; + buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); + buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); + buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); + buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); + SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; + SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; + + memcpy(tsec_keys, &buf, 0x10); + } + +out_free:; + free(fwbuf); + +out:; + + // Disable clocks. + clock_disable_kfuse(); + clock_disable_sor1(); + clock_disable_sor0(); + clock_disable_sor_safe(); + clock_disable_tsec(); + bpmp_mmu_enable(); + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + + return res; +} diff --git a/ariane/src/hwinit/util.h b/ariane/src/bdk/sec/tsec.h similarity index 70% rename from ariane/src/hwinit/util.h rename to ariane/src/bdk/sec/tsec.h index 0f960a2..6206034 100644 --- a/ariane/src/hwinit/util.h +++ b/ariane/src/bdk/sec/tsec.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert +* Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,19 +15,20 @@ * along with this program. If not, see . */ -#ifndef _UTIL_H_ -#define _UTIL_H_ +#ifndef _TSEC_H_ +#define _TSEC_H_ -#include "types.h" +#include -typedef struct _cfg_op_t +typedef struct _tsec_ctxt_t { - u32 off; - u32 val; -} cfg_op_t; + void *fw; + u32 size; + void *pkg1; + u32 pkg11_off; + u32 secmon_base; +} tsec_ctxt_t; -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); -int running_on_bpmp(void); -void shutdown_using_pmic(void); +int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); #endif diff --git a/ariane/src/bdk/sec/tsec_t210.h b/ariane/src/bdk/sec/tsec_t210.h new file mode 100644 index 0000000..befe269 --- /dev/null +++ b/ariane/src/bdk/sec/tsec_t210.h @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2018 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _TSEC_T210_H_ +#define _TSEC_T210_H_ + +#define TSEC_BOOTKEYVER 0x1040 +#define TSEC_STATUS 0x1044 +#define TSEC_ITFEN 0x1048 +#define TSEC_ITFEN_CTXEN (1 << 0) +#define TSEC_ITFEN_MTHDEN (1 << 1) +#define TSEC_IRQMSET 0x1010 +#define TSEC_IRQMSET_WDTMR (1 << 1) +#define TSEC_IRQMSET_HALT (1 << 4) +#define TSEC_IRQMSET_EXTERR (1 << 5) +#define TSEC_IRQMSET_SWGEN0 (1 << 6) +#define TSEC_IRQMSET_SWGEN1 (1 << 7) +#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8) +#define TSEC_IRQDEST 0x101C +#define TSEC_IRQDEST_HALT (1 << 4) +#define TSEC_IRQDEST_EXTERR (1 << 5) +#define TSEC_IRQDEST_SWGEN0 (1 << 6) +#define TSEC_IRQDEST_SWGEN1 (1 << 7) +#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) +#define TSEC_CPUCTL 0x1100 +#define TSEC_CPUCTL_STARTCPU (1 << 1) +#define TSEC_BOOTVEC 0x1104 +#define TSEC_DMACTL 0x110C +#define TSEC_DMATRFBASE 0x1110 +#define TSEC_DMATRFMOFFS 0x1114 +#define TSEC_DMATRFCMD 0x1118 +#define TSEC_DMATRFCMD_IDLE (1 << 1) +#define TSEC_DMATRFCMD_IMEM (1 << 4) +#define TSEC_DMATRFCMD_SIZE_256B (6 << 8) +#define TSEC_DMATRFFBOFFS 0x111C + +#endif diff --git a/ariane/src/bdk/soc/bpmp.c b/ariane/src/bdk/soc/bpmp.c new file mode 100644 index 0000000..1a8a205 --- /dev/null +++ b/ariane/src/bdk/soc/bpmp.c @@ -0,0 +1,308 @@ +/* + * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 + * + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#define BPMP_MMU_CACHE_LINE_SIZE 0x20 + +#define BPMP_CACHE_CONFIG 0x0 +#define CFG_ENABLE_CACHE (1 << 0) +#define CFG_ENABLE_SKEW_ASSOC (1 << 1) +#define CFG_DISABLE_RANDOM_ALLOC (1 << 2) +#define CFG_FORCE_WRITE_THROUGH (1 << 3) +#define CFG_NEVER_ALLOCATE (1 << 6) +#define CFG_ENABLE_INTERRUPT (1 << 7) +#define CFG_MMU_TAG_MODE(x) (x << 8) +#define TAG_MODE_PARALLEL 0 +#define TAG_MODE_TAG_FIRST 1 +#define TAG_MODE_MMU_FIRST 2 +#define CFG_DISABLE_WRITE_BUFFER (1 << 10) +#define CFG_DISABLE_READ_BUFFER (1 << 11) +#define CFG_ENABLE_HANG_DETECT (1 << 12) +#define CFG_FULL_LINE_DIRTY (1 << 13) +#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14) +#define CFG_TAG_CHK_CLR_ERR (1 << 15) +#define CFG_DISABLE_SAMELINE (1 << 16) +#define CFG_OBS_BUS_EN (1 << 31) + +#define BPMP_CACHE_LOCK 0x4 +#define LOCK_LINE(x) (1 << x) + +#define BPMP_CACHE_SIZE 0xC +#define BPMP_CACHE_LFSR 0x10 + +#define BPMP_CACHE_TAG_STATUS 0x14 +#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0) +#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0 + +#define BPMP_CACHE_CLKEN_OVERRIDE 0x18 +#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0) +#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1) + +#define BPMP_CACHE_MAINT_ADDR 0x20 +#define BPMP_CACHE_MAINT_DATA 0x24 + +#define BPMP_CACHE_MAINT_REQ 0x28 +#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8) + +#define BPMP_CACHE_INT_MASK 0x40 +#define BPMP_CACHE_INT_CLEAR 0x44 +#define BPMP_CACHE_INT_RAW_EVENT 0x48 +#define BPMP_CACHE_INT_STATUS 0x4C +#define INT_MAINT_DONE (1 << 0) +#define INT_MAINT_ERROR (1 << 1) + +#define BPMP_CACHE_RB_CFG 0x80 +#define BPMP_CACHE_WB_CFG 0x84 + +#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0 +#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 + +#define BPMP_CACHE_MMU_CFG 0xAC +#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0) +#define MMU_CFG_SEQ_EN (1 << 1) +#define MMU_CFG_TLB_EN (1 << 2) +#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3) +#define MMU_CFG_ABORT_STORE_LAST (1 << 4) +#define MMU_CFG_CLR_ABORT (1 << 5) + +#define BPMP_CACHE_MMU_CMD 0xB0 +#define MMU_CMD_NOP 0 +#define MMU_CMD_INIT 1 +#define MMU_CMD_COPY_SHADOW 2 + +#define BPMP_CACHE_MMU_ABORT_STAT 0xB4 +#define ABORT_STAT_UNIT_MASK 0x7 +#define ABORT_STAT_UNIT_NONE 0 +#define ABORT_STAT_UNIT_CACHE 1 +#define ABORT_STAT_UNIT_SEQ 2 +#define ABORT_STAT_UNIT_TLB 3 +#define ABORT_STAT_UNIT_SEG 4 +#define ABORT_STAT_UNIT_FALLBACK 5 +#define ABORT_STAT_OVERLAP (1 << 3) +#define ABORT_STAT_ENTRY (0x1F << 4) +#define ABORT_STAT_TYPE_MASK (3 << 16) +#define ABORT_STAT_TYPE_EXE (0 << 16) +#define ABORT_STAT_TYPE_RD (1 << 16) +#define ABORT_STAT_TYPE_WR (2 << 16) +#define ABORT_STAT_SIZE (3 << 18) +#define ABORT_STAT_SEQ (1 << 20) +#define ABORT_STAT_PROT (1 << 21) + +#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 +#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC + +#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) +#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) +#define MMU_EN_CACHED (1 << 0) +#define MMU_EN_EXEC (1 << 1) +#define MMU_EN_READ (1 << 2) +#define MMU_EN_WRITE (1 << 3) + +bpmp_mmu_entry_t mmu_entries[] = +{ + { DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, + { IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } +}; + +void bpmp_mmu_maintenance(u32 op, bool force) +{ + if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)) + return; + + BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE; + + // This is a blocking operation. + BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op; + + while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE)) + ; + + BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT); +} + +void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) +{ + if (idx > 31) + return; + + volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx); + + if (entry->enable) + { + mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE); + mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE); + mmu_entry->attr = entry->attr; + + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx); + + if (apply) + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; + } +} + +void bpmp_mmu_enable() +{ + if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE) + return; + + // Init BPMP MMU. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT; + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST; + + // Init BPMP MMU entries. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0; + for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++) + bpmp_mmu_set_entry(idx, &mmu_entries[idx], false); + + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; + + // Invalidate cache. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); + + // Enable cache. + BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH | + CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR; + + // HW bug. Invalidate cache again. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); +} + +void bpmp_mmu_disable() +{ + if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)) + return; + + // Clean and invalidate cache. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + // Disable cache. + BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; +} + +// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM, +// I2C host, DC/DSI/DISP. UART gives extra stress. +// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less. +const u8 pll_divn[] = { + 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. + 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. + 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. + 92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB. + // Do not use for public releases! + //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. +}; + +bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; + +void bpmp_clk_rate_get() +{ + bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3; + + if (clk_src_is_pllp) + bpmp_clock_set = BPMP_CLK_NORMAL; + else + { + bpmp_clock_set = BPMP_CLK_HIGH_BOOST; + + u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; + for (u32 i = 1; i < sizeof(pll_divn); i++) + { + if (pll_divn[i] == pll_divn_curr) + { + bpmp_clock_set = i; + break; + } + } + } +} + +void bpmp_clk_rate_set(bpmp_freq_t fid) +{ + if (fid > (BPMP_CLK_MAX - 1)) + fid = BPMP_CLK_MAX - 1; + + if (bpmp_clock_set == fid) + return; + + if (fid) + { + if (bpmp_clock_set) + { + // Restore to PLLP source during PLLC4 configuration. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. + msleep(1); // Wait a bit for clock source change. + } + + // Configure and enable PLLC. + clock_enable_pllc(pll_divn[fid]); + + // Set SCLK / HCLK / PCLK. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle. + } + else + { + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle. + msleep(1); // Wait a bit for clock source change. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK. + + // Disable PLLC to save power. + clock_disable_pllc(); + } + bpmp_clock_set = fid; +} + +// The following functions halt BPMP to reduce power while sleeping. +// They are not as accurate as RTC at big values but they guarantee time+ delay. +void bpmp_usleep(u32 us) +{ + u32 delay; + + // Each iteration takes 1us. + while (us) + { + delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + us -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + } +} + +void bpmp_msleep(u32 ms) +{ + u32 delay; + + // Iteration time is variable. ~200 - 1000us. + while (ms) + { + delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + ms -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + } +} + +void bpmp_halt() +{ + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; +} diff --git a/ariane/src/bdk/soc/bpmp.h b/ariane/src/bdk/soc/bpmp.h new file mode 100644 index 0000000..81f000b --- /dev/null +++ b/ariane/src/bdk/soc/bpmp.h @@ -0,0 +1,68 @@ +/* + * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 + * + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _BPMP_H_ +#define _BPMP_H_ + +#include + +typedef enum +{ + BPMP_MMU_MAINT_NOP = 0, + BPMP_MMU_MAINT_CLEAN_PHY = 1, + BPMP_MMU_MAINT_INVALID_PHY = 2, + BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3, + BPMP_MMU_MAINT_CLEAN_LINE = 9, + BPMP_MMU_MAINT_INVALID_LINE = 10, + BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11, + BPMP_MMU_MAINT_CLEAN_WAY = 17, + BPMP_MMU_MAINT_INVALID_WAY = 18, + BPMP_MMU_MAINT_CLN_INV_WAY = 19 +} bpmp_maintenance_t; + +typedef struct _bpmp_mmu_entry_t +{ + u32 start_addr; + u32 end_addr; + u32 attr; + u32 enable; +} bpmp_mmu_entry_t; + +typedef enum +{ + BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB. + BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB. + BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB. + BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB. + //BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB. + BPMP_CLK_MAX +} bpmp_freq_t; + +#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST + +void bpmp_mmu_maintenance(u32 op, bool force); +void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); +void bpmp_mmu_enable(); +void bpmp_mmu_disable(); +void bpmp_clk_rate_get(); +void bpmp_clk_rate_set(bpmp_freq_t fid); +void bpmp_usleep(u32 us); +void bpmp_msleep(u32 ms); +void bpmp_halt(); + +#endif diff --git a/ariane/src/bdk/soc/ccplex.c b/ariane/src/bdk/soc/ccplex.c new file mode 100644 index 0000000..24a4787 --- /dev/null +++ b/ariane/src/bdk/soc/ccplex.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void _ccplex_enable_power() +{ + u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); + + // Enable cores power. + // 1-3.x: MAX77621_NFSR_ENABLE. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, + MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); + // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); +} + +int _ccplex_pmc_enable_partition(u32 part, int enable) +{ + u32 part_mask = 1 << part; + u32 desired_state = enable << part; + + // Check if the partition has the state we want. + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + return 1; + + u32 i = 5001; + while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) + { + usleep(1); + i--; + if (i < 1) + return 0; + } + + // Toggle power gating. + PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; + + i = 5001; + while (i > 0) + { + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) + break; + usleep(1); + i--; + } + + return 1; +} + +void ccplex_boot_cpu0(u32 entry) +{ + // Set ACTIVE_CLUSER to FAST. + FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= 0xFFFFFFFE; + + _ccplex_enable_power(); + + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. + { + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. + usleep(2); + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02; + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02; + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) = (CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) & 0xFFFBFFFF) | 0x40000; + CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x40404E02; + } + while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) + ; + + // Configure MSELECT source and enable clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) & 0xFFFFFFF7) | 8; + + // Configure initial CPU clock frequency and enable clock. + CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; + CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = 1; + + clock_enable_coresight(); + + // CAR2PMC_CPU_ACK_WIDTH should be set to 0. + CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; + + // Enable CPU rail. + _ccplex_pmc_enable_partition(0, 1); + // Enable cluster 0 non-CPU. + _ccplex_pmc_enable_partition(15, 1); + // Enable CE0. + _ccplex_pmc_enable_partition(14, 1); + + // Request and wait for RAM repair. + FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; + while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2)) + ; + + EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; + + // Set reset vector. + SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; + SB(SB_AA64_RESET_HIGH) = 0; + // Non-secure reset vector write disable. + SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; + (void)SB(SB_CSR); + + // Tighten up the security aperture. + // MC(MC_TZ_SECURITY_CTRL) = 1; + + // Clear MSELECT reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; + // Clear NONCPU reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; + // Clear CPU0 reset. + // < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. + CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001; +} diff --git a/ariane/src/bdk/soc/ccplex.h b/ariane/src/bdk/soc/ccplex.h new file mode 100644 index 0000000..fb5be92 --- /dev/null +++ b/ariane/src/bdk/soc/ccplex.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CCPLEX_H_ +#define _CCPLEX_H_ + +#include + +void ccplex_boot_cpu0(u32 entry); + +#endif diff --git a/ariane/src/bdk/soc/clock.c b/ariane/src/bdk/soc/clock.c new file mode 100644 index 0000000..41e69a2 --- /dev/null +++ b/ariane/src/bdk/soc/clock.c @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +/* + * CLOCK Peripherals: + * L 0 - 31 + * H 32 - 63 + * U 64 - 95 + * V 96 - 127 + * W 128 - 159 + * X 160 - 191 + * Y 192 - 223 + */ + +/* clock_t: reset, enable, source, index, clk_src, clk_div */ + +static const clock_t _clock_uart[] = { +/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, +/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, +/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, +/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, +/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } +}; + +//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. +static const clock_t _clock_i2c[] = { +/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz +/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz +/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz +/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz +/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz +/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz +}; + +static clock_t _clock_se = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 +}; + +static clock_t _clock_tzram = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 +}; + +static clock_t _clock_host1x = { + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 +}; +static clock_t _clock_tsec = { + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 +}; +static clock_t _clock_sor_safe = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 +}; +static clock_t _clock_sor0 = { + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 +}; +static clock_t _clock_sor1 = { + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 +}; +static clock_t _clock_kfuse = { + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 +}; + +static clock_t _clock_cl_dvfs = { + CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 +}; +static clock_t _clock_coresight = { + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 +}; + +static clock_t _clock_pwm = { + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. +}; + +static clock_t _clock_sdmmc_legacy_tm = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66 +}; + +void clock_enable(const clock_t *clk) +{ + // Put clock into reset. + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); + // Disable. + CLOCK(clk->enable) &= ~(1 << clk->index); + // Configure clock source if required. + if (clk->source) + CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); + // Enable. + CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); + usleep(2); + + // Take clock off reset. + CLOCK(clk->reset) &= ~(1 << clk->index); +} + +void clock_disable(const clock_t *clk) +{ + // Put clock into reset. + CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); + // Disable. + CLOCK(clk->enable) &= ~(1 << clk->index); +} + +void clock_enable_fuse(bool enable) +{ + CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28); +} + +void clock_enable_uart(u32 idx) +{ + clock_enable(&_clock_uart[idx]); +} + +void clock_disable_uart(u32 idx) +{ + clock_disable(&_clock_uart[idx]); +} + +#define UART_SRC_CLK_DIV_EN (1 << 24) + +int clock_uart_use_src_div(u32 idx, u32 baud) +{ + u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000; + + if (baud == 1000000) + CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49; + else + { + CLOCK(_clock_uart[idx].source) = clk_src_div | 2; + + return 1; + } + + return 0; +} + +void clock_enable_i2c(u32 idx) +{ + clock_enable(&_clock_i2c[idx]); +} + +void clock_disable_i2c(u32 idx) +{ + clock_disable(&_clock_i2c[idx]); +} + +void clock_enable_se() +{ + clock_enable(&_clock_se); +} + +void clock_enable_tzram() +{ + clock_enable(&_clock_tzram); +} + +void clock_enable_host1x() +{ + clock_enable(&_clock_host1x); +} + +void clock_disable_host1x() +{ + clock_disable(&_clock_host1x); +} + +void clock_enable_tsec() +{ + clock_enable(&_clock_tsec); +} + +void clock_disable_tsec() +{ + clock_disable(&_clock_tsec); +} + +void clock_enable_sor_safe() +{ + clock_enable(&_clock_sor_safe); +} + +void clock_disable_sor_safe() +{ + clock_disable(&_clock_sor_safe); +} + +void clock_enable_sor0() +{ + clock_enable(&_clock_sor0); +} + +void clock_disable_sor0() +{ + clock_disable(&_clock_sor0); +} + +void clock_enable_sor1() +{ + clock_enable(&_clock_sor1); +} + +void clock_disable_sor1() +{ + clock_disable(&_clock_sor1); +} + +void clock_enable_kfuse() +{ + //clock_enable(&_clock_kfuse); + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF; + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100; + usleep(10); + CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF; + usleep(20); +} + +void clock_disable_kfuse() +{ + clock_disable(&_clock_kfuse); +} + +void clock_enable_cl_dvfs() +{ + clock_enable(&_clock_cl_dvfs); +} + +void clock_disable_cl_dvfs() +{ + clock_disable(&_clock_cl_dvfs); +} + +void clock_enable_coresight() +{ + clock_enable(&_clock_coresight); +} + +void clock_disable_coresight() +{ + clock_disable(&_clock_coresight); +} + +void clock_enable_pwm() +{ + clock_enable(&_clock_pwm); +} + +void clock_disable_pwm() +{ + clock_disable(&_clock_pwm); +} + +void clock_enable_pllc(u32 divn) +{ + u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; + + // Check if already enabled and configured. + if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn)) + return; + + // Take PLLC out of reset and set basic misc parameters. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = + ((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; + usleep(10); + + // Set PLLC dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. + + // Enable PLLC and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) + ; + + // Disable PLLC_OUT1, enable reset and set div to 1.5. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8); + + // Enable PLLC_OUT1 and bring it out of reset. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); + msleep(1); // Wait a bit for PLL to stabilize. +} + +void clock_disable_pllc() +{ + // Disable PLLC and PLLC_OUT1. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR); + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ; + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET; + usleep(10); +} + +#define PLLC4_ENABLED (1 << 31) +#define PLLC4_IN_USE (~PLLC4_ENABLED) + +u32 pllc4_enabled = 0; + +static void _clock_enable_pllc4(u32 mask) +{ + pllc4_enabled |= mask; + + if (pllc4_enabled & PLLC4_ENABLED) + return; + + // Enable Phase and Frequency lock detection. + //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; + usleep(10); + + // Set PLLC4 dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (104 << 8) | 4; // DIVM: 4, DIVP: 1. + + // Enable PLLC4 and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) + ; + + msleep(1); // Wait a bit for PLL to stabilize. + + pllc4_enabled |= PLLC4_ENABLED; +} + +static void _clock_disable_pllc4(u32 mask) +{ + pllc4_enabled &= ~mask; + + // Check if currently in use or disabled. + if ((pllc4_enabled & PLLC4_IN_USE) || !(pllc4_enabled & PLLC4_ENABLED)) + return; + + // Disable PLLC4. + msleep(1); // Wait at least 1ms to prevent glitching. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ; + usleep(10); + + pllc4_enabled = 0; +} + +#define L_SWR_SDMMC1_RST (1 << 14) +#define L_SWR_SDMMC2_RST (1 << 9) +#define L_SWR_SDMMC4_RST (1 << 15) +#define U_SWR_SDMMC3_RST (1 << 5) + +#define L_CLK_ENB_SDMMC1 (1 << 14) +#define L_CLK_ENB_SDMMC2 (1 << 9) +#define L_CLK_ENB_SDMMC4 (1 << 15) +#define U_CLK_ENB_SDMMC3 (1 << 5) + +#define L_SET_SDMMC1_RST (1 << 14) +#define L_SET_SDMMC2_RST (1 << 9) +#define L_SET_SDMMC4_RST (1 << 15) +#define U_SET_SDMMC3_RST (1 << 5) + +#define L_CLR_SDMMC1_RST (1 << 14) +#define L_CLR_SDMMC2_RST (1 << 9) +#define L_CLR_SDMMC4_RST (1 << 15) +#define U_CLR_SDMMC3_RST (1 << 5) + +#define L_SET_CLK_ENB_SDMMC1 (1 << 14) +#define L_SET_CLK_ENB_SDMMC2 (1 << 9) +#define L_SET_CLK_ENB_SDMMC4 (1 << 15) +#define U_SET_CLK_ENB_SDMMC3 (1 << 5) + +#define L_CLR_CLK_ENB_SDMMC1 (1 << 14) +#define L_CLR_CLK_ENB_SDMMC2 (1 << 9) +#define L_CLR_CLK_ENB_SDMMC4 (1 << 15) +#define U_CLR_CLK_ENB_SDMMC3 (1 << 5) + +static int _clock_sdmmc_is_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC1_RST; + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC2_RST; + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & U_SWR_SDMMC3_RST; + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC4_RST; + } + return 0; +} + +static void _clock_sdmmc_set_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; + break; + } +} + +static void _clock_sdmmc_clear_reset(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; + break; + } +} + +static int _clock_sdmmc_is_enabled(u32 id) +{ + switch (id) + { + case SDMMC_1: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC1; + case SDMMC_2: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC2; + case SDMMC_3: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & U_CLK_ENB_SDMMC3; + case SDMMC_4: + return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC4; + } + return 0; +} + +static void _clock_sdmmc_set_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; + break; + } +} + +static void _clock_sdmmc_clear_enable(u32 id) +{ + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; + break; + } +} + +static void _clock_sdmmc_config_legacy_tm() +{ + clock_t *clk = &_clock_sdmmc_legacy_tm; + if (!(CLOCK(clk->enable) & (1 << clk->index))) + clock_enable(clk); +} + +typedef struct _clock_sdmmc_t +{ + u32 clock; + u32 real_clock; +} clock_sdmmc_t; + +static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; + +#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 +#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 +#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 + +static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) +{ + u32 divisor = 0; + u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; + + if (id > SDMMC_4) + return 0; + + // Get IO clock divisor. + switch (val) + { + case 25000: + *pclock = 24728; + divisor = 31; // 16.5 div. + break; + case 26000: + *pclock = 25500; + divisor = 30; // 16 div. + break; + case 40800: + *pclock = 40800; + divisor = 18; // 10 div. + break; + case 50000: + *pclock = 48000; + divisor = 15; // 8.5 div. + break; + case 52000: + *pclock = 51000; + divisor = 14; // 8 div. + break; + case 100000: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + *pclock = 99840; + divisor = 2; // 2 div. + break; + case 164000: + *pclock = 163200; + divisor = 3; // 2.5 div. + break; + case 200000: // 240MHz evo+. + switch (id) + { + case SDMMC_1: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_2: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + case SDMMC_3: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_4: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + } + *pclock = 199680; + divisor = 0; // 1 div. + break; + default: + *pclock = 24728; + divisor = 31; // 16.5 div. + } + + _clock_sdmmc_table[id].clock = val; + _clock_sdmmc_table[id].real_clock = *pclock; + + // Enable PLLC4 if in use by any SDMMC. + if (source) + _clock_enable_pllc4(1 << id); + + // Set SDMMC legacy timeout clock. + _clock_sdmmc_config_legacy_tm(); + + // Set SDMMC clock. + switch (id) + { + case SDMMC_1: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor; + break; + case SDMMC_2: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor; + break; + case SDMMC_3: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor; + break; + case SDMMC_4: + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor; + break; + } + + return 1; +} + +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) +{ + if (_clock_sdmmc_table[id].clock == val) + { + *pclock = _clock_sdmmc_table[id].real_clock; + } + else + { + int is_enabled = _clock_sdmmc_is_enabled(id); + if (is_enabled) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_config_clock_host(pclock, id, val); + if (is_enabled) + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + } +} + +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) +{ + // Get Card clock divisor. + switch (type) + { + case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. + *pclock = 26000; + *pdivisor = 66; + break; + case SDHCI_TIMING_MMC_LS26: + *pclock = 26000; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_HS52: + *pclock = 52000; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + *pclock = 200000; + *pdivisor = 1; + break; + case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz. + *pclock = 25000; + *pdivisor = 64; + break; + case SDHCI_TIMING_SD_DS12: + case SDHCI_TIMING_UHS_SDR12: + *pclock = 25000; + *pdivisor = 1; + break; + case SDHCI_TIMING_SD_HS25: + case SDHCI_TIMING_UHS_SDR25: + *pclock = 50000; + *pdivisor = 1; + break; + case SDHCI_TIMING_UHS_SDR50: + *pclock = 100000; + *pdivisor = 1; + break; + case SDHCI_TIMING_UHS_SDR82: + *pclock = 164000; + *pdivisor = 1; + break; + case SDHCI_TIMING_UHS_DDR50: + *pclock = 40800; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz. + *pclock = 200000; + *pdivisor = 2; + break; + } +} + +int clock_sdmmc_is_not_reset_and_enabled(u32 id) +{ + return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id); +} + +void clock_sdmmc_enable(u32 id, u32 val) +{ + u32 clock = 0; + + if (_clock_sdmmc_is_enabled(id)) + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_set_reset(id); + _clock_sdmmc_config_clock_host(&clock, id, val); + _clock_sdmmc_set_enable(id); + _clock_sdmmc_is_reset(id); + usleep((100000 + clock - 1) / clock); + _clock_sdmmc_clear_reset(id); + _clock_sdmmc_is_reset(id); +} + +void clock_sdmmc_disable(u32 id) +{ + _clock_sdmmc_set_reset(id); + _clock_sdmmc_clear_enable(id); + _clock_sdmmc_is_reset(id); + _clock_disable_pllc4(1 << id); +} diff --git a/ariane/src/bdk/soc/clock.h b/ariane/src/bdk/soc/clock.h new file mode 100644 index 0000000..bbcd482 --- /dev/null +++ b/ariane/src/bdk/soc/clock.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CLOCK_H_ +#define _CLOCK_H_ + +#include + +/*! Clock registers. */ +#define CLK_RST_CONTROLLER_RST_SOURCE 0x0 +#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 +#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 +#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18 +#define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20 +#define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28 +#define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C +#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 +#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 +#define CLK_RST_CONTROLLER_OSC_CTRL 0x50 +#define CLK_RST_CONTROLLER_PLLC_BASE 0x80 +#define CLK_RST_CONTROLLER_PLLC_OUT 0x84 +#define CLK_RST_CONTROLLER_PLLC_MISC 0x88 +#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C +#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 +#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 +#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C +#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 +#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0 +#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4 +#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8 +#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC +#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0 +#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC +#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 +#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 +#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC +#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 +#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 +#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 +#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100 +#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 +#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C +#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 +#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 +#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 +#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C +#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 +#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 +#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C +#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 +#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 +#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 +#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC +#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300 +#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304 +#define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308 +#define CLK_RST_CONTROLLER_RST_DEV_H_CLR 0x30C +#define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310 +#define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314 +#define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320 +#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324 +#define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328 +#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR 0x32C +#define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330 +#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334 +#define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358 +#define CLK_RST_CONTROLLER_RST_DEVICES_W 0x35C +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364 +#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC +#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C +#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430 +#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 +#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438 +#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C +#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 +#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 +#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C +#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 +#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484 +#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 +#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C +#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 +#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 +#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 +#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C +#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 +#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 +#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 +#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 +#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C +#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 +#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC +#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 + +#define CLK_NO_SOURCE 0x0 + +/*! PLL control and status bits */ +#define PLLCX_BASE_ENABLE (1 << 30) +#define PLLCX_BASE_REF_DIS (1 << 29) +#define PLLCX_BASE_LOCK (1 << 27) + +#define PLLA_BASE_IDDQ (1 << 25) +#define PLLA_OUT0_CLKEN (1 << 1) +#define PLLA_OUT0_RSTN_CLR (1 << 0) + +#define PLLC_MISC_RESET (1 << 30) +#define PLLC_MISC1_IDDQ (1 << 27) +#define PLLC_OUT1_CLKEN (1 << 1) +#define PLLC_OUT1_RSTN_CLR (1 << 0) + +#define PLLC4_MISC_EN_LCKDET (1 << 30) +#define PLLC4_BASE_IDDQ (1 << 18) +#define PLLC4_OUT3_CLKEN (1 << 1) +#define PLLC4_OUT3_RSTN_CLR (1 << 0) + +/*! Generic clock descriptor. */ +typedef struct _clock_t +{ + u32 reset; + u32 enable; + u32 source; + u8 index; + u8 clk_src; + u8 clk_div; +} clock_t; + +/*! Generic clock enable/disable. */ +void clock_enable(const clock_t *clk); +void clock_disable(const clock_t *clk); + +/*! Clock control for specific hardware portions. */ +void clock_enable_fuse(bool enable); +void clock_enable_uart(u32 idx); +void clock_disable_uart(u32 idx); +int clock_uart_use_src_div(u32 idx, u32 baud); +void clock_enable_i2c(u32 idx); +void clock_disable_i2c(u32 idx); +void clock_enable_se(); +void clock_enable_tzram(); +void clock_enable_host1x(); +void clock_disable_host1x(); +void clock_enable_tsec(); +void clock_disable_tsec(); +void clock_enable_sor_safe(); +void clock_disable_sor_safe(); +void clock_enable_sor0(); +void clock_disable_sor0(); +void clock_enable_sor1(); +void clock_disable_sor1(); +void clock_enable_kfuse(); +void clock_disable_kfuse(); +void clock_enable_cl_dvfs(); +void clock_disable_cl_dvfs(); +void clock_enable_coresight(); +void clock_disable_coresight(); +void clock_enable_pwm(); +void clock_disable_pwm(); +void clock_enable_pllc(u32 divn); +void clock_disable_pllc(); +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type); +int clock_sdmmc_is_not_reset_and_enabled(u32 id); +void clock_sdmmc_enable(u32 id, u32 val); +void clock_sdmmc_disable(u32 id); + +#endif diff --git a/ariane/src/bdk/soc/fuse.c b/ariane/src/bdk/soc/fuse.c new file mode 100644 index 0000000..84c366d --- /dev/null +++ b/ariane/src/bdk/soc/fuse.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 shuffle2 + * Copyright (c) 2018 balika011 + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include + +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) + +static const u32 evp_thunk_template[] = { + 0xe92d0007, // STMFD SP!, {R0-R2} + 0xe1a0200e, // MOV R2, LR + 0xe2422002, // SUB R2, R2, #2 + 0xe5922000, // LDR R2, [R2] + 0xe20220ff, // AND R2, R2, #0xFF + 0xe1a02082, // MOV R2, R2,LSL#1 + 0xe59f001c, // LDR R0, =evp_thunk_template + 0xe59f101c, // LDR R1, =thunk_end + 0xe0411000, // SUB R1, R1, R0 + 0xe59f0018, // LDR R0, =iram_evp_thunks + 0xe0800001, // ADD R0, R0, R1 + 0xe0822000, // ADD R2, R2, R0 + 0xe3822001, // ORR R2, R2, #1 + 0xe8bd0003, // LDMFD SP!, {R0,R1} + 0xe12fff12, // BX R2 + 0x001007b0, // off_1007EC DCD evp_thunk_template + 0x001007f8, // off_1007F0 DCD thunk_end + 0x40004c30, // off_1007F4 DCD iram_evp_thunks + // thunk_end is here +}; +static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); + +// treated as 12bit values +static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; + +void fuse_disable_program() +{ + FUSE(FUSE_DISABLEREGPROGRAM) = 1; +} + +u32 fuse_read_odm(u32 idx) +{ + return FUSE(FUSE_RESERVED_ODMX(idx)); +} + +u32 fuse_read_odm_keygen_rev() +{ + if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) + return (fuse_read_odm(2) & 0x1F); + + return 0; +} + +void fuse_wait_idle() +{ + u32 ctrl; + do + { + ctrl = FUSE(FUSE_CTRL); + } while (((ctrl >> 16) & 0x1f) != 4); +} + +u32 fuse_read(u32 addr) +{ + FUSE(FUSE_ADDR) = addr; + FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; + fuse_wait_idle(); + return FUSE(FUSE_RDATA); +} + +void fuse_read_array(u32 *words) +{ + for (u32 i = 0; i < 192; i++) + words[i] = fuse_read(i); +} + +static u32 _parity32_even(u32 *words, u32 count) +{ + u32 acc = words[0]; + for (u32 i = 1; i < count; i++) + { + acc ^= words[i]; + } + u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; + u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; + u32 x = hi ^ lo; + lo = ((x & 0xf) ^ (x >> 4)) & 3; + hi = ((x & 0xf) ^ (x >> 4)) >> 2; + x = hi ^ lo; + + return (x & 1) ^ (x >> 1); +} + +static int _patch_hash_one(u32 *word) +{ + u32 bits20_31 = *word & 0xfff00000; + u32 parity_bit = _parity32_even(&bits20_31, 1); + u32 hash = 0; + for (u32 i = 0; i < 12; i++) + { + if (*word & (1 << (20 + i))) + { + hash ^= hash_vals[i]; + } + } + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + *word ^= 1 << 24; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) + { + if (hash_vals[i] == hash) + { + *word ^= 1 << (20 + i); + return 1; + } + } + return 2; +} + +static int _patch_hash_multi(u32 *words, u32 count) +{ + u32 parity_bit = _parity32_even(words, count); + u32 bits0_14 = words[0] & 0x7fff; + u32 bit15 = words[0] & 0x8000; + u32 bits16_19 = words[0] & 0xf0000; + + u32 hash = 0; + words[0] = bits16_19; + for (u32 i = 0; i < count; i++) + { + u32 w = words[i]; + if (w) + { + for (u32 bitpos = 0; bitpos < 32; bitpos++) + { + if ((w >> bitpos) & 1) + { + hash ^= 0x4000 + i * 32 + bitpos; + } + } + } + } + hash ^= bits0_14; + // stupid but this is what original code does. + // equivalent to original words[0] &= 0xfff00000 + words[0] = bits16_19 ^ bit15 ^ bits0_14; + + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + words[0] ^= 0x8000; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + u32 bitcount = hash - 0x4000; + if (bitcount < 16 || bitcount >= count * 32) + { + u32 num_set = 0; + for (u32 bitpos = 0; bitpos < 15; bitpos++) + { + if ((hash >> bitpos) & 1) + { + num_set++; + } + } + if (num_set != 1) + { + return 2; + } + words[0] ^= hash; + return 1; + } + words[bitcount / 32] ^= 1 << (hash & 0x1f); + return 1; +} + +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + if (ipatch_count) + { + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = words[i + 1]; + u32 addr = (word >> 16) * 2; + u32 data = word & 0xFFFF; + + ipatch(addr, data); + } + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + int evp_thunk_written = 0; + void *evp_thunk_dst_addr = 0; + + memset(iram_evp_thunks, 0, *iram_evp_thunks_len); + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + u32 insn_count = word_count - ipatch_count - 1; + if (insn_count) + { + if (!evp_thunk_written) + { + evp_thunk_dst_addr = (void *)iram_evp_thunks; + + memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); + evp_thunk_dst_addr += evp_thunk_template_len; + evp_thunk_written = 1; + *iram_evp_thunks_len = evp_thunk_template_len; + + //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); + } + + u32 thunk_patch_len = insn_count * sizeof(u32); + memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len); + evp_thunk_dst_addr += thunk_patch_len; + *iram_evp_thunks_len += thunk_patch_len; + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +bool fuse_check_patched_rcm() +{ + // Check if XUSB in use. + if (FUSE(FUSE_RESERVED_SW) & (1<<7)) + return true; + + // Check if RCM is ipatched. + u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; + u32 word_addr = 191; + + while (word_count) + { + u32 word0 = fuse_read(word_addr); + u32 ipatch_count = (word0 >> 16) & 0xF; + + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = fuse_read(word_addr - (i + 1)); + u32 addr = (word >> 16) * 2; + if (addr == 0x769A) + return true; + } + + word_addr -= word_count; + word_count = word0 >> 25; + } + + return false; +} diff --git a/ariane/src/bdk/soc/fuse.h b/ariane/src/bdk/soc/fuse.h new file mode 100644 index 0000000..e5ca2fb --- /dev/null +++ b/ariane/src/bdk/soc/fuse.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 shuffle2 + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FUSE_H_ +#define _FUSE_H_ + +#include + +/*! Fuse registers. */ +#define FUSE_CTRL 0x0 +#define FUSE_ADDR 0x4 +#define FUSE_RDATA 0x8 +#define FUSE_WDATA 0xC +#define FUSE_TIME_RD1 0x10 +#define FUSE_TIME_RD2 0x14 +#define FUSE_TIME_PGM1 0x18 +#define FUSE_TIME_PGM2 0x1C +#define FUSE_PRIV2INTFC 0x20 +#define FUSE_FUSEBYPASS 0x24 +#define FUSE_PRIVATEKEYDISABLE 0x28 +#define FUSE_DISABLEREGPROGRAM 0x2C +#define FUSE_WRITE_ACCESS_SW 0x30 +#define FUSE_PWR_GOOD_SW 0x34 +#define FUSE_SKU_INFO 0x110 +#define FUSE_CPU_SPEEDO_0_CALIB 0x114 +#define FUSE_CPU_IDDQ_CALIB 0x118 +#define FUSE_OPT_FT_REV 0x128 +#define FUSE_CPU_SPEEDO_1_CALIB 0x12C +#define FUSE_CPU_SPEEDO_2_CALIB 0x130 +#define FUSE_SOC_SPEEDO_0_CALIB 0x134 +#define FUSE_SOC_SPEEDO_1_CALIB 0x138 +#define FUSE_SOC_SPEEDO_2_CALIB 0x13C +#define FUSE_SOC_IDDQ_CALIB 0x140 +#define FUSE_OPT_CP_REV 0x190 +#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c +#define FUSE_PRIVATE_KEY0 0x1A4 +#define FUSE_PRIVATE_KEY1 0x1A8 +#define FUSE_PRIVATE_KEY2 0x1AC +#define FUSE_PRIVATE_KEY3 0x1B0 +#define FUSE_PRIVATE_KEY4 0x1B4 +#define FUSE_RESERVED_SW 0x1C0 +#define FUSE_USB_CALIB 0x1F0 +#define FUSE_SKU_DIRECT_CONFIG 0x1F4 +#define FUSE_OPT_VENDOR_CODE 0x200 +#define FUSE_OPT_FAB_CODE 0x204 +#define FUSE_OPT_LOT_CODE_0 0x208 +#define FUSE_OPT_LOT_CODE_1 0x20C +#define FUSE_OPT_WAFER_ID 0x210 +#define FUSE_OPT_X_COORDINATE 0x214 +#define FUSE_OPT_Y_COORDINATE 0x218 +#define FUSE_GPU_IDDQ_CALIB 0x228 +#define FUSE_USB_CALIB_EXT 0x350 + +/*! Fuse commands. */ +#define FUSE_READ 0x1 +#define FUSE_WRITE 0x2 +#define FUSE_SENSE 0x3 +#define FUSE_CMD_MASK 0x3 + +/*! Fuse cache registers. */ +#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) + +void fuse_disable_program(); +u32 fuse_read_odm(u32 idx); +u32 fuse_read_odm_keygen_rev(); +void fuse_wait_idle(); +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); +void fuse_read_array(u32 *words); +bool fuse_check_patched_rcm(); + +#endif diff --git a/ariane/src/bdk/soc/gpio.c b/ariane/src/bdk/soc/gpio.c new file mode 100644 index 0000000..281e867 --- /dev/null +++ b/ariane/src/bdk/soc/gpio.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#define GPIO_BANK_IDX(port) (port >> 2) + +#define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2)) + +#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2)) +#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2)) + +#define GPIO_IRQ_BANK1 32 +#define GPIO_IRQ_BANK2 33 +#define GPIO_IRQ_BANK3 34 +#define GPIO_IRQ_BANK4 35 +#define GPIO_IRQ_BANK5 55 +#define GPIO_IRQ_BANK6 87 +#define GPIO_IRQ_BANK7 89 +#define GPIO_IRQ_BANK8 125 + +static u8 gpio_bank_irq_ids[8] = { + GPIO_IRQ_BANK1, GPIO_IRQ_BANK2, GPIO_IRQ_BANK3, GPIO_IRQ_BANK4, + GPIO_IRQ_BANK5, GPIO_IRQ_BANK6, GPIO_IRQ_BANK7, GPIO_IRQ_BANK8 +}; + +void gpio_config(u32 port, u32 pins, int mode) +{ + u32 offset = GPIO_CNF_OFFSET(port); + + if (mode) + GPIO(offset) |= pins; + else + GPIO(offset) &= ~pins; + + (void)GPIO(offset); // Commit the write. +} + +void gpio_output_enable(u32 port, u32 pins, int enable) +{ + u32 port_offset = GPIO_OE_OFFSET(port); + + if (enable) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +void gpio_write(u32 port, u32 pins, int high) +{ + u32 port_offset = GPIO_OUT_OFFSET(port); + + if (high) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +int gpio_read(u32 port, u32 pins) +{ + u32 port_offset = GPIO_IN_OFFSET(port); + + return (GPIO(port_offset) & pins) ? 1 : 0; +} + +static void _gpio_interrupt_clear(u32 port, u32 pins) +{ + u32 port_offset = GPIO_INT_CLR_OFFSET(port); + + GPIO(port_offset) |= pins; + + (void)GPIO(port_offset); // Commit the write. +} + +int gpio_interrupt_status(u32 port, u32 pins) +{ + u32 port_offset = GPIO_INT_STA_OFFSET(port); + u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins; + + int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0; + + // Clear the interrupt status. + if (status) + _gpio_interrupt_clear(port, pins); + + return status; +} + +void gpio_interrupt_enable(u32 port, u32 pins, int enable) +{ + u32 port_offset = GPIO_INT_ENB_OFFSET(port); + + // Clear any possible stray interrupt. + _gpio_interrupt_clear(port, pins); + + if (enable) + GPIO(port_offset) |= pins; + else + GPIO(port_offset) &= ~pins; + + (void)GPIO(port_offset); // Commit the write. +} + +void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta) +{ + u32 port_offset = GPIO_INT_LVL_OFFSET(port); + + u32 val = GPIO(port_offset); + + if (high) + val |= pins; + else + val &= ~pins; + + if (edge) + val |= pins << 8; + else + val &= ~(pins << 8); + + if (delta) + val |= pins << 16; + else + val &= ~(pins << 16); + + GPIO(port_offset) = val; + + (void)GPIO(port_offset); // Commit the write. + + // Clear any possible stray interrupt. + _gpio_interrupt_clear(port, pins); +} + +u32 gpio_get_bank_irq_id(u32 port) +{ + u32 bank_idx = GPIO_BANK_IDX(port); + + return gpio_bank_irq_ids[bank_idx]; +} \ No newline at end of file diff --git a/ariane/src/hwinit/gpio.h b/ariane/src/bdk/soc/gpio.h similarity index 54% rename from ariane/src/hwinit/gpio.h rename to ariane/src/bdk/soc/gpio.h index 3b24782..99aed88 100644 --- a/ariane/src/hwinit/gpio.h +++ b/ariane/src/bdk/soc/gpio.h @@ -1,30 +1,44 @@ /* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef _GPIO_H_ #define _GPIO_H_ -#include "types.h" +#include #define GPIO_MODE_SPIO 0 #define GPIO_MODE_GPIO 1 + #define GPIO_OUTPUT_DISABLE 0 #define GPIO_OUTPUT_ENABLE 1 + +#define GPIO_IRQ_DISABLE 0 +#define GPIO_IRQ_ENABLE 1 + #define GPIO_LOW 0 #define GPIO_HIGH 1 +#define GPIO_FALLING 0 +#define GPIO_RISING 1 + +#define GPIO_LEVEL 0 +#define GPIO_EDGE 1 + +#define GPIO_CONFIGURED_EDGE 0 +#define GPIO_ANY_EDGE_CHANGE 1 /*! GPIO pins (0-7 for each port). */ #define GPIO_PIN_0 (1 << 0) @@ -72,18 +86,10 @@ void gpio_config(u32 port, u32 pins, int mode); void gpio_output_enable(u32 port, u32 pins, int enable); void gpio_write(u32 port, u32 pins, int high); -int gpio_read(u32 port, u32 pins); - -static inline u32 gpio_index_port(u32 index) -{ - return index >> 3; -} - -static inline u32 gpio_index_bitmask(u32 index) -{ - return 1u << (index & 7); -} - -#define GPIO_DECOMPOSE(x) gpio_index_port(x), gpio_index_bitmask(x) +int gpio_read(u32 port, u32 pins); +int gpio_interrupt_status(u32 port, u32 pins); +void gpio_interrupt_enable(u32 port, u32 pins, int enable); +void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta); +u32 gpio_get_bank_irq_id(u32 port); #endif diff --git a/ariane/src/bdk/soc/hw_init.c b/ariane/src/bdk/soc/hw_init.c new file mode 100644 index 0000000..b6b4bbd --- /dev/null +++ b/ariane/src/bdk/soc/hw_init.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern boot_cfg_t b_cfg; +extern volatile nyx_storage_t *nyx_str; + +/* + * CLK_OSC - 38.4 MHz crystal. + * CLK_M - 19.2 MHz (osc/2). + * CLK_S - 32.768 KHz (from PMIC). + * SCLK - 204MHz init (-> 408MHz -> OC). + * HCLK - 204MHz init (-> 408MHz -> OC). + * PCLK - 68MHz init (-> 136MHz -> OC/4). + */ + +void _config_oscillators() +{ + CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. + SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. + TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. + + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; + PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; + PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE. + + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. + + PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) + + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. +} + +void _config_gpios() +{ + PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; + PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + + // Set Joy-Con IsAttached direction. + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + + // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); +#endif +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); +#endif + // Set Joy-Con IsAttached mode. + gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); + + // Enable input logic for Joy-Con IsAttached and UARTB/C TX pins. + gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + + pinmux_config_i2c(I2C_1); + pinmux_config_i2c(I2C_5); + pinmux_config_uart(UART_A); + + // Configure volume up/down as inputs. + gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO); + gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); + gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); + + // Configure HOME as inputs. + // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); +} + +void _config_pmc_scratch() +{ + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. + PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL + PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; +} + +void _mbist_workaround() +{ + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + + // Set mux output to SOR1 clock switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; + // Enabled PLLD and set csi to PLLD for test pattern generation. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; + + // Clear per-clock resets. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. + usleep(2); + + // I2S channels to master and disable SLCG. + I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; + I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; + I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; + + DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. + VIC(0x8C) = 0xFFFFFFFF; + usleep(2); + + // Set per-clock reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC. + + // Enable specific clocks and disable all others. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA. + + // Disable clock gate overrides. + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; + CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; + + // Set child clock sources. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. +} + +void _config_se_brom() +{ + // Enable fuse clock. + clock_enable_fuse(true); + + // This memset needs to happen here, else TZRAM will behave weirdly later on. + memset((void *)TZRAM_BASE, 0, 0x10000); + PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; + SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; + + // Clear the boot reason to avoid problems later + PMC(APBDEV_PMC_SCRATCH200) = 0x0; + PMC(APBDEV_PMC_RST_STATUS) = 0x0; + APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); +} + +void _config_regulators() +{ + // Disable low battery shutdown monitor. + max77620_low_battery_monitor_config(false); + + // Disable SDMMC1 IO power. + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); + max77620_regulator_enable(REGULATOR_LDO2, 0); + sd_power_cycle_time_start = get_tmr_ms(); + + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, + (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + + // Configure all Flexible Power Sequencers. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + max77620_regulator_config_fps(REGULATOR_LDO4); + max77620_regulator_config_fps(REGULATOR_LDO8); + max77620_regulator_config_fps(REGULATOR_SD0); + max77620_regulator_config_fps(REGULATOR_SD1); + max77620_regulator_config_fps(REGULATOR_SD3); + + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, + (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ + + // Set vdd_core voltage to 1.125V. + max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); + + // Fix CPU/GPU after a L4T warmboot. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); + + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVS_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); +} + +void config_hw() +{ + // Bootrom stuff we skipped by going through rcm. + _config_se_brom(); + //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; + SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. + PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; + + _mbist_workaround(); + clock_enable_se(); + + // Enable fuse clock. + clock_enable_fuse(true); + + // Disable fuse programming. + fuse_disable_program(); + + mc_enable(); + + _config_oscillators(); + APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; + _config_gpios(); + +#ifdef DEBUG_UART_PORT + clock_enable_uart(DEBUG_UART_PORT); + uart_init(DEBUG_UART_PORT, 115200); +#endif + + clock_enable_cl_dvfs(); + + clock_enable_i2c(I2C_1); + clock_enable_i2c(I2C_5); + + clock_enable_tzram(); + + i2c_init(I2C_1); + i2c_init(I2C_5); + + // Enable charger in case it's disabled. + bq24193_enable_charger(); + + _config_regulators(); + + _config_pmc_scratch(); // Missing from 4.x+ + + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). + + sdram_init(); + + bpmp_mmu_enable(); + + // Clear flags from PMC_SCRATCH0 + PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD; +} + +void reconfig_hw_workaround(bool extra_reconfig, u32 magic) +{ + // Disable BPMP max clock. + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + +#ifdef NYX + // Deinit touchscreen, 5V regulators and Joy-Con. + touch_power_off(); + set_fan_duty(0); + jc_deinit(); + regulator_disable_5v(REGULATOR_5V_ALL); + clock_disable_uart(UART_B); + clock_disable_uart(UART_C); +#endif + + // Flush/disable MMU cache and set DRAM clock to 204MHz. + bpmp_mmu_disable(); + minerva_change_freq(FREQ_204); + nyx_str->mtc_cfg.init_done = 0; + + // Re-enable clocks to Audio Processing Engine as a workaround to hanging. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + + if (extra_reconfig) + { + msleep(10); + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + + clock_disable_cl_dvfs(); + + // Disable Joy-con GPIOs. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO); + } + + // Power off display. + display_end(); + + // Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits. + if (magic == 0xBAADF00D) + { + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); + sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0); + clock_disable_cl_dvfs(); + + msleep(200); + } +} diff --git a/ariane/src/bdk/soc/hw_init.h b/ariane/src/bdk/soc/hw_init.h new file mode 100644 index 0000000..d19f271 --- /dev/null +++ b/ariane/src/bdk/soc/hw_init.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _HW_INIT_H_ +#define _HW_INIT_H_ + +#include + +void config_hw(); +void reconfig_hw_workaround(bool extra_reconfig, u32 magic); + +#endif diff --git a/ariane/src/bdk/soc/i2c.c b/ariane/src/bdk/soc/i2c.c new file mode 100644 index 0000000..d3f31e7 --- /dev/null +++ b/ariane/src/bdk/soc/i2c.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include + +static const u32 i2c_addrs[] = { + 0x7000C000, 0x7000C400, 0x7000C500, + 0x7000C700, 0x7000D000, 0x7000D100 +}; + +static void _i2c_wait(vu32 *base) +{ + base[I2C_CONFIG_LOAD] = 0x25; + for (u32 i = 0; i < 20; i++) + { + usleep(1); + if (!(base[I2C_CONFIG_LOAD] & 1)) + break; + } +} + +static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) +{ + if (size > 8) + return 0; + + u32 tmp = 0; + + vu32 *base = (vu32 *)i2c_addrs[idx]; + base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). + + if (size > 4) + { + memcpy(&tmp, buf, 4); + base[I2C_CMD_DATA1] = tmp; //Set value. + tmp = 0; + memcpy(&tmp, buf + 4, size - 4); + base[I2C_CMD_DATA2] = tmp; + } + else + { + memcpy(&tmp, buf, size); + base[I2C_CMD_DATA1] = tmp; //Set value. + } + + base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. + _i2c_wait(base); //Kick transaction. + + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + + u32 timeout = get_tmr_ms() + 1500; + while (base[I2C_STATUS] & 0x100) + { + if (get_tmr_ms() > timeout) + return 0; + } + + if (base[I2C_STATUS] << 28) + return 0; + + return 1; +} + +static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) +{ + if (size > 8) + return 0; + + vu32 *base = (vu32 *)i2c_addrs[idx]; + base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). + base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. + _i2c_wait(base); // Kick transaction. + + base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; + + u32 timeout = get_tmr_ms() + 1500; + while (base[I2C_STATUS] & 0x100) + { + if (get_tmr_ms() > timeout) + return 0; + } + + if (base[I2C_STATUS] << 28) + return 0; + + u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. + if (size > 4) + { + memcpy(buf, &tmp, 4); + tmp = base[I2C_CMD_DATA2]; // Get MS value. + memcpy(buf + 4, &tmp, size - 4); + } + else + memcpy(buf, &tmp, size); + + return 1; +} + +void i2c_init(u32 idx) +{ + vu32 *base = (vu32 *)i2c_addrs[idx]; + + base[I2C_CLK_DIVISOR_REGISTER] = 0x50001; + base[I2C_BUS_CLEAR_CONFIG] = 0x90003; + _i2c_wait(base); + + for (u32 i = 0; i < 10; i++) + { + usleep(20000); + if (base[INTERRUPT_STATUS_REGISTER] & 0x800) + break; + } + + (vu32)base[I2C_BUS_CLEAR_STATUS]; + base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER]; +} + +int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) +{ + u8 tmp[4]; + + if (size > 7) + return 0; + + tmp[0] = y; + memcpy(tmp + 1, buf, size); + + return _i2c_send_pkt(idx, x, tmp, size + 1); +} + +int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x) +{ + return _i2c_recv_pkt(idx, buf, size, x); +} + +int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) +{ + int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); + if (res) + res = _i2c_recv_pkt(idx, buf, size, x); + return res; +} + +int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) +{ + return i2c_send_buf_small(idx, x, y, &b, 1); +} + +u8 i2c_recv_byte(u32 idx, u32 x, u32 y) +{ + u8 tmp = 0; + i2c_recv_buf_small(&tmp, 1, idx, x, y); + return tmp; +} + diff --git a/ariane/src/bdk/soc/i2c.h b/ariane/src/bdk/soc/i2c.h new file mode 100644 index 0000000..a630b15 --- /dev/null +++ b/ariane/src/bdk/soc/i2c.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _I2C_H_ +#define _I2C_H_ + +#include + +#define I2C_1 0 +#define I2C_2 1 +#define I2C_3 2 +#define I2C_4 3 +#define I2C_5 4 +#define I2C_6 5 + +#define I2C_CNFG 0x00 +#define I2C_CMD_ADDR0 0x01 +#define I2C_CMD_DATA1 0x03 +#define I2C_CMD_DATA2 0x04 +#define I2C_STATUS 0x07 +#define INTERRUPT_STATUS_REGISTER 0x1A +#define I2C_CLK_DIVISOR_REGISTER 0x1B +#define I2C_BUS_CLEAR_CONFIG 0x21 +#define I2C_BUS_CLEAR_STATUS 0x22 +#define I2C_CONFIG_LOAD 0x23 + +void i2c_init(u32 idx); +int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); +int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x); +int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); +int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); +u8 i2c_recv_byte(u32 idx, u32 x, u32 y); + +#endif diff --git a/ariane/src/bdk/soc/irq.c b/ariane/src/bdk/soc/irq.c new file mode 100644 index 0000000..cb34d12 --- /dev/null +++ b/ariane/src/bdk/soc/irq.c @@ -0,0 +1,263 @@ +/* + * BPMP-Lite IRQ driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "irq.h" +#include +#include +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +extern void irq_disable(); +extern void irq_enable_cpu_irq_exceptions(); +extern void irq_disable_cpu_irq_exceptions(); + +typedef struct _irq_ctxt_t +{ + u32 irq; + int (*handler)(u32 irq, void *data); + void *data; + u32 flags; +} irq_ctxt_t; + +bool irq_init_done = false; +irq_ctxt_t irqs[IRQ_MAX_HANDLERS]; + +static void _irq_enable_source(u32 irq) +{ + u32 ctrl_idx = irq >> 5; + u32 bit = irq % 32; + + // Set as normal IRQ. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~(1 << bit); + + // Enable IRQ source. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = 1 << bit; +} + +static void _irq_disable_source(u32 irq) +{ + u32 ctrl_idx = irq >> 5; + u32 bit = irq % 32; + + // Disable IRQ source. + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = 1 << bit; +} + +static void _irq_disable_and_ack_all() +{ + // Disable and ack all IRQ sources. + for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++) + { + u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER); + ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs; + ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = enabled_irqs; + } +} + +static void _irq_ack_source(u32 irq) +{ + u32 ctrl_idx = irq >> 5; + u32 bit = irq % 32; + + // Force stop the interrupt as it's serviced here. + ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = 1 << bit; +} + +void irq_free(u32 irq) +{ + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].irq == irq && irqs[idx].handler) + { + irqs[idx].irq = 0; + irqs[idx].handler = NULL; + irqs[idx].data = NULL; + irqs[idx].flags = 0; + + _irq_disable_source(irq); + } + } +} + +static void _irq_free_all() +{ + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].handler) + { + _irq_disable_source(irqs[idx].irq); + + irqs[idx].irq = 0; + irqs[idx].handler = NULL; + irqs[idx].data = NULL; + irqs[idx].flags = 0; + } + } +} + +static irq_status_t _irq_handle_source(u32 irq) +{ + int status = IRQ_NONE; + + _irq_disable_source(irq); + _irq_ack_source(irq); + + u32 idx; + for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].irq == irq) + { + status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data); + + if (status == IRQ_HANDLED) + break; + } + } + + if (irqs[idx].flags & IRQ_FLAG_ONE_OFF) + irq_free(irq); + else + _irq_enable_source(irq); + + return status; +} + +void irq_handler() +{ + // Get IRQ source. + u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF; + + if (!irq_init_done) + { + _irq_ack_source(irq); + return; + } + + DPRINTF("IRQ: %d\n", irq); + + int err = _irq_handle_source(irq); + + //TODO: disable if unhandhled. + if (err == IRQ_NONE) + gfx_printf("Unhandled IRQ: %d\n", irq); +} + +static void _irq_init() +{ + _irq_disable_and_ack_all(); + memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS); + irq_init_done = true; +} + +void irq_end() +{ + _irq_free_all(); + irq_disable_cpu_irq_exceptions(); + irq_init_done = false; +} + +void irq_wait_event(u32 irq) +{ + irq_disable_cpu_irq_exceptions(); + + _irq_enable_source(irq); + + // Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ. + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_STOP_UNTIL_IRQ; + + _irq_disable_source(irq); + _irq_ack_source(irq); + + irq_enable_cpu_irq_exceptions(); +} + +void irq_disable_wait_event() +{ + irq_enable_cpu_irq_exceptions(); +} + +irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags) +{ + if (!irq_init_done) + _irq_init(); + + for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++) + { + if (irqs[idx].handler == NULL || + (irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE)) + { + DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx); + DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags); + + irqs[idx].irq = irq; + irqs[idx].handler = handler; + irqs[idx].data = data; + irqs[idx].flags = flags; + + _irq_enable_source(irq); + + return IRQ_ENABLED; + } + else if (irqs[idx].irq == irq) + return IRQ_ALREADY_REGISTERED; + } + + return IRQ_NO_SLOTS_AVAILABLE; +} + +void __attribute__ ((target("arm"))) fiq_setup() +{ +/* + asm volatile("mrs r12, cpsr\n\t" + "bic r12, r12, #0x1F\n\t" + "orr r12, r12, #0x11\n\t" + "msr cpsr_c, r12\n\t"); + + register volatile char *text asm ("r8"); + register volatile char *uart_tx asm ("r9"); + register int len asm ("r10"); + + len = 5; + uart_tx = (char *)0x70006040; + memcpy((char *)text, "FIQ\r\n", len); + *uart_tx = 0; + + asm volatile("mrs r12, cpsr\n" + "orr r12, r12, #0x1F\n" + "msr cpsr_c, r12"); +*/ +} + +void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler() +{ +/* + register volatile char *text asm ("r8"); + register volatile char *uart_tx asm ("r9"); + register int len asm ("r10"); + + while (len) + { + *uart_tx = *text++; + len--; + } +*/ +} diff --git a/ariane/src/bdk/soc/irq.h b/ariane/src/bdk/soc/irq.h new file mode 100644 index 0000000..d33ffbe --- /dev/null +++ b/ariane/src/bdk/soc/irq.h @@ -0,0 +1,222 @@ +/* + * BPMP-Lite IRQ driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef IRQ_H +#define IRQ_H + +#include + +#define IRQ_MAX_HANDLERS 16 + +/* Primary interrupt controller ids */ +#define IRQ_TMR1 0 +#define IRQ_TMR2 1 +#define IRQ_RTC 2 +#define IRQ_CEC 3 +#define IRQ_SHR_SEM_INBOX_FULL 4 +#define IRQ_SHR_SEM_INBOX_EMPTY 5 +#define IRQ_SHR_SEM_OUTBOX_FULL 6 +#define IRQ_SHR_SEM_OUTBOX_EMPTY 7 +#define IRQ_NVJPEG 8 +#define IRQ_NVDEC 9 +#define IRQ_QUAD_SPI 10 +#define IRQ_DPAUX_INT1 11 +#define IRQ_SATA_RX_STAT 13 +#define IRQ_SDMMC1 14 +#define IRQ_SDMMC2 15 +#define IRQ_VGPIO_INT 16 +#define IRQ_VII2C_INT 17 +#define IRQ_SDMMC3 19 +#define IRQ_USB 20 +#define IRQ_USB2 21 +#define IRQ_SATA_CTL 23 +#define IRQ_PMC_INT 24 +#define IRQ_FC_INT 25 +#define IRQ_APB_DMA_CPU 26 +#define IRQ_ARB_SEM_GNT_COP 28 +#define IRQ_ARB_SEM_GNT_CPU 29 +#define IRQ_SDMMC4 31 + +/* Secondary interrupt controller ids */ +#define IRQ_GPIO1 32 +#define IRQ_GPIO2 33 +#define IRQ_GPIO3 34 +#define IRQ_GPIO4 35 +#define IRQ_UARTA 36 +#define IRQ_UARTB 37 +#define IRQ_I2C 38 +#define IRQ_USB3_HOST_INT 39 +#define IRQ_USB3_HOST_SMI 40 +#define IRQ_TMR3 41 +#define IRQ_TMR4 42 +#define IRQ_USB3_HOST_PME 43 +#define IRQ_USB3_DEV_HOST 44 +#define IRQ_ACTMON 45 +#define IRQ_UARTC 46 +#define IRQ_THERMAL 48 +#define IRQ_XUSB_PADCTL 49 +#define IRQ_TSEC 50 +#define IRQ_EDP 51 +#define IRQ_I2C5 53 +#define IRQ_GPIO5 55 +#define IRQ_USB3_DEV_SMI 56 +#define IRQ_USB3_DEV_PME 57 +#define IRQ_SE 58 +#define IRQ_SPI1 59 +#define IRQ_APB_DMA_COP 60 +#define IRQ_CLDVFS 62 +#define IRQ_I2C6 63 + +/* Tertiary interrupt controller ids */ +#define IRQ_HOST1X_SYNCPT_COP 64 +#define IRQ_HOST1X_SYNCPT_CPU 65 +#define IRQ_HOST1X_GEN_COP 66 +#define IRQ_HOST1X_GEN_CPU 67 +#define IRQ_NVENC 68 +#define IRQ_VI 69 +#define IRQ_ISPB 70 +#define IRQ_ISP 71 +#define IRQ_VIC 72 +#define IRQ_DISPLAY 73 +#define IRQ_DISPLAYB 74 +#define IRQ_SOR1 75 +#define IRQ_SOR 76 +#define IRQ_MC 77 +#define IRQ_EMC 78 +#define IRQ_TSECB 80 +#define IRQ_HDA 81 +#define IRQ_SPI2 82 +#define IRQ_SPI3 83 +#define IRQ_I2C2 84 +#define IRQ_PMU_EXT 86 +#define IRQ_GPIO6 87 +#define IRQ_GPIO7 89 +#define IRQ_UARTD 90 +#define IRQ_I2C3 92 +#define IRQ_SPI4 93 + +/* Quaternary interrupt controller ids */ +#define IRQ_DTV 96 +#define IRQ_PCIE_INT 98 +#define IRQ_PCIE_MSI 99 +#define IRQ_AVP_CACHE 101 +#define IRQ_APE_INT1 102 +#define IRQ_APE_INT0 103 +#define IRQ_APB_DMA_CH0 104 +#define IRQ_APB_DMA_CH1 105 +#define IRQ_APB_DMA_CH2 106 +#define IRQ_APB_DMA_CH3 107 +#define IRQ_APB_DMA_CH4 108 +#define IRQ_APB_DMA_CH5 109 +#define IRQ_APB_DMA_CH6 110 +#define IRQ_APB_DMA_CH7 111 +#define IRQ_APB_DMA_CH8 112 +#define IRQ_APB_DMA_CH9 113 +#define IRQ_APB_DMA_CH10 114 +#define IRQ_APB_DMA_CH11 115 +#define IRQ_APB_DMA_CH12 116 +#define IRQ_APB_DMA_CH13 117 +#define IRQ_APB_DMA_CH14 118 +#define IRQ_APB_DMA_CH15 119 +#define IRQ_I2C4 120 +#define IRQ_TMR5 121 +#define IRQ_WDT_CPU 123 +#define IRQ_WDT_AVP 124 +#define IRQ_GPIO8 125 +#define IRQ_CAR 126 + +/* Quinary interrupt controller ids */ +#define IRQ_APB_DMA_CH16 128 +#define IRQ_APB_DMA_CH17 129 +#define IRQ_APB_DMA_CH18 130 +#define IRQ_APB_DMA_CH19 131 +#define IRQ_APB_DMA_CH20 132 +#define IRQ_APB_DMA_CH21 133 +#define IRQ_APB_DMA_CH22 134 +#define IRQ_APB_DMA_CH23 135 +#define IRQ_APB_DMA_CH24 136 +#define IRQ_APB_DMA_CH25 137 +#define IRQ_APB_DMA_CH26 138 +#define IRQ_APB_DMA_CH27 139 +#define IRQ_APB_DMA_CH28 140 +#define IRQ_APB_DMA_CH29 141 +#define IRQ_APB_DMA_CH30 142 +#define IRQ_APB_DMA_CH31 143 +#define IRQ_CPU0_PMU_INTR 144 +#define IRQ_CPU1_PMU_INTR 145 +#define IRQ_CPU2_PMU_INTR 146 +#define IRQ_CPU3_PMU_INTR 147 +#define IRQ_SDMMC1_SYS 148 +#define IRQ_SDMMC2_SYS 149 +#define IRQ_SDMMC3_SYS 150 +#define IRQ_SDMMC4_SYS 151 +#define IRQ_TMR6 152 +#define IRQ_TMR7 153 +#define IRQ_TMR8 154 +#define IRQ_TMR9 155 +#define IRQ_TMR0 156 +#define IRQ_GPU_STALL 157 +#define IRQ_GPU_NONSTALL 158 +#define IRQ_DPAUX 159 + +/* Senary interrupt controller ids */ +#define IRQ_MPCORE_AXIERRIRQ 160 +#define IRQ_MPCORE_INTERRIRQ 161 +#define IRQ_EVENT_GPIO_A 162 +#define IRQ_EVENT_GPIO_B 163 +#define IRQ_EVENT_GPIO_C 164 +#define IRQ_FLOW_RSM_CPU 168 +#define IRQ_FLOW_RSM_COP 169 +#define IRQ_TMR_SHARED 170 +#define IRQ_MPCORE_CTIIRQ0 171 +#define IRQ_MPCORE_CTIIRQ1 172 +#define IRQ_MPCORE_CTIIRQ2 173 +#define IRQ_MPCORE_CTIIRQ3 174 +#define IRQ_MSELECT_ERROR 175 +#define IRQ_TMR10 176 +#define IRQ_TMR11 177 +#define IRQ_TMR12 178 +#define IRQ_TMR13 179 + +typedef int (*irq_handler_t)(u32 irq, void *data); + +typedef enum _irq_status_t +{ + IRQ_NONE = 0, + IRQ_HANDLED = 1, + IRQ_ERROR = 2, + + IRQ_ENABLED = 0, + IRQ_NO_SLOTS_AVAILABLE = 1, + IRQ_ALREADY_REGISTERED = 2 +} irq_status_t; + +typedef enum _irq_flags_t +{ + IRQ_FLAG_NONE = 0, + IRQ_FLAG_ONE_OFF = (1 << 0), + IRQ_FLAG_REPLACEABLE = (1 << 1) +} irq_flags_t; + +void irq_end(); +void irq_free(u32 irq); +void irq_wait_event(); +void irq_disable_wait_event(); +irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags); + +#endif \ No newline at end of file diff --git a/ariane/src/bdk/soc/kfuse.c b/ariane/src/bdk/soc/kfuse.c new file mode 100644 index 0000000..2da9593 --- /dev/null +++ b/ariane/src/bdk/soc/kfuse.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +int kfuse_wait_ready() +{ + // Wait for KFUSE to finish init and verification of data. + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + ; + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + return 0; + + return 1; +} + +int kfuse_read(u32 *buf) +{ + int res = 0; + + clock_enable_kfuse(); + + if (!kfuse_wait_ready()) + goto out; + + KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; + for (int i = 0; i < KFUSE_NUM_WORDS; i++) + buf[i] = KFUSE(KFUSE_KEYS); + + res = 1; + +out: + clock_disable_kfuse(); + return res; +} diff --git a/ariane/src/bdk/soc/kfuse.h b/ariane/src/bdk/soc/kfuse.h new file mode 100644 index 0000000..099dcac --- /dev/null +++ b/ariane/src/bdk/soc/kfuse.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _KFUSE_H_ +#define _KFUSE_H_ + +#include + +#define KFUSE_STATE_SOFTRESET (1 << 31) +#define KFUSE_STATE_STOP (1 << 25) +#define KFUSE_STATE_RESTART (1 << 24) +#define KFUSE_STATE_CRCPASS (1 << 17) +#define KFUSE_STATE_DONE (1 << 16) +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_CURBLOCK_MASK 0x3F + +#define KFUSE_KEYADDR_AUTOINC (1<<16) + +#define KFUSE_STATE 0x80 +#define KFUSE_KEYADDR 0x88 +#define KFUSE_KEYS 0x8C + +#define KFUSE_NUM_WORDS 144 + +int kfuse_wait_ready(); +int kfuse_read(u32 *buf); + +#endif diff --git a/ariane/src/bdk/soc/pinmux.c b/ariane/src/bdk/soc/pinmux.c new file mode 100644 index 0000000..2601cdf --- /dev/null +++ b/ariane/src/bdk/soc/pinmux.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +void pinmux_config_uart(u32 idx) +{ + PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0; + PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0; + PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN; +} + +void pinmux_config_i2c(u32 idx) +{ + PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE; + PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE; +} diff --git a/ariane/src/bdk/soc/pinmux.h b/ariane/src/bdk/soc/pinmux.h new file mode 100644 index 0000000..9a3ed5c --- /dev/null +++ b/ariane/src/bdk/soc/pinmux.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PINMUX_H_ +#define _PINMUX_H_ + +#include + +/*! APB MISC registers. */ +#define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 +#define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8 +#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 +#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 + +/*! Pinmux registers. */ +#define PINMUX_AUX_SDMMC1_CLK 0x00 +#define PINMUX_AUX_SDMMC1_CMD 0x04 +#define PINMUX_AUX_SDMMC1_DAT3 0x08 +#define PINMUX_AUX_SDMMC1_DAT2 0x0C +#define PINMUX_AUX_SDMMC1_DAT1 0x10 +#define PINMUX_AUX_SDMMC1_DAT0 0x14 +#define PINMUX_AUX_SDMMC3_CLK 0x1C +#define PINMUX_AUX_SDMMC3_CMD 0x20 +#define PINMUX_AUX_SDMMC3_DAT0 0x24 +#define PINMUX_AUX_SDMMC3_DAT1 0x28 +#define PINMUX_AUX_SDMMC3_DAT2 0x2C +#define PINMUX_AUX_SDMMC3_DAT3 0x30 +#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C +#define PINMUX_AUX_DMIC3_CLK 0xB4 +#define PINMUX_AUX_DMIC3_DAT 0xB8 +#define PINMUX_AUX_CAM_I2C_SCL 0xD4 +#define PINMUX_AUX_CAM_I2C_SDA 0xD8 +#define PINMUX_AUX_UART2_TX 0xF4 +#define PINMUX_AUX_UART3_TX 0x104 +#define PINMUX_AUX_DAP4_DIN 0x148 +#define PINMUX_AUX_DAP4_SCLK 0x150 +#define PINMUX_AUX_GPIO_X1_AUD 0x18C +#define PINMUX_AUX_GPIO_X3_AUD 0x190 +#define PINMUX_AUX_SPDIF_IN 0x1A4 +#define PINMUX_AUX_USB_VBUS_EN0 0x1A8 +#define PINMUX_AUX_USB_VBUS_EN1 0x1AC +#define PINMUX_AUX_WIFI_EN 0x1B4 +#define PINMUX_AUX_WIFI_RST 0x1B8 +#define PINMUX_AUX_AP_WAKE_NFC 0x1CC +#define PINMUX_AUX_NFC_EN 0x1D0 +#define PINMUX_AUX_NFC_INT 0x1D4 +#define PINMUX_AUX_CAM1_PWDN 0x1EC +#define PINMUX_AUX_CAM2_PWDN 0x1F0 +#define PINMUX_AUX_LCD_BL_PWM 0x1FC +#define PINMUX_AUX_LCD_BL_EN 0x200 +#define PINMUX_AUX_LCD_RST 0x204 +#define PINMUX_AUX_LCD_GPIO1 0x208 +#define PINMUX_AUX_LCD_GPIO2 0x20C +#define PINMUX_AUX_TOUCH_INT 0x220 +#define PINMUX_AUX_MOTION_INT 0x224 +#define PINMUX_AUX_BUTTON_HOME 0x240 +#define PINMUX_AUX_GPIO_PE6 0x248 +#define PINMUX_AUX_GPIO_PH6 0x250 +#define PINMUX_AUX_GPIO_PK3 0x260 +#define PINMUX_AUX_GPIO_PZ1 0x280 +/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ +#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) +#define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) +#define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x)) +#define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x)) +/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */ +#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x)) +#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x)) + +#define PINMUX_FUNC_MASK (3 << 0) + +#define PINMUX_PULL_MASK (3 << 2) +#define PINMUX_PULL_NONE (0 << 2) +#define PINMUX_PULL_DOWN (1 << 2) +#define PINMUX_PULL_UP (2 << 2) + +#define PINMUX_TRISTATE (1 << 4) +#define PINMUX_PARKED (1 << 5) +#define PINMUX_INPUT_ENABLE (1 << 6) +#define PINMUX_LOCK (1 << 7) +#define PINMUX_LPDR (1 << 8) +#define PINMUX_HSM (1 << 9) + +#define PINMUX_IO_HV (1 << 10) +#define PINMUX_OPEN_DRAIN (1 << 11) +#define PINMUX_SCHMT (1 << 12) + +#define PINMUX_DRIVE_1X (0 << 13) +#define PINMUX_DRIVE_2X (1 << 13) +#define PINMUX_DRIVE_3X (2 << 13) +#define PINMUX_DRIVE_4X (3 << 13) + +void pinmux_config_uart(u32 idx); +void pinmux_config_i2c(u32 idx); + +#endif diff --git a/ariane/src/bdk/soc/pmc.h b/ariane/src/bdk/soc/pmc.h new file mode 100644 index 0000000..7df7922 --- /dev/null +++ b/ariane/src/bdk/soc/pmc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 st4rk + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PMC_H_ +#define _PMC_H_ + +/*! PMC registers. */ +#define APBDEV_PMC_CNTRL 0x0 +#define PMC_CNTRL_MAIN_RST (1 << 4) +#define APBDEV_PMC_SEC_DISABLE 0x4 +#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 +#define APBDEV_PMC_PWRGATE_STATUS 0x38 +#define APBDEV_PMC_NO_IOPOWER 0x44 +#define PMC_NO_IOPOWER_GPIO_IO_EN (1 << 21) +#define PMC_NO_IOPOWER_AUDIO_HV (1 << 18) +#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) +#define APBDEV_PMC_SCRATCH0 0x50 +#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) +#define PMC_SCRATCH0_MODE_FASTBOOT (1 << 30) +#define PMC_SCRATCH0_MODE_PAYLOAD (1 << 29) +#define PMC_SCRATCH0_MODE_RCM (1 << 1) +#define PMC_SCRATCH0_MODE_WARMBOOT (1 << 0) +#define APBDEV_PMC_SCRATCH1 0x54 +#define APBDEV_PMC_SCRATCH20 0xA0 +#define APBDEV_PMC_PWR_DET_VAL 0xE4 +#define PMC_PWR_DET_GPIO_IO_EN (1 << 21) +#define PMC_PWR_DET_AUDIO_HV (1 << 18) +#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) +#define APBDEV_PMC_DDR_PWR 0xE8 +#define APBDEV_PMC_USB_AO 0xF0 +#define APBDEV_PMC_CRYPTO_OP 0xF4 +#define PMC_CRYPTO_OP_SE_ENABLE 0 +#define PMC_CRYPTO_OP_SE_DISABLE 1 +#define APBDEV_PMC_SCRATCH33 0x120 +#define APBDEV_PMC_SCRATCH40 0x13C +#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 +#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 +#define APBDEV_PMC_CLK_OUT_CNTRL 0x1A8 +#define PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN (1 << 2) +#define APBDEV_PMC_RST_STATUS 0x1B4 +#define APBDEV_PMC_IO_DPD_REQ 0x1B8 +#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 +#define APBDEV_PMC_VDDP_SEL 0x1CC +#define APBDEV_PMC_DDR_CFG 0x1D0 +#define APBDEV_PMC_SCRATCH45 0x234 +#define APBDEV_PMC_SCRATCH46 0x238 +#define APBDEV_PMC_SCRATCH49 0x244 +#define APBDEV_PMC_TSC_MULT 0x2B4 +#define APBDEV_PMC_SEC_DISABLE2 0x2C4 +#define APBDEV_PMC_WEAK_BIAS 0x2C8 +#define APBDEV_PMC_REG_SHORT 0x2CC +#define APBDEV_PMC_SEC_DISABLE3 0x2D8 +#define APBDEV_PMC_SECURE_SCRATCH21 0x334 +#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 +#define APBDEV_PMC_SECURE_SCRATCH32 0x360 +#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 +#define APBDEV_PMC_CNTRL2 0x440 +#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 +#define APBDEV_PMC_IO_DPD3_REQ 0x45C +#define APBDEV_PMC_IO_DPD4_REQ 0x464 +#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 +#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC +#define APBDEV_PMC_DDR_CNTRL 0x4E4 +#define APBDEV_PMC_SEC_DISABLE4 0x5B0 +#define APBDEV_PMC_SEC_DISABLE5 0x5B4 +#define APBDEV_PMC_SEC_DISABLE6 0x5B8 +#define APBDEV_PMC_SEC_DISABLE7 0x5BC +#define APBDEV_PMC_SEC_DISABLE8 0x5C0 +#define APBDEV_PMC_SCRATCH188 0x810 +#define APBDEV_PMC_SCRATCH190 0x818 +#define APBDEV_PMC_SCRATCH200 0x840 + +#endif diff --git a/ariane/src/bdk/soc/pmc_lp0_t210.h b/ariane/src/bdk/soc/pmc_lp0_t210.h new file mode 100644 index 0000000..5b87d5a --- /dev/null +++ b/ariane/src/bdk/soc/pmc_lp0_t210.h @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _TEGRA210_PMC_H_ +#define _TEGRA210_PMC_H_ + +#include + +struct tegra_pmc_regs +{ + u32 cntrl; + u32 sec_disable; + u32 pmc_swrst; + u32 wake_mask; + u32 wake_lvl; + u32 wake_status; + u32 sw_wake_status; + u32 dpd_pads_oride; + u32 dpd_sample; + u32 dpd_enable; + u32 pwrgate_timer_off; + u32 clamp_status; + u32 pwrgate_toggle; + u32 remove_clamping_cmd; + u32 pwrgate_status; + u32 pwrgood_timer; + u32 blink_timer; + u32 no_iopower; + u32 pwr_det; + u32 pwr_det_latch; + u32 scratch0; + u32 scratch1; + u32 scratch2; + u32 scratch3; + u32 scratch4; + u32 scratch5; + u32 scratch6; + u32 scratch7; + u32 scratch8; + u32 scratch9; + u32 scratch10; + u32 scratch11; + u32 scratch12; + u32 scratch13; + u32 scratch14; + u32 scratch15; + u32 scratch16; + u32 scratch17; + u32 scratch18; + u32 scratch19; + u32 odmdata; + u32 scratch21; + u32 scratch22; + u32 scratch23; + u32 secure_scratch0; + u32 secure_scratch1; + u32 secure_scratch2; + u32 secure_scratch3; + u32 secure_scratch4; + u32 secure_scratch5; + u32 cpupwrgood_timer; + u32 cpupwroff_timer; + u32 pg_mask; + u32 pg_mask_1; + u32 auto_wake_lvl; + u32 auto_wake_lvl_mask; + u32 wake_delay; + u32 pwr_det_val; + u32 ddr_pwr; + u32 usb_debounce_del; + u32 usb_a0; + u32 crypto_op; + u32 pllp_wb0_override; + u32 scratch24; + u32 scratch25; + u32 scratch26; + u32 scratch27; + u32 scratch28; + u32 scratch29; + u32 scratch30; + u32 scratch31; + u32 scratch32; + u32 scratch33; + u32 scratch34; + u32 scratch35; + u32 scratch36; + u32 scratch37; + u32 scratch38; + u32 scratch39; + u32 scratch40; + u32 scratch41; + u32 scratch42; + u32 bondout_mirror[3]; + u32 sys_33v_en; + u32 bondout_mirror_access; + u32 gate; + u32 wake2_mask; + u32 wake2_lvl; + u32 wake2_status; + u32 sw_wake2_status; + u32 auto_wake2_lvl_mask; + u32 pg_mask_2; + u32 pg_mask_ce1; + u32 pg_mask_ce2; + u32 pg_mask_ce3; + u32 pwrgate_timer_ce[7]; + u32 pcx_edpd_cntrl; + u32 osc_edpd_over; + u32 clk_out_cntrl; + u32 sata_pwrgt; + u32 sensor_ctrl; + u32 rst_status; + u32 io_dpd_req; + u32 io_dpd_status; + u32 io_dpd2_req; + u32 io_dpd2_status; + u32 sel_dpd_tim; + u32 vddp_sel; + u32 ddr_cfg; + u32 e_no_vttgen; + u8 _rsv0[4]; + u32 pllm_wb0_override_freq; + u32 test_pwrgate; + u32 pwrgate_timer_mult; + u32 dis_sel_dpd; + u32 utmip_uhsic_triggers; + u32 utmip_uhsic_saved_state; + u32 utmip_pad_cfg; + u32 utmip_term_pad_cfg; + u32 utmip_uhsic_sleep_cfg; + u32 utmip_uhsic_sleepwalk_cfg; + u32 utmip_sleepwalk_p[3]; + u32 uhsic_sleepwalk_p0; + u32 utmip_uhsic_status; + u32 utmip_uhsic_fake; + u32 bondout_mirror3[5 - 3]; + u32 secure_scratch6; + u32 secure_scratch7; + u32 scratch43; + u32 scratch44; + u32 scratch45; + u32 scratch46; + u32 scratch47; + u32 scratch48; + u32 scratch49; + u32 scratch50; + u32 scratch51; + u32 scratch52; + u32 scratch53; + u32 scratch54; + u32 scratch55; + u32 scratch0_eco; + u32 por_dpd_ctrl; + u32 scratch2_eco; + u32 utmip_uhsic_line_wakeup; + u32 utmip_bias_master_cntrl; + u32 utmip_master_config; + u32 td_pwrgate_inter_part_timer; + u32 utmip_uhsic2_triggers; + u32 utmip_uhsic2_saved_state; + u32 utmip_uhsic2_sleep_cfg; + u32 utmip_uhsic2_sleepwalk_cfg; + u32 uhsic2_sleepwalk_p1; + u32 utmip_uhsic2_status; + u32 utmip_uhsic2_fake; + u32 utmip_uhsic2_line_wakeup; + u32 utmip_master2_config; + u32 utmip_uhsic_rpd_cfg; + u32 pg_mask_ce0; + u32 pg_mask3[5 - 3]; + u32 pllm_wb0_override2; + u32 tsc_mult; + u32 cpu_vsense_override; + u32 glb_amap_cfg; + u32 sticky_bits; + u32 sec_disable2; + u32 weak_bias; + u32 reg_short; + u32 pg_mask_andor; + u8 _rsv1[0x2c]; + u32 secure_scratch8; /* offset 0x300 */ + u32 secure_scratch9; + u32 secure_scratch10; + u32 secure_scratch11; + u32 secure_scratch12; + u32 secure_scratch13; + u32 secure_scratch14; + u32 secure_scratch15; + u32 secure_scratch16; + u32 secure_scratch17; + u32 secure_scratch18; + u32 secure_scratch19; + u32 secure_scratch20; + u32 secure_scratch21; + u32 secure_scratch22; + u32 secure_scratch23; + u32 secure_scratch24; + u32 secure_scratch25; + u32 secure_scratch26; + u32 secure_scratch27; + u32 secure_scratch28; + u32 secure_scratch29; + u32 secure_scratch30; + u32 secure_scratch31; + u32 secure_scratch32; + u32 secure_scratch33; + u32 secure_scratch34; + u32 secure_scratch35; + u32 secure_scratch36; + u32 secure_scratch37; + u32 secure_scratch38; + u32 secure_scratch39; + u32 secure_scratch40; + u32 secure_scratch41; + u32 secure_scratch42; + u32 secure_scratch43; + u32 secure_scratch44; + u32 secure_scratch45; + u32 secure_scratch46; + u32 secure_scratch47; + u32 secure_scratch48; + u32 secure_scratch49; + u32 secure_scratch50; + u32 secure_scratch51; + u32 secure_scratch52; + u32 secure_scratch53; + u32 secure_scratch54; + u32 secure_scratch55; + u32 secure_scratch56; + u32 secure_scratch57; + u32 secure_scratch58; + u32 secure_scratch59; + u32 secure_scratch60; + u32 secure_scratch61; + u32 secure_scratch62; + u32 secure_scratch63; + u32 secure_scratch64; + u32 secure_scratch65; + u32 secure_scratch66; + u32 secure_scratch67; + u32 secure_scratch68; + u32 secure_scratch69; + u32 secure_scratch70; + u32 secure_scratch71; + u32 secure_scratch72; + u32 secure_scratch73; + u32 secure_scratch74; + u32 secure_scratch75; + u32 secure_scratch76; + u32 secure_scratch77; + u32 secure_scratch78; + u32 secure_scratch79; + u32 _rsv0x420[8]; + u32 cntrl2; /* 0x440 */ + u32 _rsv0x444[2]; + u32 event_counter; /* 0x44C */ + u32 fuse_control; + u32 scratch1_eco; + u32 _rsv0x458[1]; + u32 io_dpd3_req; /* 0x45C */ + u32 io_dpd3_status; + u32 io_dpd4_req; + u32 io_dpd4_status; + u32 _rsv0x46C[30]; + u32 ddr_cntrl; /* 0x4E4 */ + u32 _rsv0x4E8[70]; + u32 scratch56; /* 0x600 */ + u32 scratch57; + u32 scratch58; + u32 scratch59; + u32 scratch60; + u32 scratch61; + u32 scratch62; + u32 scratch63; + u32 scratch64; + u32 scratch65; + u32 scratch66; + u32 scratch67; + u32 scratch68; + u32 scratch69; + u32 scratch70; + u32 scratch71; + u32 scratch72; + u32 scratch73; + u32 scratch74; + u32 scratch75; + u32 scratch76; + u32 scratch77; + u32 scratch78; + u32 scratch79; + u32 scratch80; + u32 scratch81; + u32 scratch82; + u32 scratch83; + u32 scratch84; + u32 scratch85; + u32 scratch86; + u32 scratch87; + u32 scratch88; + u32 scratch89; + u32 scratch90; + u32 scratch91; + u32 scratch92; + u32 scratch93; + u32 scratch94; + u32 scratch95; + u32 scratch96; + u32 scratch97; + u32 scratch98; + u32 scratch99; + u32 scratch100; + u32 scratch101; + u32 scratch102; + u32 scratch103; + u32 scratch104; + u32 scratch105; + u32 scratch106; + u32 scratch107; + u32 scratch108; + u32 scratch109; + u32 scratch110; + u32 scratch111; + u32 scratch112; + u32 scratch113; + u32 scratch114; + u32 scratch115; + u32 scratch116; + u32 scratch117; + u32 scratch118; + u32 scratch119; + u32 scratch120; /* 0x700 */ + u32 scratch121; + u32 scratch122; + u32 scratch123; + u32 scratch124; + u32 scratch125; + u32 scratch126; + u32 scratch127; + u32 scratch128; + u32 scratch129; + u32 scratch130; + u32 scratch131; + u32 scratch132; + u32 scratch133; + u32 scratch134; + u32 scratch135; + u32 scratch136; + u32 scratch137; + u32 scratch138; + u32 scratch139; + u32 scratch140; + u32 scratch141; + u32 scratch142; + u32 scratch143; + u32 scratch144; + u32 scratch145; + u32 scratch146; + u32 scratch147; + u32 scratch148; + u32 scratch149; + u32 scratch150; + u32 scratch151; + u32 scratch152; + u32 scratch153; + u32 scratch154; + u32 scratch155; + u32 scratch156; + u32 scratch157; + u32 scratch158; + u32 scratch159; + u32 scratch160; + u32 scratch161; + u32 scratch162; + u32 scratch163; + u32 scratch164; + u32 scratch165; + u32 scratch166; + u32 scratch167; + u32 scratch168; + u32 scratch169; + u32 scratch170; + u32 scratch171; + u32 scratch172; + u32 scratch173; + u32 scratch174; + u32 scratch175; + u32 scratch176; + u32 scratch177; + u32 scratch178; + u32 scratch179; + u32 scratch180; + u32 scratch181; + u32 scratch182; + u32 scratch183; + u32 scratch184; + u32 scratch185; + u32 scratch186; + u32 scratch187; + u32 scratch188; + u32 scratch189; + u32 scratch190; + u32 scratch191; + u32 scratch192; + u32 scratch193; + u32 scratch194; + u32 scratch195; + u32 scratch196; + u32 scratch197; + u32 scratch198; + u32 scratch199; + u32 scratch200; + u32 scratch201; + u32 scratch202; + u32 scratch203; + u32 scratch204; + u32 scratch205; + u32 scratch206; + u32 scratch207; + u32 scratch208; + u32 scratch209; + u32 scratch210; + u32 scratch211; + u32 scratch212; + u32 scratch213; + u32 scratch214; + u32 scratch215; + u32 scratch216; + u32 scratch217; + u32 scratch218; + u32 scratch219; + u32 scratch220; + u32 scratch221; + u32 scratch222; + u32 scratch223; + u32 scratch224; + u32 scratch225; + u32 scratch226; + u32 scratch227; + u32 scratch228; + u32 scratch229; + u32 scratch230; + u32 scratch231; + u32 scratch232; + u32 scratch233; + u32 scratch234; + u32 scratch235; + u32 scratch236; + u32 scratch237; + u32 scratch238; + u32 scratch239; + u32 scratch240; + u32 scratch241; + u32 scratch242; + u32 scratch243; + u32 scratch244; + u32 scratch245; + u32 scratch246; + u32 scratch247; + u32 scratch248; + u32 scratch249; + u32 scratch250; + u32 scratch251; + u32 scratch252; + u32 scratch253; + u32 scratch254; + u32 scratch255; + u32 scratch256; + u32 scratch257; + u32 scratch258; + u32 scratch259; + u32 scratch260; + u32 scratch261; + u32 scratch262; + u32 scratch263; + u32 scratch264; + u32 scratch265; + u32 scratch266; + u32 scratch267; + u32 scratch268; + u32 scratch269; + u32 scratch270; + u32 scratch271; + u32 scratch272; + u32 scratch273; + u32 scratch274; + u32 scratch275; + u32 scratch276; + u32 scratch277; + u32 scratch278; + u32 scratch279; + u32 scratch280; + u32 scratch281; + u32 scratch282; + u32 scratch283; + u32 scratch284; + u32 scratch285; + u32 scratch286; + u32 scratch287; + u32 scratch288; + u32 scratch289; + u32 scratch290; + u32 scratch291; + u32 scratch292; + u32 scratch293; + u32 scratch294; + u32 scratch295; + u32 scratch296; + u32 scratch297; + u32 scratch298; + u32 scratch299; /* 0x9CC */ + u32 _rsv0x9D0[50]; + u32 secure_scratch80; /* 0xa98 */ + u32 secure_scratch81; + u32 secure_scratch82; + u32 secure_scratch83; + u32 secure_scratch84; + u32 secure_scratch85; + u32 secure_scratch86; + u32 secure_scratch87; + u32 secure_scratch88; + u32 secure_scratch89; + u32 secure_scratch90; + u32 secure_scratch91; + u32 secure_scratch92; + u32 secure_scratch93; + u32 secure_scratch94; + u32 secure_scratch95; + u32 secure_scratch96; + u32 secure_scratch97; + u32 secure_scratch98; + u32 secure_scratch99; + u32 secure_scratch100; + u32 secure_scratch101; + u32 secure_scratch102; + u32 secure_scratch103; + u32 secure_scratch104; + u32 secure_scratch105; + u32 secure_scratch106; + u32 secure_scratch107; + u32 secure_scratch108; + u32 secure_scratch109; + u32 secure_scratch110; + u32 secure_scratch111; + u32 secure_scratch112; + u32 secure_scratch113; + u32 secure_scratch114; + u32 secure_scratch115; + u32 secure_scratch116; + u32 secure_scratch117; + u32 secure_scratch118; + u32 secure_scratch119; +}; + +#endif /* _TEGRA210_PMC_H_ */ diff --git a/ariane/src/bdk/soc/t210.h b/ariane/src/bdk/soc/t210.h new file mode 100644 index 0000000..78432c1 --- /dev/null +++ b/ariane/src/bdk/soc/t210.h @@ -0,0 +1,288 @@ +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _T210_H_ +#define _T210_H_ + +#include + +#define BOOTROM_BASE 0x100000 +#define IRAM_BASE 0x40000000 +#define HOST1X_BASE 0x50000000 +#define BPMP_CACHE_BASE 0x50040000 +#define DISPLAY_A_BASE 0x54200000 +#define DSI_BASE 0x54300000 +#define VIC_BASE 0x54340000 +#define TSEC_BASE 0x54500000 +#define SOR1_BASE 0x54580000 +#define ICTLR_BASE 0x60004000 +#define TMR_BASE 0x60005000 +#define CLOCK_BASE 0x60006000 +#define FLOW_CTLR_BASE 0x60007000 +#define AHBDMA_BASE 0x60008000 +#define SYSREG_BASE 0x6000C000 +#define SB_BASE (SYSREG_BASE + 0x200) +#define GPIO_BASE 0x6000D000 +#define GPIO_1_BASE (GPIO_BASE) +#define GPIO_2_BASE (GPIO_BASE + 0x100) +#define GPIO_3_BASE (GPIO_BASE + 0x200) +#define GPIO_4_BASE (GPIO_BASE + 0x300) +#define GPIO_5_BASE (GPIO_BASE + 0x400) +#define GPIO_6_BASE (GPIO_BASE + 0x500) +#define GPIO_7_BASE (GPIO_BASE + 0x600) +#define GPIO_8_BASE (GPIO_BASE + 0x700) +#define EXCP_VEC_BASE 0x6000F000 +#define IPATCH_BASE 0x6001DC00 +#define APBDMA_BASE 0x60020000 +#define APB_MISC_BASE 0x70000000 +#define PINMUX_AUX_BASE 0x70003000 +#define UART_BASE 0x70006000 +#define PWM_BASE 0x7000A000 +#define RTC_BASE 0x7000E000 +#define PMC_BASE 0x7000E400 +#define SYSCTR0_BASE 0x700F0000 +#define FUSE_BASE 0x7000F800 +#define KFUSE_BASE 0x7000FC00 +#define SE_BASE 0x70012000 +#define MC_BASE 0x70019000 +#define EMC_BASE 0x7001B000 +#define EMC0_BASE 0x7001E000 +#define EMC1_BASE 0x7001F000 +#define MIPI_CAL_BASE 0x700E3000 +#define CL_DVFS_BASE 0x70110000 +#define I2S_BASE 0x702D1000 +#define ADMA_BASE 0x702E2000 +#define TZRAM_BASE 0x7C010000 +#define USB_BASE 0x7D000000 +#define USB_OTG_BASE USB_BASE +#define USB1_BASE 0x7D004000 + +#define _REG(base, off) *(vu32 *)((base) + (off)) + +#define HOST1X(off) _REG(HOST1X_BASE, off) +#define BPMP_CACHE_CTRL(off) _REG(BPMP_CACHE_BASE, off) +#define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off) +#define DSI(off) _REG(DSI_BASE, off) +#define VIC(off) _REG(VIC_BASE, off) +#define TSEC(off) _REG(TSEC_BASE, off) +#define SOR1(off) _REG(SOR1_BASE, off) +#define ICTLR(cidx, off) _REG(ICTLR_BASE + (0x100 * cidx), off) +#define TMR(off) _REG(TMR_BASE, off) +#define CLOCK(off) _REG(CLOCK_BASE, off) +#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) +#define SYSREG(off) _REG(SYSREG_BASE, off) +#define AHB_GIZMO(off) _REG(SYSREG_BASE, off) +#define SB(off) _REG(SB_BASE, off) +#define GPIO(off) _REG(GPIO_BASE, off) +#define GPIO_1(off) _REG(GPIO_1_BASE, off) +#define GPIO_2(off) _REG(GPIO_2_BASE, off) +#define GPIO_3(off) _REG(GPIO_3_BASE, off) +#define GPIO_4(off) _REG(GPIO_4_BASE, off) +#define GPIO_5(off) _REG(GPIO_5_BASE, off) +#define GPIO_6(off) _REG(GPIO_6_BASE, off) +#define GPIO_7(off) _REG(GPIO_7_BASE, off) +#define GPIO_8(off) _REG(GPIO_8_BASE, off) +#define EXCP_VEC(off) _REG(EXCP_VEC_BASE, off) +#define APB_MISC(off) _REG(APB_MISC_BASE, off) +#define PINMUX_AUX(off) _REG(PINMUX_AUX_BASE, off) +#define PWM(off) _REG(PWM_BASE, off) +#define RTC(off) _REG(RTC_BASE, off) +#define PMC(off) _REG(PMC_BASE, off) +#define SYSCTR0(off) _REG(SYSCTR0_BASE, off) +#define FUSE(off) _REG(FUSE_BASE, off) +#define KFUSE(off) _REG(KFUSE_BASE, off) +#define SE(off) _REG(SE_BASE, off) +#define MC(off) _REG(MC_BASE, off) +#define EMC(off) _REG(EMC_BASE, off) +#define EMC_CH0(off) _REG(EMC0_BASE, off) +#define EMC_CH1(off) _REG(EMC1_BASE, off) +#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) +#define CL_DVFS(off) _REG(CL_DVFS_BASE, off) +#define I2S(off) _REG(I2S_BASE, off) +#define ADMA(off) _REG(ADMA_BASE, off) +#define USB(off) _REG(USB_BASE, off) +#define USB1(off) _REG(USB1_BASE, off) +#define TEST_REG(off) _REG(0x0, off) + +/* HOST1X registers. */ +#define HOST1X_CH0_SYNC_BASE 0x2100 +#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4) +#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200) + +/*! EVP registers. */ +#define EVP_CPU_RESET_VECTOR 0x100 +#define EVP_COP_RESET_VECTOR 0x200 +#define EVP_COP_UNDEF_VECTOR 0x204 +#define EVP_COP_SWI_VECTOR 0x208 +#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C +#define EVP_COP_DATA_ABORT_VECTOR 0x210 +#define EVP_COP_RSVD_VECTOR 0x214 +#define EVP_COP_IRQ_VECTOR 0x218 +#define EVP_COP_FIQ_VECTOR 0x21C +#define EVP_COP_IRQ_STS 0x220 + +/*! Primary Interrupt Controller registers. */ +#define PRI_ICTLR_FIR 0x14 +#define PRI_ICTLR_FIR_SET 0x18 +#define PRI_ICTLR_FIR_CLR 0x1C +#define PRI_ICTLR_CPU_IER 0x20 +#define PRI_ICTLR_CPU_IER_SET 0x24 +#define PRI_ICTLR_CPU_IER_CLR 0x28 +#define PRI_ICTLR_CPU_IEP_CLASS 0x2C +#define PRI_ICTLR_COP_IER 0x30 +#define PRI_ICTLR_COP_IER_SET 0x34 +#define PRI_ICTLR_COP_IER_CLR 0x38 +#define PRI_ICTLR_COP_IEP_CLASS 0x3C + +/*! AHB Gizmo registers. */ +#define AHB_ARBITRATION_PRIORITY_CTRL 0x8 +#define ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE (1 << 6) +#define AHB_GIZMO_AHB_MEM 0x10 +#define AHB_MEM_ENB_FAST_REARBITRATE (1 << 2) +#define AHB_GIZMO_USB 0x20 +#define AHB_GIZMO_USB_IMMEDIATE (1 << 18) +#define AHB_AHB_MEM_PREFETCH_CFG1 0xF0 +#define MEM_PREFETCH_ENABLE (1 << 31) +#define MEM_PREFETCH_AHB_MST_USB 6 + +/*! Misc registers. */ +#define APB_MISC_PP_STRAPPING_OPT_A 0x08 +#define APB_MISC_PP_PINMUX_GLOBAL 0x40 +#define APB_MISC_GP_HIDREV 0x804 +#define GP_HIDREV_MAJOR_T210 0x1 +#define GP_HIDREV_MAJOR_T210B01 0x2 +#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4 +#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 +#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 +#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C +#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 +#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC +#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 +#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 + +/*! System registers. */ +#define AHB_ARBITRATION_XBAR_CTRL 0xE0 +#define AHB_AHB_SPARE_REG 0x110 + +/*! Secure boot registers. */ +#define SB_CSR 0x0 +#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) +#define SB_CSR_PIROM_DISABLE (1 << 4) +#define SB_AA64_RESET_LOW 0x30 +#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) +#define SB_AA64_RESET_HIGH 0x34 + +/*! SOR registers. */ +#define SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB 0x1E8 +#define SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB 0x21C +#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB 0x208 +#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB 0x20C + +/*! RTC registers. */ +#define APBDEV_RTC_SECONDS 0x8 +#define APBDEV_RTC_SHADOW_SECONDS 0xC +#define APBDEV_RTC_MILLI_SECONDS 0x10 + +/*! SYSCTR0 registers. */ +#define SYSCTR0_CNTFID0 0x20 +#define SYSCTR0_CNTCR 0x00 +#define SYSCTR0_COUNTERID0 0xFE0 +#define SYSCTR0_COUNTERID1 0xFE4 +#define SYSCTR0_COUNTERID2 0xFE8 +#define SYSCTR0_COUNTERID3 0xFEC +#define SYSCTR0_COUNTERID4 0xFD0 +#define SYSCTR0_COUNTERID5 0xFD4 +#define SYSCTR0_COUNTERID6 0xFD8 +#define SYSCTR0_COUNTERID7 0xFDC +#define SYSCTR0_COUNTERID8 0xFF0 +#define SYSCTR0_COUNTERID9 0xFF4 +#define SYSCTR0_COUNTERID10 0xFF8 +#define SYSCTR0_COUNTERID11 0xFFC + +/*! TMR registers. */ +#define TIMERUS_CNTR_1US (0x10 + 0x0) +#define TIMERUS_USEC_CFG (0x10 + 0x4) +#define TIMER_TMR8_TMR_PTV 0x78 +#define TIMER_TMR9_TMR_PTV 0x80 +#define TIMER_EN (1 << 31) +#define TIMER_PER_EN (1 << 30) +#define TIMER_TMR8_TMR_PCR 0x7C +#define TIMER_TMR9_TMR_PCR 0x8C +#define TIMER_INTR_CLR (1 << 30) + +#define TIMER_WDT4_CONFIG (0x100 + 0x80) +#define TIMER_SRC(TMR) (TMR & 0xF) +#define TIMER_PER(PER) ((PER & 0xFF) << 4) +#define TIMER_SYSRESET_EN (1 << 14) +#define TIMER_PMCRESET_EN (1 << 15) +#define TIMER_WDT4_COMMAND (0x108 + 0x80) +#define TIMER_START_CNT (1 << 0) +#define TIMER_CNT_DISABLE (1 << 1) +#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) +#define TIMER_MAGIC_PTRN 0xC45A + +/*! I2S registers. */ +#define I2S1_CG 0x88 +#define I2S1_CTRL 0xA0 +#define I2S2_CG 0x188 +#define I2S2_CTRL 0x1A0 +#define I2S3_CG 0x288 +#define I2S3_CTRL 0x2A0 +#define I2S4_CG 0x388 +#define I2S4_CTRL 0x3A0 +#define I2S5_CG 0x488 +#define I2S5_CTRL 0x4A0 +#define I2S_CG_SLCG_ENABLE (1 << 0) +#define I2S_CTRL_MASTER_EN (1 << 10) + +/*! PWM registers. */ +#define PWM_CONTROLLER_PWM_CSR_0 0x00 +#define PWM_CONTROLLER_PWM_CSR_1 0x10 +#define PWM_CSR_EN (1 << 31) + +/*! Special registers. */ +#define EMC_SCRATCH0 0x324 +#define EMC_HEKA_UPD (1 << 30) +#define EMC_SEPT_RUN (1 << 31) + +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define HALT_COP_GIC_IRQ (1 << 9) +#define HALT_COP_LIC_IRQ (1 << 11) +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_STOP_UNTIL_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 + +/*! USB controller registers. */ +#define USB1_UTMIP_BAT_CHRG_CFG0 0x830 +#define BAT_CHRG_CFG0_OP_SRC_EN (1 << 3) +#define BAT_CHRG_CFG0_PWRDOWN_CHRG (1 << 0) + +#endif diff --git a/ariane/src/bdk/soc/uart.c b/ariane/src/bdk/soc/uart.c new file mode 100644 index 0000000..75e18b8 --- /dev/null +++ b/ariane/src/bdk/soc/uart.c @@ -0,0 +1,169 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2020 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include +#include +#include + +/* UART A, B, C, D and E. */ +static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 }; + +void uart_init(u32 idx, u32 baud) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + // Make sure no data is being sent. + uart_wait_idle(idx, UART_TX_IDLE); + + // Set clock. + bool clk_type = clock_uart_use_src_div(idx, baud); + + // Misc settings. + u32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST. + uart->UART_IER_DLAB = 0; // Disable interrupts. + uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode. + uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB. + uart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB. + uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB. + (void)uart->UART_SPR; + + // Setup and flush fifo. + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO; + (void)uart->UART_SPR; + usleep(20); + uart->UART_MCR = 0; // Disable hardware flow control. + usleep(96); + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; + + // Wait 3 symbols for baudrate change. + usleep(3 * ((baud + 999999) / baud)); + uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE); +} + +void uart_wait_idle(u32 idx, u32 which) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + if (UART_TX_IDLE & which) + { + while (!(uart->UART_LSR & UART_LSR_TMTY)) + ; + } + if (UART_RX_IDLE & which) + { + while (uart->UART_LSR & UART_LSR_RDR) + ; + } +} + +void uart_send(u32 idx, const u8 *buf, u32 len) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + for (u32 i = 0; i != len; i++) + { + while (!(uart->UART_LSR & UART_LSR_THRE)) + ; + uart->UART_THR_DLAB = buf[i]; + } +} + +u32 uart_recv(u32 idx, u8 *buf, u32 len) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + u32 timeout = get_tmr_us() + 250; + u32 i; + + for (i = 0; ; i++) + { + while (!(uart->UART_LSR & UART_LSR_RDR)) + { + if (timeout < get_tmr_us()) + break; + if (len && len < i) + break; + } + if (timeout < get_tmr_us()) + break; + + buf[i] = uart->UART_THR_DLAB; + timeout = get_tmr_us() + 250; + } + + return i ? (len ? (i - 1) : i) : 0; +} + +void uart_invert(u32 idx, bool enable, u32 invert_mask) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + if (enable) + uart->UART_IRDA_CSR |= invert_mask; + else + uart->UART_IRDA_CSR &= ~invert_mask; + (void)uart->UART_SPR; +} + +u32 uart_get_IIR(u32 idx) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + return uart->UART_IIR_FCR; +} + +void uart_set_IIR(u32 idx) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD; + (void)uart->UART_SPR; + uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD; + (void)uart->UART_SPR; +} + +void uart_empty_fifo(u32 idx, u32 which) +{ + uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); + + uart->UART_MCR = 0; + (void)uart->UART_SPR; + usleep(96); + + uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR; + (void)uart->UART_SPR; + usleep(18); + u32 tries = 0; + + if (UART_IIR_FCR_TX_CLR & which) + { + while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY) + { + tries++; + usleep(100); + } + tries = 0; + } + + if (UART_IIR_FCR_RX_CLR & which) + { + while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR) + { + tries++; + usleep(100); + } + } +} diff --git a/ariane/src/hwinit/uart.h b/ariane/src/bdk/soc/uart.h similarity index 60% rename from ariane/src/hwinit/uart.h rename to ariane/src/bdk/soc/uart.h index 9afcd11..809192a 100644 --- a/ariane/src/hwinit/uart.h +++ b/ariane/src/bdk/soc/uart.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,20 +18,45 @@ #ifndef _UART_H_ #define _UART_H_ -#include "types.h" +#include #define UART_A 0 #define UART_B 1 #define UART_C 2 #define UART_D 3 +#define UART_E 4 #define BAUD_115200 115200 -#define UART_TX_IDLE 0x00000001 -#define UART_RX_IDLE 0x00000002 +#define UART_TX_IDLE 0x1 +#define UART_RX_IDLE 0x2 + #define UART_TX_FIFO_FULL 0x100 #define UART_RX_FIFO_EMPTY 0x200 +#define UART_INVERT_RXD 0x01 +#define UART_INVERT_TXD 0x02 +#define UART_INVERT_CTS 0x04 +#define UART_INVERT_RTS 0x08 + +#define UART_IER_DLAB_IE_EORD 0x20 + +#define UART_LCR_DLAB 0x80 +#define UART_LCR_STOP 0x4 +#define UART_LCR_WORD_LENGTH_8 0x3 + +#define UART_LSR_RDR 0x1 +#define UART_LSR_THRE 0x20 +#define UART_LSR_TMTY 0x40 +#define UART_LSR_FIFOE 0x80 + +#define UART_IIR_FCR_TX_CLR 0x4 +#define UART_IIR_FCR_RX_CLR 0x2 +#define UART_IIR_FCR_EN_FIFO 0x1 + +#define UART_MCR_RTS 0x2 +#define UART_MCR_DTR 0x1 + typedef struct _uart_t { /* 0x00 */ vu32 UART_THR_DLAB; @@ -51,9 +77,11 @@ typedef struct _uart_t void uart_init(u32 idx, u32 baud); void uart_wait_idle(u32 idx, u32 which); -void uart_send(u32 idx, u8 *buf, u32 len); -void uart_print(u32 idx, const char* buf, u32 len); -u32 uart_has_bytes(u32 idx); -u8 uart_recv(u32 idx); +void uart_send(u32 idx, const u8 *buf, u32 len); +u32 uart_recv(u32 idx, u8 *buf, u32 len); +void uart_invert(u32 idx, bool enable, u32 invert_mask); +u32 uart_get_IIR(u32 idx); +void uart_set_IIR(u32 idx); +void uart_empty_fifo(u32 idx, u32 which); #endif diff --git a/ariane/src/bdk/storage/mbr_gpt.h b/ariane/src/bdk/storage/mbr_gpt.h new file mode 100644 index 0000000..9e0e97d --- /dev/null +++ b/ariane/src/bdk/storage/mbr_gpt.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MBR_GPT_H +#define MBR_GPT_H + +#include + +typedef struct _mbr_chs_t +{ + u8 head; + u8 sector; + u8 cylinder; +} __attribute__((packed)) mbr_chs_t; + +typedef struct _mbr_part_t +{ + u8 status; + mbr_chs_t start_sct_chs; + u8 type; + mbr_chs_t end_sct_chs; + u32 start_sct; + u32 size_sct; +} __attribute__((packed)) mbr_part_t; + +typedef struct _mbr_t +{ + u8 bootstrap[440]; + u32 signature; + u16 copy_protected; + mbr_part_t partitions[4]; + u16 boot_signature; +} __attribute__((packed)) mbr_t; + +typedef struct _gpt_entry_t +{ + u8 type_guid[0x10]; + u8 part_guid[0x10]; + u64 lba_start; + u64 lba_end; + u64 attrs; + u16 name[36]; +} gpt_entry_t; + +typedef struct _gpt_header_t +{ + u64 signature; // "EFI PART" + u32 revision; + u32 size; + u32 crc32; + u32 res1; + u64 my_lba; + u64 alt_lba; + u64 first_use_lba; + u64 last_use_lba; + u8 disk_guid[0x10]; + u64 part_ent_lba; + u32 num_part_ents; + u32 part_ent_size; + u32 part_ents_crc32; + u8 res2[420]; // Used as first 3 partition entries backup for HOS. +} gpt_header_t; + +typedef struct _gpt_t +{ + gpt_header_t header; + gpt_entry_t entries[128]; +} gpt_t; + +#endif diff --git a/ariane/src/hwinit/mmc.h b/ariane/src/bdk/storage/mmc.h similarity index 95% rename from ariane/src/hwinit/mmc.h rename to ariane/src/bdk/storage/mmc.h index a3beea6..0d87e35 100644 --- a/ariane/src/hwinit/mmc.h +++ b/ariane/src/bdk/storage/mmc.h @@ -1,25 +1,25 @@ /* -* Header for MultiMediaCard (MMC) -* -* Copyright 2002 Hewlett-Packard Company -* -* Use consistent with the GNU GPL is permitted, -* provided that this copyright notice is -* preserved in its entirety in all copies and derived works. -* -* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, -* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS -* FITNESS FOR ANY PARTICULAR PURPOSE. -* -* Many thanks to Alessandro Rubini and Jonathan Corbet! -* -* Based strongly on code by: -* -* Author: Yong-iL Joh -* -* Author: Andrew Christian -* 15 May 2002 -*/ + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh + * + * Author: Andrew Christian + * 15 May 2002 + */ #ifndef LINUX_MMC_MMC_H #define LINUX_MMC_MMC_H @@ -31,7 +31,7 @@ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ -#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ +#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ @@ -51,7 +51,7 @@ #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ -#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ +#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ /* class 3 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ diff --git a/ariane/src/bdk/storage/nx_sd.h b/ariane/src/bdk/storage/nx_sd.h new file mode 100644 index 0000000..8651666 --- /dev/null +++ b/ariane/src/bdk/storage/nx_sd.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NX_SD_H +#define NX_SD_H + +#include +#include +#include + +enum +{ + SD_INIT_FAIL = 0, + SD_1BIT_HS25 = 1, + SD_4BIT_HS25 = 2, + SD_UHS_SDR82 = 3, + SD_UHS_SDR104 = 4 +}; + +enum +{ + SD_ERROR_INIT_FAIL = 0, + SD_ERROR_RW_FAIL = 1, + SD_ERROR_RW_RETRY = 2 +}; + +extern sdmmc_t sd_sdmmc; +extern sdmmc_storage_t sd_storage; +extern FATFS sd_fs; + +void sd_error_count_increment(u8 type); +u16 *sd_get_error_count(); +bool sd_get_card_removed(); +u32 sd_get_mode(); +int sd_init_retry(bool power_cycle); +bool sd_initialize(bool power_cycle); +bool sd_mount(); +void sd_unmount(); +void sd_end(); +void *sd_file_read(const char *path, u32 *fsize); +int sd_save_to_file(void *buf, u32 size, const char *filename); +bool sdmounted(); + +#endif diff --git a/ariane/src/bdk/storage/ramdisk.c b/ariane/src/bdk/storage/ramdisk.c new file mode 100644 index 0000000..e7b7c01 --- /dev/null +++ b/ariane/src/bdk/storage/ramdisk.c @@ -0,0 +1,67 @@ +/* + * Ramdisk driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ramdisk.h" +#include +#include + +#include + +int ram_disk_init(FATFS *ram_fs) +{ + int res; + u8 *buf = malloc(0x400000); + + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + + res = f_mkfs("ram:", FM_EXFAT, RAMDISK_CLUSTER_SZ, buf, 0x400000); // Format as exFAT w/ 32KB cluster. + if (!res) + res = f_mount(ram_fs, "ram:", 1); // Mount ramdisk. + + free(buf); + + return res; +} + +int ram_disk_read(u32 sector, u32 sector_count, void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + return 1; + + memcpy(buf, (void *)sector_off, bytes_count); + + return 0; +} + +int ram_disk_write(u32 sector, u32 sector_count, const void *buf) +{ + u32 sector_off = RAM_DISK_ADDR + (sector << 9); + u32 bytes_count = sector_count << 9; + + if ((sector_off - RAM_DISK_ADDR) > RAM_DISK_SZ) + return 1; + + memcpy((void *)sector_off, buf, bytes_count); + + return 0; +} diff --git a/ariane/src/bdk/storage/ramdisk.h b/ariane/src/bdk/storage/ramdisk.h new file mode 100644 index 0000000..ef43bb5 --- /dev/null +++ b/ariane/src/bdk/storage/ramdisk.h @@ -0,0 +1,30 @@ +/* + * Ramdisk driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef RAM_DISK_H +#define RAM_DISK_H + +#include + +#define RAMDISK_CLUSTER_SZ 32768 + +int ram_disk_init(FATFS *ram_fs); +int ram_disk_read(u32 sector, u32 sector_count, void *buf); +int ram_disk_write(u32 sector, u32 sector_count, const void *buf); + +#endif \ No newline at end of file diff --git a/ariane/src/hwinit/sd.h b/ariane/src/bdk/storage/sd.h similarity index 81% rename from ariane/src/hwinit/sd.h rename to ariane/src/bdk/storage/sd.h index 9575810..a780ec8 100644 --- a/ariane/src/hwinit/sd.h +++ b/ariane/src/bdk/storage/sd.h @@ -1,16 +1,15 @@ /* -* include/linux/mmc/sd.h -* -* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -*/ + * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ -#ifndef LINUX_MMC_SD_H -#define LINUX_MMC_SD_H +#ifndef MMC_SD_H +#define MMC_SD_H /* SD commands type argument response */ /* class 0 */ @@ -39,7 +38,9 @@ #define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ #define SD_OCR_XPC (1 << 28) /* SDXC power control */ #define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ +#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ #define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ /* * SD_SWITCH argument format: @@ -65,7 +66,6 @@ /* * SCR field definitions */ - #define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ #define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ #define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ @@ -104,6 +104,11 @@ #define SD_SET_CURRENT_LIMIT_600 2 #define SD_SET_CURRENT_LIMIT_800 3 +#define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200) +#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400) +#define SD_MAX_CURRENT_600 (1 << SD_SET_CURRENT_LIMIT_600) +#define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800) + /* * SD_SWITCH mode */ diff --git a/ariane/src/hwinit/sdmmc.c b/ariane/src/bdk/storage/sdmmc.c similarity index 72% rename from ariane/src/hwinit/sdmmc.c rename to ariane/src/bdk/storage/sdmmc.c index f350562..fc41458 100644 --- a/ariane/src/hwinit/sdmmc.c +++ b/ariane/src/bdk/storage/sdmmc.c @@ -1,31 +1,34 @@ /* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include -#include "sdmmc.h" -#include "mmc.h" -#include "sd.h" -#include "timer.h" +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef SDMMC_DEBUGGING -#include "lib/printk.h" -#define DPRINTF(...) dbg_print(__VA_ARGS__) -#else +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -#endif + +u32 sd_power_cycle_time_start; static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) { @@ -70,6 +73,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re if (_sdmmc_storage_check_result(*resp)) if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) return 1; + return 0; } @@ -83,6 +87,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) { sdmmc_cmd_t cmd; sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); } @@ -92,7 +97,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -107,7 +114,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -129,10 +138,12 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage) static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write) { + u32 tmp = 0; sdmmc_cmd_t cmdbuf; + sdmmc_req_t reqbuf; + sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); - sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.num_sectors = num_sectors; reqbuf.blksize = 512; @@ -142,68 +153,116 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) { - u32 tmp = 0; sdmmc_stop_transmission(storage->sdmmc, &tmp); _sdmmc_storage_get_status(storage, &tmp, 0); + return 0; } + return 1; } -int sdmmc_storage_end(sdmmc_storage_t *storage, u32 powerOff) +int sdmmc_storage_end(sdmmc_storage_t *storage) { if (!_sdmmc_storage_go_idle_state(storage)) - { - DPRINTF("_sdmmc_storage_go_idle_state in sdmmc_storage_end FAILED!\n"); return 0; - } - sdmmc_end(storage->sdmmc, powerOff); + sdmmc_end(storage->sdmmc); + return 1; } static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) { u8 *bbuf = (u8 *)buf; - + bool first_reinit = false; while (num_sectors) { u32 blkcnt = 0; - //Retry 9 times on error. - u32 retries = 10; + // Retry 5 times if failed. + u32 retries = 5; do { +reinit_try: if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) goto out; else retries--; - msleep(100); + sd_error_count_increment(SD_ERROR_RW_RETRY); + msleep(50); } while (retries); + + // Disk IO failure! Reinit SD Card to a lower speed. + if (storage->sdmmc->id == SDMMC_1) + { + int res; + + sd_error_count_increment(SD_ERROR_RW_FAIL); + + if (!first_reinit) + res = sd_initialize(true); + else + { + res = sd_init_retry(true); + if (!res) + sd_error_count_increment(SD_ERROR_INIT_FAIL); + } + + retries = 3; + first_reinit = true; + + if (res) + goto reinit_try; + } + return 0; -out:; - DPRINTF("readwrite: %08X\n", blkcnt); +out: +DPRINTF("readwrite: %08X\n", blkcnt); sector += blkcnt; num_sectors -= blkcnt; bbuf += 512 * blkcnt; } + return 1; } int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) { - return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); + // Ensure that buffer resides in DRAM and it's DMA aligned. + if (((u32)buf >= DRAM_START) && !((u32)buf % 8)) + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); + + if (num_sectors > (SDMMC_UP_BUF_SZ / 512)) + return 0; + + u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER; + if (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0)) + { + memcpy(buf, tmp_buf, 512 * num_sectors); + return 1; + } + return 0; } int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) { - return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); + // Ensure that buffer resides in DRAM and it's DMA aligned. + if (((u32)buf >= DRAM_START) && !((u32)buf % 8)) + return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); + + if (num_sectors > (SDMMC_UP_BUF_SZ / 512)) + return 0; + + u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER; + memcpy(tmp_buf, buf, 512 * num_sectors); + return _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1); } /* -* MMC specific functions. +* MMC specific functions. */ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power) @@ -214,10 +273,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u switch (power) { case SDMMC_POWER_1_8: - arg = 0x40000080; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_18; break; case SDMMC_POWER_3_3: - arg = 0x403F8000; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_27_34; break; default: return 0; @@ -239,14 +298,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; + if (cond & MMC_CARD_BUSY) { - if (cond & 0x40000000) + if (cond & SD_OCR_CCS) storage->has_sector_access = 1; + return 1; } if (get_tmr_ms() > timeout) break; + usleep(1000); } @@ -312,7 +374,6 @@ static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); } - static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) { storage->ext_csd.rev = buf[EXT_CSD_REV]; @@ -348,7 +409,7 @@ static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); _mmc_storage_parse_ext_csd(storage, buf); - + return _sdmmc_storage_check_result(tmp); } @@ -377,6 +438,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) if (_sdmmc_storage_check_status(storage)) { sdmmc_set_bus_width(storage->sdmmc, bus_width); + return 1; } @@ -387,14 +449,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) return 0; + if (check && !_sdmmc_storage_check_status(storage)) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 2)) + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52)) return 0; - DPRINTF("[MMC] switched to HS\n"); + +DPRINTF("[MMC] switched to HS\n"); storage->csd.busspeed = 52; + if (check || _sdmmc_storage_check_status(storage)) return 1; + return 0; } @@ -402,12 +469,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200))) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 3)) + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200)) return 0; - if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200)) + + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[MMC] switched to HS200\n"); + +DPRINTF("[MMC] switched to HS200\n"); storage->csd.busspeed = 200; + return _sdmmc_storage_check_status(storage); } @@ -415,40 +486,46 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) { if (!_mmc_storage_enable_HS200(storage)) return 0; - sdmmc_get_venclkctl(storage->sdmmc); + + sdmmc_set_tap_value(storage->sdmmc); + if (!_mmc_storage_enable_HS(storage, 0)) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8))) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) return 0; - if (!sdmmc_setup_clock(storage->sdmmc, 4)) + + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400)) return 0; - DPRINTF("[MMC] switched to HS400\n"); + +DPRINTF("[MMC] switched to HS400\n"); storage->csd.busspeed = 400; + return _sdmmc_storage_check_status(storage); } static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type) { - //TODO: this should be a config item. - //---v - if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8) + if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8) goto out; if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && - card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && - type == 4) + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400) return _mmc_storage_enable_HS400(storage); if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || - (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 && - (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) && (type == 4 || type == 3))) + (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 + && card_type & EXT_CSD_CARD_TYPE_HS200_1_8V + && (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200))) return _mmc_storage_enable_HS200(storage); -out:; +out: if (card_type & EXT_CSD_CARD_TYPE_HS_52) return _mmc_storage_enable_HS(storage, 1); + return 1; } @@ -456,53 +533,54 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) return 0; + return _sdmmc_storage_check_status(storage); } -int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) +int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; storage->rca = 2; //TODO: this could be a config item. - if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) + if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE)) return 0; - DPRINTF("[MMC] after init\n"); +DPRINTF("[MMC] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[MMC] went to idle state\n"); +DPRINTF("[MMC] went to idle state\n"); if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8)) return 0; - DPRINTF("[MMC] got op cond\n"); +DPRINTF("[MMC] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[MMC] got cid\n"); +DPRINTF("[MMC] got cid\n"); if (!_mmc_storage_set_relative_addr(storage)) return 0; - DPRINTF("[MMC] set relative addr\n"); +DPRINTF("[MMC] set relative addr\n"); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[MMC] got csd\n"); +DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); - if (!sdmmc_setup_clock(storage->sdmmc, 1)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26)) return 0; - DPRINTF("[MMC] after setup clock\n"); +DPRINTF("[MMC] after setup clock\n"); if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[MMC] card selected\n"); +DPRINTF("[MMC] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[MMC] set blocklen to 512\n"); +DPRINTF("[MMC] set blocklen to 512\n"); u32 *csd = (u32 *)storage->raw_csd; //Check system specification version, only version 4.0 and later support below features. @@ -514,43 +592,29 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!_mmc_storage_switch_buswidth(storage, bus_width)) return 0; - DPRINTF("[MMC] switched buswidth\n"); +DPRINTF("[MMC] switched buswidth\n"); - u8 ext_csd[512]; - memset(ext_csd, 0, sizeof(ext_csd)); - if (!_mmc_storage_get_ext_csd(storage, ext_csd)) + if (!_mmc_storage_get_ext_csd(storage, (u8 *)SDMMC_UPPER_BUFFER)) return 0; - - DPRINTF("[MMC] got ext_csd:\n"); - #ifdef SDMMC_DEBUGGING - for (u32 i=0; i<512; i++) - { - if ((i % 16) == 0) - dbg_print("\n"); - - dbg_print("%02X ", (u32)ext_csd[i]); - } - dbg_print("\n"); - #endif +DPRINTF("[MMC] got ext_csd\n"); _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd + //gfx_hexdump(0, ext_csd, 512); /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). Additionally this works only when we put the device in idle mode which we don't after enabling it. */ - if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) + if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2)) { _mmc_storage_enable_bkops(storage); - DPRINTF("[MMC] BKOPS enabled\n"); +DPRINTF("[MMC] BKOPS enabled\n"); } - else - DPRINTF("[MMC] BKOPS disabled\n"); if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; - DPRINTF("[MMC] switched to highspeed mode\n"); +DPRINTF("[MMC] succesfully switched to HS mode\n"); - sdmmc_sd_clock_ctrl(storage->sdmmc, 1); + sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE); return 1; } @@ -559,8 +623,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition))) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; + storage->partition = partition; return 1; } @@ -574,6 +640,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st u32 tmp; if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) return 0; + return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); } @@ -581,6 +648,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp { if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN)) return 0; + return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); } @@ -612,6 +680,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) return 0; + return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } @@ -629,15 +698,18 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i if (cond & SD_OCR_CCS) storage->has_sector_access = 1; + // Check if card supports 1.8V signaling. if (cond & SD_ROCR_S18A && supports_low_voltage) { //The low voltage regulator configuration is valid for SDMMC1 only. - if (storage->sdmmc->id == SDMMC_1 && + if (storage->sdmmc->id == SDMMC_1 && _sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) { if (!sdmmc_enable_low_voltage(storage->sdmmc)) return 0; storage->is_low_voltage = 1; + +DPRINTF("-> switched to low voltage\n"); } } @@ -645,7 +717,6 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i } if (get_tmr_ms() > timeout) break; - msleep(10); // Needs to be at least 10ms for some SD Cards } @@ -717,7 +788,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); - //Prepare buffer for unstuff_bits + //Prepare buffer for unstuff_bits for (int i = 0; i < 8; i+=4) { storage->raw_scr[i + 3] = buf[i]; @@ -726,7 +797,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) storage->raw_scr[i] = buf[i + 3]; } _sd_storage_parse_scr(storage); - //gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); + //gfx_hexdump(0, storage->raw_scr, 8); return _sdmmc_storage_check_result(tmp); } @@ -776,34 +847,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, return _sdmmc_storage_check_result(tmp); } -void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) +void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf) { - u32 pwr = SD_SET_CURRENT_LIMIT_800; + u32 pwr = SD_SET_CURRENT_LIMIT_200; + + if (current_limit & SD_MAX_CURRENT_800) + pwr = SD_SET_CURRENT_LIMIT_800; + else if (current_limit & SD_MAX_CURRENT_600) + pwr = SD_SET_CURRENT_LIMIT_600; + else if (current_limit & SD_MAX_CURRENT_400) + pwr = SD_SET_CURRENT_LIMIT_400; + _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - while (pwr > 0) + if (((buf[15] >> 4) & 0x0F) == pwr) { - pwr--; - _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); - if (((buf[15] >> 4) & 0x0F) == pwr) + switch (pwr) + { + case SD_SET_CURRENT_LIMIT_800: +DPRINTF("[SD] power limit raised to 800mA\n"); break; - } - - switch (pwr) - { - case SD_SET_CURRENT_LIMIT_800: - DPRINTF("[SD] Power limit raised to 800mA\n"); - break; - case SD_SET_CURRENT_LIMIT_600: - DPRINTF("[SD] Power limit raised to 600mA\n"); - break; - case SD_SET_CURRENT_LIMIT_400: - DPRINTF("[SD] Power limit raised to 800mA\n"); - break; - default: - case SD_SET_CURRENT_LIMIT_200: - DPRINTF("[SD] Power limit defaulted to 200mA\n"); - break; + case SD_SET_CURRENT_LIMIT_600: +DPRINTF("[SD] power limit raised to 600mA\n"); + break; + case SD_SET_CURRENT_LIMIT_400: +DPRINTF("[SD] power limit raised to 400mA\n"); + break; + default: + case SD_SET_CURRENT_LIMIT_200: +DPRINTF("[SD] power limit defaulted to 200mA\n"); + break; + } } } @@ -811,63 +885,91 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) return 0; +DPRINTF("[SD] supports switch to (U)HS mode\n"); u32 type_out = buf[16] & 0xF; if (type_out != hs_type) return 0; +DPRINTF("[SD] supports selected (U)HS mode\n"); - if ((((u16)buf[0] << 8) | buf[1]) < 0x320) + u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; +DPRINTF("[SD] total max current: %d\n", total_pwr_consumption); + + if (total_pwr_consumption <= 800) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type)) return 0; if (type_out != (buf[16] & 0xF)) return 0; - } - return 1; + return 1; + } +DPRINTF("[SD] card max current over limit\n"); + + return 0; } -int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) +int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) { - // Try to raise the current limit to let the card perform better. - _sd_storage_set_current_limit(storage, buf); - if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) return 0; if (!_sd_storage_switch_get(storage, buf)) return 0; - //gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64); + //gfx_hexdump(0, (u8 *)buf, 64); + + u8 access_mode = buf[13]; + u16 current_limit = buf[7] | buf[6] << 8; + + // Try to raise the current limit to let the card perform better. + _sd_storage_set_current_limit(storage, current_limit, buf); u32 hs_type = 0; switch (type) { - case 11: - if (buf[13] & SD_MODE_UHS_SDR104) + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + // Fall through if not supported. + if (access_mode & SD_MODE_UHS_SDR104) { - type = 11; hs_type = UHS_SDR104_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR104\n"); - storage->csd.busspeed = 104; +DPRINTF("[SD] bus speed set to SDR104\n"); + switch (type) + { + case SDHCI_TIMING_UHS_SDR104: + storage->csd.busspeed = 104; + break; + case SDHCI_TIMING_UHS_SDR82: + storage->csd.busspeed = 82; + break; + } break; } - //Fall through. - case 10: - if (buf[13] & SD_MODE_UHS_SDR50) + case SDHCI_TIMING_UHS_SDR50: + if (access_mode & SD_MODE_UHS_SDR50) { - type = 10; + type = SDHCI_TIMING_UHS_SDR50; hs_type = UHS_SDR50_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR50\n"); +DPRINTF("[SD] bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } - case 8: - if (!(buf[13] & SD_MODE_UHS_SDR12)) + case SDHCI_TIMING_UHS_SDR25: + if (access_mode & SD_MODE_UHS_SDR25) + { + type = SDHCI_TIMING_UHS_SDR25; + hs_type = UHS_SDR50_BUS_SPEED; +DPRINTF("[SD] bus speed set to SDR25\n"); + storage->csd.busspeed = 25; + break; + } + case SDHCI_TIMING_UHS_SDR12: + if (!(access_mode & SD_MODE_UHS_SDR12)) return 0; - type = 8; + type = SDHCI_TIMING_UHS_SDR12; hs_type = UHS_SDR12_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR12\n"); +DPRINTF("[SD] bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; default: @@ -877,26 +979,38 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) return 0; +DPRINTF("[SD] card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; - if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) +DPRINTF("[SD] setup clock\n"); + if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; +DPRINTF("[SD] config tuning\n"); return _sdmmc_storage_check_status(storage); } -int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) +int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) { if (!_sd_storage_switch_get(storage, buf)) return 0; + //gfx_hexdump(0, (u8 *)buf, 64); - if (!(buf[13] & 2)) + u8 access_mode = buf[13]; + u16 current_limit = buf[7] | buf[6] << 8; + + // Try to raise the current limit to let the card perform better. + _sd_storage_set_current_limit(storage, current_limit, buf); + + if (!(access_mode & SD_MODE_HIGH_SPEED)) return 1; - if (!_sd_storage_enable_highspeed(storage, 1, buf)) + if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf)) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; - return sdmmc_setup_clock(storage->sdmmc, 7); + + return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25); } static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) @@ -956,8 +1070,9 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; - if (!(storage->csd.cmdclass & CCC_APP_SPEC)) { - DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); + if (!(storage->csd.cmdclass & CCC_APP_SPEC)) + { +DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); return 0; } @@ -975,7 +1090,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) storage->raw_ssr[i] = buf[i + 3]; } _sd_storage_parse_ssr(storage); - //gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64); + //gfx_hexdump(0, storage->raw_ssr, 64); return _sdmmc_storage_check_result(tmp); } @@ -1019,44 +1134,74 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) } } -int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) +static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type) +{ + switch (type) + { + case SDHCI_TIMING_UHS_SDR12: + case SDHCI_TIMING_UHS_SDR25: + case SDHCI_TIMING_UHS_SDR50: + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + case SDHCI_TIMING_UHS_DDR50: + if (bus_width == SDMMC_BUS_WIDTH_4) + return true; + default: + return false; + } +} + +void sdmmc_storage_init_wait_sd() +{ + u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; + if (sd_poweroff_time < 100) + msleep(100 - sd_poweroff_time); +} + +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { int is_version_1 = 0; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + + // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; - if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) + if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE)) return 0; - DPRINTF("[SD] after init\n"); +DPRINTF("[SD] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[SD] went to idle state\n"); +DPRINTF("[SD] went to idle state\n"); is_version_1 = _sd_storage_send_if_cond(storage); if (is_version_1 == 2) return 0; - DPRINTF("[SD] after send if cond\n"); +DPRINTF("[SD] after send if cond\n"); - if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) + bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type); + + if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage)) return 0; - DPRINTF("[SD] got op cond\n"); +DPRINTF("[SD] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[SD] got cid\n"); +DPRINTF("[SD] got cid\n"); _sd_storage_parse_cid(storage); if (!_sd_storage_get_rca(storage)) return 0; - DPRINTF("[SD] got rca (= %04X)\n", storage->rca); +DPRINTF("[SD] got rca (= %04X)\n", storage->rca); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[SD] got csd\n"); +DPRINTF("[SD] got csd\n"); //Parse CSD. _sd_storage_parse_csd(storage); @@ -1069,45 +1214,35 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 storage->sec_cnt = storage->csd.c_size << 10; break; default: - DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure); +DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); break; } if (!storage->is_low_voltage) { - if (!sdmmc_setup_clock(storage->sdmmc, 6)) + if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12)) return 0; - DPRINTF("[SD] after setup clock\n"); +DPRINTF("[SD] after setup clock\n"); } if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[SD] card selected\n"); +DPRINTF("[SD] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[SD] set blocklen to 512\n"); +DPRINTF("[SD] set blocklen to 512\n"); u32 tmp = 0; if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) return 0; - DPRINTF("[SD] cleared card detect\n"); +DPRINTF("[SD] cleared card detect\n"); - u8 buf[512]; if (!_sd_storage_get_scr(storage, buf)) return 0; - DPRINTF("[SD] got scr\n"); - #ifdef SDMMC_DEBUGGING - for (u32 i=0; i<512; i++) - { - if ((i % 16) == 0) - dbg_print("\n"); - - dbg_print("%02X ", (u32)buf[i]); - } - dbg_print("\n"); - #endif + //gfx_hexdump(0, storage->raw_scr, 8); +DPRINTF("[SD] got scr\n"); // Check if card supports a wider bus and if it's not SD Version 1.X if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) @@ -1116,32 +1251,43 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); - DPRINTF("[SD] switched to wide bus width\n"); +DPRINTF("[SD] switched to wide bus width\n"); } else - DPRINTF("[SD] SD does not support wide bus width\n"); + { +DPRINTF("[SD] SD does not support wide bus width\n"); + } if (storage->is_low_voltage) { - if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf)) + if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) return 0; +DPRINTF("[SD] enabled UHS\n"); - DPRINTF("[SD] enabled highspeed (low voltage)\n"); + sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE); } - else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) + else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0) { - if (!_sd_storage_enable_highspeed_high_volt(storage, buf)) + if (!_sd_storage_enable_hs_high_volt(storage, buf)) return 0; - DPRINTF("[SD] enabled highspeed (high voltage)\n"); - storage->csd.busspeed = 25; +DPRINTF("[SD] enabled HS\n"); + switch (bus_width) + { + case SDMMC_BUS_WIDTH_4: + storage->csd.busspeed = 25; + break; + case SDMMC_BUS_WIDTH_1: + storage->csd.busspeed = 6; + break; + } } - sdmmc_sd_clock_ctrl(sdmmc, 1); - - // Parse additional card info from sd status + // Parse additional card info from sd status. if (_sd_storage_get_ssr(storage, buf)) - DPRINTF("[SD] got sd status\n"); + { +DPRINTF("[SD] got sd status\n"); + } return 1; } @@ -1182,17 +1328,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; - if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0)) + if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE)) return 0; - DPRINTF("[gc] after init\n"); +DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); - if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) + if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[gc] after tuning\n"); +DPRINTF("[gc] after tuning\n"); - sdmmc_sd_clock_ctrl(sdmmc, 1); + sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE); return 1; } diff --git a/ariane/src/hwinit/sdmmc.h b/ariane/src/bdk/storage/sdmmc.h similarity index 62% rename from ariane/src/hwinit/sdmmc.h rename to ariane/src/bdk/storage/sdmmc.h index 1ba0820..6bfad77 100644 --- a/ariane/src/hwinit/sdmmc.h +++ b/ariane/src/bdk/storage/sdmmc.h @@ -1,24 +1,37 @@ /* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef _SDMMC_H_ #define _SDMMC_H_ -#include "types.h" -#include "sdmmc_driver.h" +#include +#include + +extern u32 sd_power_cycle_time_start; + +typedef enum _sdmmc_type +{ + MMC_SD = 0, + MMC_EMMC = 1, + + EMMC_GPP = 0, + EMMC_BOOT0 = 1, + EMMC_BOOT1 = 2 +} sdmmc_type; typedef struct _mmc_cid { @@ -46,7 +59,7 @@ typedef struct _mmc_csd u32 read_blkbits; u32 write_blkbits; u32 capacity; - u8 write_protect; + u8 write_protect; u16 busspeed; } mmc_csd_t; @@ -72,7 +85,8 @@ typedef struct _sd_scr u8 cmds; } sd_scr_t; -typedef struct _sd_ssr { +typedef struct _sd_ssr +{ u8 bus_width; u8 speed_class; u8 uhs_grade; @@ -100,12 +114,13 @@ typedef struct _sdmmc_storage_t sd_ssr_t ssr; } sdmmc_storage_t; -int sdmmc_storage_end(sdmmc_storage_t *storage, u32 powerOff); +int sdmmc_storage_end(sdmmc_storage_t *storage); int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); -int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); +int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); -int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); +void sdmmc_storage_init_wait_sd(); +int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); #endif diff --git a/ariane/src/bdk/storage/sdmmc_driver.c b/ariane/src/bdk/storage/sdmmc_driver.c new file mode 100644 index 0000000..557fe8d --- /dev/null +++ b/ariane/src/bdk/storage/sdmmc_driver.c @@ -0,0 +1,1302 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +//#define ERROR_EXTRA_PRINTING +#define DPRINTF(...) + +#ifdef NYX +#define ERROR_EXTRA_PRINTING +#define SDMMC_EMMC_OC +#endif + +/*! SCMMC controller base addresses. */ +static const u32 _sdmmc_bases[4] = { + 0x700B0000, + 0x700B0200, + 0x700B0400, + 0x700B0600, +}; + +int sdmmc_get_io_power(sdmmc_t *sdmmc) +{ + u32 p = sdmmc->regs->pwrcon; + if (!(p & SDHCI_POWER_ON)) + return SDMMC_POWER_OFF; + if (p & SDHCI_POWER_180) + return SDMMC_POWER_1_8; + if (p & SDHCI_POWER_330) + return SDMMC_POWER_3_3; + return -1; +} + +static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power) +{ + switch (power) + { + case SDMMC_POWER_OFF: + sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON; + break; + case SDMMC_POWER_1_8: + sdmmc->regs->pwrcon = SDHCI_POWER_180; + break; + case SDMMC_POWER_3_3: + sdmmc->regs->pwrcon = SDHCI_POWER_330; + break; + default: + return 0; + } + + if (power != SDMMC_POWER_OFF) + sdmmc->regs->pwrcon |= SDHCI_POWER_ON; + + return 1; +} + +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) +{ + u32 h = sdmmc->regs->hostctl; + if (h & SDHCI_CTRL_8BITBUS) + return SDMMC_BUS_WIDTH_8; + if (h & SDHCI_CTRL_4BITBUS) + return SDMMC_BUS_WIDTH_4; + return SDMMC_BUS_WIDTH_1; +} + +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) +{ + u32 host_control = sdmmc->regs->hostctl & ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS); + + if (bus_width == SDMMC_BUS_WIDTH_1) + sdmmc->regs->hostctl = host_control; + else if (bus_width == SDMMC_BUS_WIDTH_4) + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_4BITBUS; + else if (bus_width == SDMMC_BUS_WIDTH_8) + sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; +} + +void sdmmc_set_tap_value(sdmmc_t *sdmmc) +{ + sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; + sdmmc->venclkctl_set = 1; +} + +static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) +{ + const u32 dqs_trim_val = 0x28; + const u32 tap_values[] = { 4, 0, 3, 0 }; + + u32 tap_val = 0; + + if (type == SDHCI_TIMING_MMC_HS400) + sdmmc->regs->vencapover = (sdmmc->regs->vencapover & 0xFFFFC0FF) | (dqs_trim_val << 8); + + sdmmc->regs->ventunctl0 &= ~TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; + + if (type == SDHCI_TIMING_MMC_HS400) + { + if (!sdmmc->venclkctl_set) + return 0; + + tap_val = sdmmc->venclkctl_tap; + } + else + { + tap_val = tap_values[sdmmc->id]; + } + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); + + return 1; +} + +static int _sdmmc_get_clkcon(sdmmc_t *sdmmc) +{ + return sdmmc->regs->clkcon; +} + +static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) +{ + _sdmmc_get_clkcon(sdmmc); + switch (sdmmc->id) + { + case SDMMC_1: // 33 Ohm 2X Driver. + if (power == SDMMC_POWER_OFF) + break; + u32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF; + if (power == SDMMC_POWER_1_8) + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. + else if (power == SDMMC_POWER_3_3) + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg | (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. + break; + case SDMMC_2: + case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; + break; + } +} + +static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) +{ + bool should_enable_sd_clock = false; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + { + should_enable_sd_clock = true; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + } + + // Enable E_INPUT power. + if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD)) + { + sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; + _sdmmc_get_clkcon(sdmmc); + usleep(1); + } + + // Enable auto calibration and start auto configuration. + sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START; + _sdmmc_get_clkcon(sdmmc); + usleep(2); + + u32 timeout = get_tmr_ms() + 10; + while (sdmmc->regs->autocalsts & TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE) + { + if (get_tmr_ms() > timeout) + { + timeout = 0; // Set timeout to 0 if we timed out. + break; + } + } +/* + // Check if PU results are inside limits. + // SDMMC1: CZ pads - 7-bit PU. SDMMC2/4: LV_CZ pads - 5-bit PU. + u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x7F; + switch (sdmmc->id) + { + case SDMMC_1: + if (!autocal_pu_status || autocal_pu_status == 0x7F) + timeout = 0; + break; + case SDMMC_2: + case SDMMC_4: + autocal_pu_status &= 0x1F; + if (!autocal_pu_status || autocal_pu_status == 0x1F) + timeout = 0; + break; + } +*/ + // In case auto calibration fails, we load suggested standard values. + if (!timeout) + { + _sdmmc_pad_config_fallback(sdmmc, power); + sdmmc->regs->autocalcfg &= ~TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE; + } + + // Disable E_INPUT to conserve power. + sdmmc->regs->sdmemcmppadctl &= ~TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; + + if(should_enable_sd_clock) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; +} + +#ifdef SDMMC_EMMC_OC +static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc, bool overclock) +#else +static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) +#endif +{ + int result = 1, should_disable_sd_clock = 0; + + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + } + +#ifdef SDMMC_EMMC_OC + if (sdmmc->id == SDMMC_4 && overclock) + sdmmc->regs->vendllcalcfg = sdmmc->regs->vendllcalcfg &= 0xFFFFC07F | (0x7C << 7); // Add -4 TX_DLY_CODE_OFFSET if HS533. +#endif + + sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE; + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_ms() + 5; + while (sdmmc->regs->vendllcalcfg & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE) + { + if (get_tmr_ms() > timeout) + { + result = 0; + goto out; + } + } + + timeout = get_tmr_ms() + 10; + while (sdmmc->regs->vendllcalcfgsts & TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE) + { + if (get_tmr_ms() > timeout) + { + result = 0; + goto out; + } + } + +out:; + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + return result; +} + +static void _sdmmc_reset(sdmmc_t *sdmmc) +{ + sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA; + _sdmmc_get_clkcon(sdmmc); + u32 timeout = get_tmr_ms() + 2000; + while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout) + ; +} + +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) +{ + // Disable the SD clock if it was enabled, and reenable it later. + bool should_enable_sd_clock = false; + if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) + { + should_enable_sd_clock = true; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + } + + _sdmmc_config_tap_val(sdmmc, type); + + _sdmmc_reset(sdmmc); + + switch (type) + { + case SDHCI_TIMING_MMC_ID: + case SDHCI_TIMING_MMC_LS26: + case SDHCI_TIMING_SD_ID: + case SDHCI_TIMING_SD_DS12: + sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; + break; + case SDHCI_TIMING_MMC_HS52: + case SDHCI_TIMING_SD_HS25: + sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD; + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; + break; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104. + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + case SDHCI_TIMING_UHS_DDR50: + case SDHCI_TIMING_MMC_DDR52: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + case SDHCI_TIMING_MMC_HS400: + // Non standard. + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + case SDHCI_TIMING_UHS_SDR25: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + case SDHCI_TIMING_UHS_SDR12: + sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; + break; + } + + _sdmmc_get_clkcon(sdmmc); + + u32 clock; + u16 divisor; + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); + clock_sdmmc_config_clock_source(&clock, sdmmc->id, clock); + sdmmc->divisor = (clock + divisor - 1) / divisor; + + //if divisor != 1 && divisor << 31 -> error + + u16 div = divisor >> 1; + divisor = 0; + if (div > 0xFF) + divisor = div >> SDHCI_DIVIDER_SHIFT; + + sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK)) + | (div << SDHCI_DIVIDER_SHIFT) | (divisor << SDHCI_DIVIDER_HI_SHIFT); + + // Enable the SD clock again. + if (should_enable_sd_clock) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + + if (type == SDHCI_TIMING_MMC_HS400) + { +#ifdef SDMMC_EMMC_OC + bool overclock_en = clock > 208000; + return _sdmmc_dll_cal_execute(sdmmc, overclock_en); +#else + return _sdmmc_dll_cal_execute(sdmmc); +#endif + } + + return 1; +} + +static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc) +{ + // Recalibrate conditionally. + if ((sdmmc->id == SDMMC_1) && !sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + if (!sdmmc->auto_cal_enabled) + { + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + } + sdmmc->card_clock_enabled = 1; +} + +static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) +{ + sdmmc->card_clock_enabled = 0; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; +} + +void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable) +{ + // Recalibrate periodically for SDMMC1. + if ((sdmmc->id == SDMMC_1) && !auto_cal_enable && sdmmc->card_clock_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + sdmmc->auto_cal_enabled = auto_cal_enable; + if (auto_cal_enable) + { + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + return; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + return; + } + + if (sdmmc->card_clock_enabled) + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; +} + +static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) +{ + switch (type) + { + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_3: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (size < 4) + return 0; + rsp[0] = sdmmc->regs->rspreg0; + break; + case SDMMC_RSP_TYPE_2: + if (size < 0x10) + return 0; + // CRC is stripped, so shifting is needed. + u32 tempreg; + for (int i = 0; i < 4; i++) + { + switch(i) + { + case 0: + tempreg = sdmmc->regs->rspreg3; + break; + case 1: + tempreg = sdmmc->regs->rspreg2; + break; + case 2: + tempreg = sdmmc->regs->rspreg1; + break; + case 3: + tempreg = sdmmc->regs->rspreg0; + break; + } + rsp[i] = tempreg << 8; + + if (i != 0) + rsp[i - 1] |= (tempreg >> 24) & 0xFF; + } + break; + default: + return 0; + break; + } + + return 1; +} + +int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) +{ + if (!rsp || sdmmc->expected_rsp_type != type) + return 0; + + switch (type) + { + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_3: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (size < 4) + return 0; + rsp[0] = sdmmc->rsp[0]; + break; + case SDMMC_RSP_TYPE_2: + if (size < 0x10) + return 0; + rsp[0] = sdmmc->rsp[0]; + rsp[1] = sdmmc->rsp[1]; + rsp[2] = sdmmc->rsp[2]; + rsp[3] = sdmmc->rsp[3]; + break; + default: + return 0; + break; + } + + return 1; +} + +static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + + if (wait_dat) + { + timeout = get_tmr_ms() + 2000; + while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK)) + if (get_tmr_ms() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + + return 1; +} + +static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) +{ + switch (sdmmc_get_bus_width(sdmmc)) + { + case SDMMC_BUS_WIDTH_1: + return 0; + break; + case SDMMC_BUS_WIDTH_4: + sdmmc->regs->blksize = 64; + break; + case SDMMC_BUS_WIDTH_8: + sdmmc->regs->blksize = 128; + break; + } + sdmmc->regs->blkcnt = 1; + sdmmc->regs->trnmod = SDHCI_TRNS_READ; + return 1; +} + +static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) +{ + u16 cmdflags = 0; + + switch (cmd->rsp_type) + { + case SDMMC_RSP_TYPE_0: + break; + case SDMMC_RSP_TYPE_1: + case SDMMC_RSP_TYPE_4: + case SDMMC_RSP_TYPE_5: + if (cmd->check_busy) + cmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; + else + cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; + break; + case SDMMC_RSP_TYPE_2: + cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC; + break; + case SDMMC_RSP_TYPE_3: + cmdflags = SDHCI_CMD_RESP_LEN48; + break; + default: + return 0; + break; + } + + if (is_data_present) + cmdflags |= SDHCI_CMD_DATA; + sdmmc->regs->argument = cmd->arg; + sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags; + + return 1; +} + +static void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd) +{ + sdmmc_cmd_t cmdbuf; + cmdbuf.cmd = cmd; + cmdbuf.arg = 0; + cmdbuf.rsp_type = SDMMC_RSP_TYPE_1; + cmdbuf.check_busy = 0; + _sdmmc_send_cmd(sdmmc, &cmdbuf, true); +} + +static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) +{ + if (sdmmc->auto_cal_enabled) + return 0; + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true)) + return 0; + + _sdmmc_setup_read_small_block(sdmmc); + + sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + + _sdmmc_send_tuning_cmd(sdmmc, cmd); + _sdmmc_get_clkcon(sdmmc); + usleep(1); + + _sdmmc_reset(sdmmc); + + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_us() + 5000; + while (get_tmr_us() < timeout) + { + if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL) + { + sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL; + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; + _sdmmc_get_clkcon(sdmmc); + usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + return 1; + } + } + + _sdmmc_reset(sdmmc); + + sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; + _sdmmc_get_clkcon(sdmmc); + usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + + return 0; +} + +int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd) +{ + u32 max = 0, flag = 0; + + switch (type) + { + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + case SDHCI_TIMING_UHS_SDR82: + max = 128; + flag = (2 << 13); // 128 iterations. + break; + case SDHCI_TIMING_UHS_SDR50: + case SDHCI_TIMING_UHS_DDR50: + case SDHCI_TIMING_MMC_DDR52: + max = 256; + flag = (4 << 13); // 256 iterations. + break; + case SDHCI_TIMING_UHS_SDR12: + case SDHCI_TIMING_UHS_SDR25: + return 1; + default: + return 0; + } + + sdmmc->regs->ventunctl1 = 0; // step_size 1. + + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier. + sdmmc->regs->ventunctl0 |= TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; + sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; + + for (u32 i = 0; i < max; i++) + { + _sdmmc_tuning_execute_once(sdmmc, cmd); + if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) + break; + } + + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) + return 1; + + return 0; +} + +static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) +{ + //Enable internal clock and wait till it is stable. + sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN; + _sdmmc_get_clkcon(sdmmc); + u32 timeout = get_tmr_ms() + 2000; + while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE)) + { + if (get_tmr_ms() > timeout) + return 0; + } + + sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; + sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE; + sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; + + if (!(sdmmc->regs->capareg & SDHCI_CAN_64BIT)) + return 0; + + sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; + sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK; + sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE; + + return 1; +} + +static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) +{ + u32 off_pd = 0; + u32 off_pu = 0; + + switch (sdmmc->id) + { + case SDMMC_2: + case SDMMC_4: + if (power != SDMMC_POWER_1_8) + return 0; + off_pd = 5; + off_pu = 5; + break; + case SDMMC_1: + case SDMMC_3: + if (power == SDMMC_POWER_1_8) + { + off_pd = 123; + off_pu = 123; + } + else if (power == SDMMC_POWER_3_3) + { + off_pd = 125; + off_pu = 0; + } + else + return 0; + break; + } + + sdmmc->regs->autocalcfg = (sdmmc->regs->autocalcfg & 0xFFFF8080) | (off_pd << 8) | off_pu; + return 1; +} + +static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; + sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; + sdmmc->regs->norintsts = sdmmc->regs->norintsts; + sdmmc->regs->errintsts = sdmmc->regs->errintsts; +} + +static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) +{ + sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; + sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); +} + +static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) +{ + u16 norintsts = sdmmc->regs->norintsts; + u16 errintsts = sdmmc->regs->errintsts; + +DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); + + if (pout) + *pout = norintsts; + + // Check for error interrupt. + if (norintsts & SDHCI_INT_ERROR) + { + sdmmc->regs->errintsts = errintsts; + return SDMMC_MASKINT_ERROR; + } + else if (norintsts & mask) + { + sdmmc->regs->norintsts = norintsts & mask; + return SDMMC_MASKINT_MASKED; + } + + return SDMMC_MASKINT_NOERROR; +} + +static int _sdmmc_wait_response(sdmmc_t *sdmmc) +{ + _sdmmc_get_clkcon(sdmmc); + + u32 timeout = get_tmr_ms() + 2000; + while (true) + { + int result = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE); + if (result == SDMMC_MASKINT_MASKED) + break; + if (result != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) + { + _sdmmc_reset(sdmmc); + return 0; + } + } + + return 1; +} + +static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) +{ + sdmmc_cmd_t cmd; + + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, false)) + return 0; + + _sdmmc_enable_interrupts(sdmmc); + + cmd.cmd = MMC_STOP_TRANSMISSION; + cmd.arg = 0; + cmd.rsp_type = SDMMC_RSP_TYPE_1; + cmd.check_busy = 1; + + _sdmmc_send_cmd(sdmmc, &cmd, false); + + int result = _sdmmc_wait_response(sdmmc); + _sdmmc_mask_interrupts(sdmmc); + + if (!result) + return 0; + + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); + + return _sdmmc_wait_card_busy(sdmmc); +} + +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) +{ + if (!sdmmc->card_clock_enabled) + return 0; + + // Recalibrate periodically for SDMMC1. + if ((sdmmc->id == SDMMC_1) && sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + bool should_disable_sd_clock = false; + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = true; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_get_clkcon(sdmmc); + usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + } + + int result = _sdmmc_stop_transmission_inner(sdmmc, rsp); + usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + + return result; +} + +static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) +{ + if (!req->blksize || !req->num_sectors) + return 0; + + u32 blkcnt = req->num_sectors; + if (blkcnt >= 0xFFFF) + blkcnt = 0xFFFF; + u32 admaaddr = (u32)req->buf; + + // Check alignment. + if (admaaddr & 7) + return 0; + + sdmmc->regs->admaaddr = admaaddr; + sdmmc->regs->admaaddr_hi = 0; + + sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000; + + sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out). + sdmmc->regs->blkcnt = blkcnt; + + if (blkcnt_out) + *blkcnt_out = blkcnt; + + u32 trnmode = SDHCI_TRNS_DMA; + if (req->is_multi_block) + trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA; + if (!req->is_write) + trnmode |= SDHCI_TRNS_READ; + if (req->is_auto_cmd12) + trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12; + + sdmmc->regs->trnmod = trnmode; + + return 1; +} + +static int _sdmmc_update_dma(sdmmc_t *sdmmc) +{ + u16 blkcnt = 0; + do + { + blkcnt = sdmmc->regs->blkcnt; + u32 timeout = get_tmr_ms() + 1500; + do + { + int result = 0; + while (true) + { + u16 intr = 0; + result = _sdmmc_check_mask_interrupt(sdmmc, &intr, + SDHCI_INT_DATA_END | SDHCI_INT_DMA_END); + if (result < 0) + break; + + if (intr & SDHCI_INT_DATA_END) + return 1; // Transfer complete. + + if (intr & SDHCI_INT_DMA_END) + { + // Update DMA. + sdmmc->regs->admaaddr = sdmmc->dma_addr_next; + sdmmc->regs->admaaddr_hi = 0; + sdmmc->dma_addr_next += 0x80000; + } + } + if (result != SDMMC_MASKINT_NOERROR) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("%08X!", result); +#endif + _sdmmc_reset(sdmmc); + return 0; + } + } while (get_tmr_ms() < timeout); + } while (sdmmc->regs->blkcnt != blkcnt); + + _sdmmc_reset(sdmmc); + return 0; +} + +static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + int has_req_or_check_busy = req || cmd->check_busy; + if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy)) + return 0; + + u32 blkcnt = 0; + bool is_data_present = false; + if (req) + { + if (!_sdmmc_config_dma(sdmmc, &blkcnt, req)) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: DMA Wrong cfg!"); +#endif + return 0; + } + + // Flush cache before starting the transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + is_data_present = true; + } + else + is_data_present = false; + + _sdmmc_enable_interrupts(sdmmc); + + if (!_sdmmc_send_cmd(sdmmc, cmd, is_data_present)) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC: Wrong Response type %08X!", cmd->rsp_type); +#endif + return 0; + } + + int result = _sdmmc_wait_response(sdmmc); + if (!result) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: Transfer timeout!"); +#endif + } + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, + sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); + if (result) + { + if (cmd->rsp_type) + { + sdmmc->expected_rsp_type = cmd->rsp_type; + result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); + if (!result) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC: Unknown response %08X!", sdmmc->rsp[0]); +#endif + } + } + if (req && result) + { + result = _sdmmc_update_dma(sdmmc); + if (!result) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: DMA Update failed!"); +#endif + } + } + } + + _sdmmc_mask_interrupts(sdmmc); + + if (result) + { + if (req) + { + // Flush cache after transfer. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + if (blkcnt_out) + *blkcnt_out = blkcnt; + + if (req->is_auto_cmd12) + sdmmc->rsp3 = sdmmc->regs->rspreg3; + } + + if (cmd->check_busy || req) + { + result = _sdmmc_wait_card_busy(sdmmc); + if (!result) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTF("SDMMC: Busy timeout!"); +#endif + } + return result; + } + } + + return result; +} + +bool sdmmc_get_sd_inserted() +{ + return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)); +} + +static int _sdmmc_config_sdmmc1() +{ + // Configure SD card detect. + PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up. + APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; + gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); + usleep(100); + + // Check if SD card is inserted. + if(!sdmmc_get_sd_inserted()) + return 0; + + /* + * Pinmux config: + * DRV_TYPE = DRIVE_2X + * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) + * E_INPUT = ENABLE + * TRISTATE = PASSTHROUGH + * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK + */ + + // Configure SDMMC1 pinmux. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; + + // Make sure the SDMMC1 controller is powered. + PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN; + usleep(1000); + PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN); + + // Inform IO pads that voltage is gonna be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + + // Set enable SD card power. + PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Pull down. + gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); + gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); + usleep(1000); + + // Enable SD card power. + max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); + max77620_regulator_enable(REGULATOR_LDO2, 1); + usleep(1000); + + // Set pad slew codes to get good quality clock. + APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; + usleep(1000); + + return 1; +} + +static void _sdmmc_config_emmc(u32 id) +{ + switch (id) + { + case SDMMC_2: + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; + break; + case SDMMC_4: + // Unset park for pads. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF; + // Set default pad cfg. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; + + // Enabled schmitt trigger. + APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; // Enable Schmitt trigger. + break; + } +} + +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable) +{ + const u32 trim_values[] = { 2, 8, 3, 8 }; + + if (id > SDMMC_4) + return 0; + + memset(sdmmc, 0, sizeof(sdmmc_t)); + + sdmmc->regs = (t210_sdmmc_t *)_sdmmc_bases[id]; + sdmmc->id = id; + sdmmc->clock_stopped = 1; + + // Do specific SDMMC HW configuration. + switch (id) + { + case SDMMC_1: + if (!_sdmmc_config_sdmmc1()) + return 0; + break; + case SDMMC_2: + case SDMMC_4: + _sdmmc_config_emmc(id); + break; + } + + if (clock_sdmmc_is_not_reset_and_enabled(id)) + { + _sdmmc_sd_clock_disable(sdmmc); + _sdmmc_get_clkcon(sdmmc); + } + + u32 clock; + u16 divisor; + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); + clock_sdmmc_enable(id, clock); + + sdmmc->clock_stopped = 0; + + //TODO: make this skip-able. + sdmmc->regs->iospare |= 0x80000; // Enable muxing. + sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; // Set Band Gap VREG to supply DLL. + sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | (trim_values[sdmmc->id] << 24); + sdmmc->regs->sdmemcmppadctl = + (sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7; + + if (!_sdmmc_autocal_config_offset(sdmmc, power)) + return 0; + + _sdmmc_autocal_execute(sdmmc, power); + + if (_sdmmc_enable_internal_clock(sdmmc)) + { + sdmmc_set_bus_width(sdmmc, bus_width); + _sdmmc_set_io_power(sdmmc, power); + + if (sdmmc_setup_clock(sdmmc, type)) + { + sdmmc_card_clock_ctrl(sdmmc, auto_cal_enable); + _sdmmc_card_clock_enable(sdmmc); + _sdmmc_get_clkcon(sdmmc); + + return 1; + } + + return 0; + } + return 0; +} + +void sdmmc_end(sdmmc_t *sdmmc) +{ + if (!sdmmc->clock_stopped) + { + _sdmmc_sd_clock_disable(sdmmc); + // Disable SDMMC power. + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF); + + // Disable SD card power. + if (sdmmc->id == SDMMC_1) + { + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); + max77620_regulator_enable(REGULATOR_LDO2, 0); + + // Inform IO pads that next voltage might be 3.3V. + PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN; + + sd_power_cycle_time_start = get_tmr_ms(); // Some SanDisk U1 cards need 100ms for a power cycle. + usleep(1000); // To power cycle, min 1ms without power is needed. + } + + _sdmmc_get_clkcon(sdmmc); + clock_sdmmc_disable(sdmmc->id); + sdmmc->clock_stopped = 1; + } +} + +void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy) +{ + cmdbuf->cmd = cmd; + cmdbuf->arg = arg; + cmdbuf->rsp_type = rsp_type; + cmdbuf->check_busy = check_busy; +} + +int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) +{ + if (!sdmmc->card_clock_enabled) + return 0; + + // Recalibrate periodically for SDMMC1. + if (sdmmc->id == SDMMC_1 && sdmmc->auto_cal_enabled) + _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); + + int should_disable_sd_clock = 0; + if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) + { + should_disable_sd_clock = 1; + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_get_clkcon(sdmmc); + usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + } + + int result = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); + usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + + if (should_disable_sd_clock) + sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; + + return result; +} + +int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) +{ + if(sdmmc->id != SDMMC_1) + return 0; + + if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12)) + return 0; + + _sdmmc_get_clkcon(sdmmc); + + // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); + usleep(300); + + // Inform IO pads that we switched to 1.8V. + PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN); + + // Enable schmitt trigger for better duty cycle and low jitter clock. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; + + _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); + _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); + _sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8); + _sdmmc_get_clkcon(sdmmc); + msleep(5); // Wait minimum 5ms before turning on the card clock. + + // Turn on SDCLK. + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) + { + sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; + _sdmmc_get_clkcon(sdmmc); + usleep(1000); + if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) + return 1; + } + + return 0; +} diff --git a/ariane/src/bdk/storage/sdmmc_driver.h b/ariane/src/bdk/storage/sdmmc_driver.h new file mode 100644 index 0000000..2937d93 --- /dev/null +++ b/ariane/src/bdk/storage/sdmmc_driver.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SDMMC_DRIVER_H_ +#define _SDMMC_DRIVER_H_ + +#include +#include + +/*! SDMMC controller IDs. */ +#define SDMMC_1 0 +#define SDMMC_2 1 +#define SDMMC_3 2 +#define SDMMC_4 3 + +/*! SDMMC power types. */ +#define SDMMC_POWER_OFF 0 +#define SDMMC_POWER_1_8 1 +#define SDMMC_POWER_3_3 2 + +/*! SDMMC bus widths. */ +#define SDMMC_BUS_WIDTH_1 0 +#define SDMMC_BUS_WIDTH_4 1 +#define SDMMC_BUS_WIDTH_8 2 + +/*! SDMMC response types. */ +#define SDMMC_RSP_TYPE_0 0 +#define SDMMC_RSP_TYPE_1 1 +#define SDMMC_RSP_TYPE_2 2 +#define SDMMC_RSP_TYPE_3 3 +#define SDMMC_RSP_TYPE_4 4 +#define SDMMC_RSP_TYPE_5 5 + +/*! SDMMC mask interrupt status. */ +#define SDMMC_MASKINT_MASKED 0 +#define SDMMC_MASKINT_NOERROR -1 +#define SDMMC_MASKINT_ERROR -2 + +/*! SDMMC present state. */ +#define SDHCI_CMD_INHIBIT 0x1 +#define SDHCI_DATA_INHIBIT 0x2 +#define SDHCI_DOING_WRITE 0x100 +#define SDHCI_DOING_READ 0x200 +#define SDHCI_SPACE_AVAILABLE 0x400 +#define SDHCI_DATA_AVAILABLE 0x800 +#define SDHCI_CARD_PRESENT 0x10000 +#define SDHCI_CD_STABLE 0x20000 +#define SDHCI_CD_LVL 0x40000 +#define SDHCI_WRITE_PROTECT 0x80000 +#define SDHCI_DATA_LVL_MASK 0xF00000 +#define SDHCI_DATA_0_LVL_MASK 0x100000 +#define SDHCI_CMD_LVL 0x1000000 + +/*! SDMMC transfer mode. */ +#define SDHCI_TRNS_DMA 0x01 +#define SDHCI_TRNS_BLK_CNT_EN 0x02 +#define SDHCI_TRNS_AUTO_CMD12 0x04 +#define SDHCI_TRNS_AUTO_CMD23 0x08 +#define SDHCI_TRNS_AUTO_SEL 0x0C +#define SDHCI_TRNS_WRITE 0x00 +#define SDHCI_TRNS_READ 0x10 +#define SDHCI_TRNS_MULTI 0x20 + +/*! SDMMC command. */ +#define SDHCI_CMD_RESP_MASK 0x3 +#define SDHCI_CMD_RESP_NO_RESP 0x0 +#define SDHCI_CMD_RESP_LEN136 0x1 +#define SDHCI_CMD_RESP_LEN48 0x2 +#define SDHCI_CMD_RESP_LEN48_BUSY 0x3 +#define SDHCI_CMD_CRC 0x08 +#define SDHCI_CMD_INDEX 0x10 +#define SDHCI_CMD_DATA 0x20 +#define SDHCI_CMD_ABORTCMD 0xC0 + +/*! SDMMC host control. */ +#define SDHCI_CTRL_LED 0x01 +#define SDHCI_CTRL_4BITBUS 0x02 +#define SDHCI_CTRL_HISPD 0x04 +#define SDHCI_CTRL_DMA_MASK 0x18 +#define SDHCI_CTRL_SDMA 0x00 +#define SDHCI_CTRL_ADMA1 0x08 +#define SDHCI_CTRL_ADMA32 0x10 +#define SDHCI_CTRL_ADMA64 0x18 +#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_CDTEST_INS 0x40 +#define SDHCI_CTRL_CDTEST_EN 0x80 + +/*! SDMMC host control 2. */ +#define SDHCI_CTRL_UHS_MASK 0xFFF8 +#define SDHCI_CTRL_VDD_180 8 +#define SDHCI_CTRL_DRV_TYPE_B 0x00 +#define SDHCI_CTRL_DRV_TYPE_A 0x10 +#define SDHCI_CTRL_DRV_TYPE_C 0x20 +#define SDHCI_CTRL_DRV_TYPE_D 0x30 +#define SDHCI_CTRL_EXEC_TUNING 0x40 +#define SDHCI_CTRL_TUNED_CLK 0x80 +#define SDHCI_HOST_VERSION_4_EN 0x1000 +#define SDHCI_ADDRESSING_64BIT_EN 0x2000 +#define SDHCI_CTRL_PRESET_VAL_EN 0x8000 + +/*! SDMMC power control. */ +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E +#define SDHCI_POWER_MASK 0xF1 + +// /*! SDMMC max current. */ +// #define SDHCI_MAX_CURRENT_330_MASK 0xFF +// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000 +// #define SDHCI_MAX_CURRENT_MULTIPLIER 4 + +/*! SDMMC clock control. */ +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_DIV_MASK 0xFF00 +#define SDHCI_DIV_HI_MASK 0xC0 +#define SDHCI_PROG_CLOCK_MODE 0x20 +#define SDHCI_CLOCK_CARD_EN 0x4 +#define SDHCI_CLOCK_INT_STABLE 0x2 +#define SDHCI_CLOCK_INT_EN 0x1 + +/*! SDMMC software reset. */ +#define SDHCI_RESET_ALL 0x01 +#define SDHCI_RESET_CMD 0x02 +#define SDHCI_RESET_DATA 0x04 + +/*! SDMMC interrupt status and control. */ +#define SDHCI_INT_RESPONSE 0x1 +#define SDHCI_INT_DATA_END 0x2 +#define SDHCI_INT_BLK_GAP 0x4 +#define SDHCI_INT_DMA_END 0x8 +#define SDHCI_INT_SPACE_AVAIL 0x10 +#define SDHCI_INT_DATA_AVAIL 0x20 +#define SDHCI_INT_CARD_INSERT 0x40 +#define SDHCI_INT_CARD_REMOVE 0x80 +#define SDHCI_INT_CARD_INT 0x100 +#define SDHCI_INT_RETUNE 0x1000 +#define SDHCI_INT_CQE 0x4000 +#define SDHCI_INT_ERROR 0x8000 + +/*! SDMMC error interrupt status and control. */ +#define SDHCI_ERR_INT_TIMEOUT 0x1 +#define SDHCI_ERR_INT_CRC 0x2 +#define SDHCI_ERR_INT_END_BIT 0x4 +#define SDHCI_ERR_INT_INDEX 0x8 +#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10 +#define SDHCI_ERR_INT_DATA_CRC 0x20 +#define SDHCI_ERR_INT_DATA_END_BIT 0x40 +#define SDHCI_ERR_INT_BUS_POWER 0x80 +#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100 +#define SDHCI_ERR_INT_ADMA_ERROR 0x200 + +#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \ + (SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \ + SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \ + SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \ + SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT) + +/*! SD bus speeds. */ +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 +#define HS400_BUS_SPEED 5 + +/*! SDMMC timmings. */ +#define SDHCI_TIMING_MMC_ID 0 +#define SDHCI_TIMING_MMC_LS26 1 +#define SDHCI_TIMING_MMC_HS52 2 +#define SDHCI_TIMING_MMC_HS200 3 +#define SDHCI_TIMING_MMC_HS400 4 +#define SDHCI_TIMING_SD_ID 5 +#define SDHCI_TIMING_SD_DS12 6 +#define SDHCI_TIMING_SD_HS25 7 +#define SDHCI_TIMING_UHS_SDR12 8 +#define SDHCI_TIMING_UHS_SDR25 9 +#define SDHCI_TIMING_UHS_SDR50 10 +#define SDHCI_TIMING_UHS_SDR104 11 +#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock. +#define SDHCI_TIMING_UHS_DDR50 13 +#define SDHCI_TIMING_MMC_DDR52 14 + +#define SDHCI_CAN_64BIT 0x10000000 + +/*! SDMMC Low power features. */ +#define SDMMC_AUTO_CAL_DISABLE 0 +#define SDMMC_AUTO_CAL_ENABLE 1 + +/*! Helper for SWITCH command argument. */ +#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) + +/*! SDMMC controller context. */ +typedef struct _sdmmc_t +{ + t210_sdmmc_t *regs; + u32 id; + u32 divisor; + u32 clock_stopped; + int auto_cal_enabled; + int card_clock_enabled; + int venclkctl_set; + u32 venclkctl_tap; + u32 expected_rsp_type; + u32 dma_addr_next; + u32 rsp[4]; + u32 rsp3; +} sdmmc_t; + +/*! SDMMC command. */ +typedef struct _sdmmc_cmd_t +{ + u16 cmd; + u32 arg; + u32 rsp_type; + u32 check_busy; +} sdmmc_cmd_t; + +/*! SDMMC request. */ +typedef struct _sdmmc_req_t +{ + void *buf; + u32 blksize; + u32 num_sectors; + int is_write; + int is_multi_block; + int is_auto_cmd12; +} sdmmc_req_t; + +int sdmmc_get_io_power(sdmmc_t *sdmmc); +u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); +void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); +void sdmmc_set_tap_value(sdmmc_t *sdmmc); +int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); +void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable); +int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); +int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd); +int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); +bool sdmmc_get_sd_inserted(); +int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable); +void sdmmc_end(sdmmc_t *sdmmc); +void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy); +int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out); +int sdmmc_enable_low_voltage(sdmmc_t *sdmmc); + +#endif diff --git a/ariane/src/bdk/storage/sdmmc_t210.h b/ariane/src/bdk/storage/sdmmc_t210.h new file mode 100644 index 0000000..c5ecf11 --- /dev/null +++ b/ariane/src/bdk/storage/sdmmc_t210.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SDMMC_T210_H_ +#define _SDMMC_T210_H_ + +#include + +#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000 +#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000 +#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000 +#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000 +#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0 +#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000 +#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000 +#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000 + +typedef struct _t210_sdmmc_t +{ + vu32 sysad; + vu16 blksize; + vu16 blkcnt; + vu32 argument; + vu16 trnmod; + vu16 cmdreg; + vu32 rspreg0; + vu32 rspreg1; + vu32 rspreg2; + vu32 rspreg3; + vu32 bdata; + vu32 prnsts; + vu8 hostctl; + vu8 pwrcon; + vu8 blkgap; + vu8 wakcon; + vu16 clkcon; + vu8 timeoutcon; + vu8 swrst; + vu16 norintsts; + vu16 errintsts; + vu16 norintstsen; // Enable irq status. + vu16 errintstsen; // Enable irq status. + vu16 norintsigen; // Enable irq signal to LIC/GIC. + vu16 errintsigen; // Enable irq signal to LIC/GIC. + vu16 acmd12errsts; + vu16 hostctl2; + vu32 capareg; + vu32 capareg_1; + vu32 maxcurr; + vu8 rsvd0[4]; // 4C-4F reserved for more max current. + vu16 setacmd12err; + vu16 setinterr; + vu8 admaerr; + vu8 rsvd1[3]; // 55-57 reserved. + vu32 admaaddr; + vu32 admaaddr_hi; + vu8 rsvd2[156]; // 60-FB reserved. + vu16 slotintsts; + vu16 hcver; + vu32 venclkctl; + vu32 vensysswctl; + vu32 venerrintsts; + vu32 vencapover; + vu32 venbootctl; + vu32 venbootacktout; + vu32 venbootdattout; + vu32 vendebouncecnt; + vu32 venmiscctl; + vu32 maxcurrover; + vu32 maxcurrover_hi; + vu32 unk0[32]; // 0x12C + vu32 veniotrimctl; + vu32 vendllcalcfg; + vu32 vendllctl0; + vu32 vendllctl1; + vu32 vendllcalcfgsts; + vu32 ventunctl0; + vu32 ventunctl1; + vu32 ventunsts0; + vu32 ventunsts1; + vu32 venclkgatehystcnt; + vu32 venpresetval0; + vu32 venpresetval1; + vu32 venpresetval2; + vu32 sdmemcmppadctl; + vu32 autocalcfg; + vu32 autocalintval; + vu32 autocalsts; + vu32 iospare; + vu32 mcciffifoctl; + vu32 timeoutwcoal; +} t210_sdmmc_t; + +#endif diff --git a/ariane/src/bdk/thermal/fan.c b/ariane/src/bdk/thermal/fan.c new file mode 100644 index 0000000..686f9e8 --- /dev/null +++ b/ariane/src/bdk/thermal/fan.c @@ -0,0 +1,106 @@ +/* + * Fan driver for Nintendo Switch + * + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +void set_fan_duty(u32 duty) +{ + static bool fan_init = false; + static u16 curr_duty = -1; + + if (curr_duty == duty) + return; + + if (!fan_init) + { + // Fan tachometer. + PINMUX_AUX(PINMUX_AUX_CAM1_PWDN) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; + gpio_config(GPIO_PORT_S, GPIO_PIN_7, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_S, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); + + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Max PWM to disable fan. + + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + gpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode. + + fan_init = true; + } + + if (duty > 236) + duty = 236; + + // Inverted polarity. + u32 inv_duty = 236 - duty; + + // If disabled send a 0 duty. + if (inv_duty == 236) + { + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (1 << 24); // Bit 24 is absolute 0%. + regulator_disable_5v(REGULATOR_5V_FAN); + + // Disable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = + PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_DOWN; // Set source to PWM1. + } + else // Set PWM duty. + { + // Fan power supply. + regulator_enable_5v(REGULATOR_5V_FAN); + PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16); + + // Enable fan. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1. + } + + curr_duty = duty; +} + +void get_fan_speed(u32 *duty, u32 *rpm) +{ + if (rpm) + { + u32 irq_count = 1; + bool should_read = true; + bool irq_val = 0; + + // Poll irqs for 2 seconds. + int timer = get_tmr_us() + 1000000; + while (timer - get_tmr_us()) + { + irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7); + if (irq_val && should_read) + { + irq_count++; + should_read = false; + } + else if (!irq_val) + should_read = true; + } + + // Calculate rpm based on triggered interrupts. + *rpm = 60000000 / ((1000000 * 2) / irq_count); + } + + if (duty) + *duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF); +} diff --git a/ariane/src/bdk/thermal/fan.h b/ariane/src/bdk/thermal/fan.h new file mode 100644 index 0000000..e827975 --- /dev/null +++ b/ariane/src/bdk/thermal/fan.h @@ -0,0 +1,29 @@ +/* + * Fan driver for Nintendo Switch + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __FAN_H_ +#define __FAN_H_ + +#include + +// Disable: 0 (0 RPM), min duty: 1 (960 RPM), max duty 235 (11000 RPM). +void set_fan_duty(u32 duty); +// Passing NULL ptr on either of the two, disables parsing of it. +void get_fan_speed(u32 *duty, u32 *rpm); + +#endif /* __FAN_H_ */ diff --git a/ariane/src/bdk/thermal/tmp451.c b/ariane/src/bdk/thermal/tmp451.c new file mode 100644 index 0000000..fb9f9fa --- /dev/null +++ b/ariane/src/bdk/thermal/tmp451.c @@ -0,0 +1,65 @@ +/* + * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +u16 tmp451_get_soc_temp(bool intenger) +{ + u8 val; + u16 temp = 0; + + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TEMP_REG); + if (intenger) + return val; + + temp = val << 8; + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_DEC_REG); + temp |= ((val >> 4) * 625) / 100; + + return temp; +} + +u16 tmp451_get_pcb_temp(bool intenger) +{ + u8 val; + u16 temp = 0; + + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TEMP_REG); + if (intenger) + return val; + + temp = val << 8; + val = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TMP_DEC_REG); + temp |= ((val >> 4) * 625) / 100; + + return temp; +} + +void tmp451_init() +{ + // Disable ALARM and Range to 0 - 127 oC. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0x80); + + // Set conversion rate to 32/s and make a read to update the reg. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 9); + tmp451_get_soc_temp(false); + + // Set rate to every 4 seconds. + i2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 2); +} diff --git a/ariane/src/bdk/thermal/tmp451.h b/ariane/src/bdk/thermal/tmp451.h new file mode 100644 index 0000000..9549ffa --- /dev/null +++ b/ariane/src/bdk/thermal/tmp451.h @@ -0,0 +1,42 @@ +/* + * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451 + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TMP451_H_ +#define __TMP451_H_ + +#include + +#define TMP451_I2C_ADDR 0x4C + +#define TMP451_PCB_TEMP_REG 0x00 +#define TMP451_SOC_TEMP_REG 0x01 + +#define TMP451_CONFIG_REG 0x09 +#define TMP451_CNV_RATE_REG 0x0A + +#define TMP451_SOC_TMP_DEC_REG 0x10 +#define TMP451_PCB_TMP_DEC_REG 0x15 + +// If input is false, the return value is packed. MSByte is the integer in oC +// and the LSByte is the decimal point truncated to 2 decimal places. +// Otherwise it's an integer oC. +u16 tmp451_get_soc_temp(bool integer); +u16 tmp451_get_pcb_temp(bool integer); +void tmp451_init(); + +#endif /* __TMP451_H_ */ diff --git a/ariane/src/bdk/usb/usb_descriptors.h b/ariane/src/bdk/usb/usb_descriptors.h new file mode 100644 index 0000000..74556f8 --- /dev/null +++ b/ariane/src/bdk/usb/usb_descriptors.h @@ -0,0 +1,752 @@ +/* + * USB driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _USB_DESCRIPTORS_H_ +#define _USB_DESCRIPTORS_H_ + +#include + +typedef enum { + USB_DESCRIPTOR_DEVICE = 1, + USB_DESCRIPTOR_CONFIGURATION = 2, + USB_DESCRIPTOR_STRING = 3, + USB_DESCRIPTOR_INTERFACE = 4, + USB_DESCRIPTOR_ENDPOINT = 5, + USB_DESCRIPTOR_DEVICE_QUALIFIER = 6, + USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + USB_DESCRIPTOR_INTERFACE_POWER = 8, + USB_DESCRIPTOR_INTERFACE_OTG = 9, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT = 15, + USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP = 16, + USB_DESCRIPTOR_HID = 33, + USB_DESCRIPTOR_HID_REPORT = 34 +} usb_desc_type_t; + +typedef enum { + USB_DESCRIPTOR_MS_COMPAT_ID = 4, + USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5 +} usb_vendor_desc_type_t; + +typedef enum { + USB_ATTR_REMOTE_WAKE_UP = 0x20, + USB_ATTR_SELF_POWERED = 0x40, + USB_ATTR_BUS_POWERED_RSVD = 0x80 +} usb_cfg_attr_type_t; + +typedef enum +{ + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISO = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INTR = 3 +} usb_cfg_ep_type_t; + +/* Device descriptor structure */ +typedef struct _usb_dev_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u16 idVendor; // Vendor ID assigned by USB forum. + u16 idProduct; // Product ID assigned by Organization. + u16 bcdDevice; // Device Release number in BCD. + u8 iManufacturer; // Index of String descriptor describing Manufacturer. + u8 iProduct; // Index of String descriptor describing Product. + u8 iSerialNumber; // Index of String descriptor describing Serial number. + u8 bNumConfigs; // Number of possible configuration. +} __attribute__((packed)) usb_dev_descr_t; + +/* Device Qualigier descriptor structure */ +typedef struct _usb_dev_qual_descr_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER) + u16 bcdUSB; // USB Spec. Release number (2.1). + u8 bDeviceClass; // Class is specified in the interface descriptor. + u8 bDeviceSubClass; // SubClass is specified in the interface descriptor. + u8 bDeviceProtocol; // Protocol is specified in the interface descriptor. + u8 bMaxPacketSize; // Maximum packet size for EP0. + u8 bNumOtherConfigs; // Number of possible other-speed configurations. + u8 bReserved; // Reserved for future use, must be zero +} __attribute__((packed)) usb_dev_qual_descr_t; + +/* Configuration descriptor structure */ +typedef struct _usb_cfg_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + u16 wTotalLength; // Total length of all descriptors for this configuration. + u8 bNumInterfaces; // Number of interfaces in this configuration. + u8 bConfigurationValue; // Value of this configuration (1 based). + u8 iConfiguration; // Index of String Descriptor describing the configuration. + u8 bmAttributes; // Configuration characteristics. + u8 bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) usb_cfg_descr_t; + +/* Interface descriptor structure */ +typedef struct _usb_inter_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + u8 bInterfaceNumber; // Number of this interface (0 based). + u8 bAlternateSetting; // Value of this alternate interface setting. + u8 bNumEndpoints; // Number of endpoints in this interface. + u8 bInterfaceClass; // Class code (assigned by the USB-IF). + u8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + u8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF). + u8 iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) usb_inter_descr_t; + +/* HID descriptor structure */ +typedef struct _usb_hid_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_HID). + u16 bcdHID; // HID class specification release + u8 bCountryCode; // Country code. + u8 bNumDescriptors; // Number of descriptors. + u8 bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT). + u16 bDescriptorLength; // Report descriptor length. +} __attribute__((packed)) usb_hid_descr_t; + +/* Endpoint descriptor structure */ +typedef struct _usb_ep_descr_t +{ + u8 bLength; // Length of this descriptor. + u8 bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + u8 bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN). + u8 bmAttributes; // Endpoint transfer type. + u16 wMaxPacketSize; // Maximum packet size. + u8 bInterval; // Polling interval in frames. For Interrupt and Isochronous data transfer only. +} __attribute__((packed)) usb_ep_descr_t; + +typedef struct _usb_cfg_simple_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_simple_descr_t; + +typedef struct _usb_cfg_hid_descr_t +{ + usb_cfg_descr_t config; + usb_inter_descr_t interface; + usb_hid_descr_t hid; + usb_ep_descr_t endpoint[2]; +} __attribute__((packed)) usb_cfg_hid_descr_t; + +typedef struct _usb_dev_bot_t +{ + u8 bLength; // Size of this descriptor in bytes. + u8 bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT) + u16 wTotalLength; // Size of this descriptor in bytes. + u8 bNumDeviceCaps; // Number of device capabilities in this descriptor. + + /* Device Capability USB 2.0 Extension Descriptor */ + /* Needed for a USB2.10 device. */ + u8 bLengthCap0; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap0; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap0; // USB2: 2. + u32 bmAttributesCap0; // bit1: Link Power Management (LPM). + + u8 bLengthCap1; // Size of this capability descriptor in bytes. + u8 bDescriptorTypeCap1; // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP) + u8 bDevCapabilityTypeCap1; // USB3: 3. + u8 bmAttributesCap1; // bit1: Latency Tolerance Messaging (LTM). + u16 wSpeedsSupported; // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed. + u8 bFunctionalitySupport; // Lowest speed at which all the functionality is available. 1: Full speed and above. + u8 bU1DevExitLat; // USB3.0 U1 exit latency. + u16 wU2DevExitLat; // USB3.0 U2 exit latency. + +} __attribute__((packed)) usb_dev_bot_t; + +/* Microsoft OS String descriptor structure */ +typedef struct _usb_ms_os_descr_t +{ + u8 bLength; // 0x12 + u8 bDescriptorType; // 3 + u16 wSignature[7]; // "MSFT100" UTF16 LE + u8 bVendorCode; // + u8 bPadding; +} __attribute__((packed)) usb_ms_os_descr_t; + +/* Microsoft Compatible ID Feature descriptor structure */ +typedef struct _usb_ms_cid_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wCompatibilityId; + u8 bSections; + u8 bReserved0[7]; + u8 bInterfaceNumber; + u8 bReserved1; + u8 bCompatibleId[8]; + u8 bSubCompatibleId[8]; + u8 bReserved2[6]; +} __attribute__((packed)) usb_ms_cid_descr_t; + +/* Microsoft Extended Properties Feature descriptor structure */ +typedef struct _usb_ms_ext_prop_descr_t +{ + u32 dLength; + u16 wVersion; + u16 wExtendedProperty; + u16 wSections; + u32 dPropertySize; + u32 dPropertyType; + u16 wPropertyNameLength; + u16 wPropertyName[22]; // UTF16 LE + u32 dPropertyDataLength; + u16 wPropertyData[2]; // UTF16 LE +} __attribute__((packed)) usb_ms_ext_prop_descr_t; + +typedef struct _usb_desc_t +{ + usb_dev_descr_t *dev; + usb_dev_qual_descr_t *dev_qual; + usb_cfg_simple_descr_t *cfg; + usb_cfg_simple_descr_t *cfg_other; + usb_dev_bot_t *dev_bot; + u8 *vendor; + u8 *product; + usb_ms_os_descr_t *ms_os; + usb_ms_cid_descr_t *ms_cid; + usb_ms_ext_prop_descr_t *mx_ext; +} usb_desc_t; + +usb_dev_descr_t usb_device_descriptor_ums = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E0, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_dev_qual_descr_t usb_device_qualifier_descriptor = +{ + .bLength = 10, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_QUALIFIER, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .bNumOtherConfigs = 0x01, + .bReserved = 0x00 +}; + +usb_cfg_simple_descr_t usb_configuration_descriptor_ums = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 0x00, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 0x00 +}; + +usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums = +{ + /* Other Speed Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION, + .config.wTotalLength = 0x20, + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0x00, + .interface.bAlternateSetting = 0x00, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x08, // Mass Storage Class. + .interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[0].wMaxPacketSize = 0x40, + .endpoint[0].bInterval = 0, + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_BULK, + .endpoint[1].wMaxPacketSize = 0x40, + .endpoint[1].bInterval = 0 +}; + +usb_dev_bot_t usb_device_binary_object_descriptor = +{ + .bLength = 5, + .bDescriptorType = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT, + .wTotalLength = 22, + .bNumDeviceCaps = 2, + + /* Device Capability USB 2.0 Extension Descriptor */ + .bLengthCap0 = 7, + .bDescriptorTypeCap0 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap0 = 2, // USB2. + .bmAttributesCap0 = 0, + + /* Device Capability SuperSpeed Descriptor */ + /* Needed for a USB2.10 device. */ + .bLengthCap1 = 10, + .bDescriptorTypeCap1 = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP, + .bDevCapabilityTypeCap1 = 3, // USB3. + .bmAttributesCap1 = 0, + .wSpeedsSupported = 0x6, // FS | HS. + .bFunctionalitySupport = 1, // FS and above. + .bU1DevExitLat = 0, + .wU2DevExitLat = 0 +}; + +u8 usb_vendor_string_descriptor_ums[32] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0, + 'D', 0, 'i', 0, 's', 0, 'k', 0 +}; + +u8 usb_product_string_descriptor_ums[22] = +{ + 8, 0x03, + 'U', 0, 'M', 0, 'S', 0 +}; + +usb_ms_os_descr_t usb_ms_os_descriptor = +{ + .bLength = 0x28, + .bDescriptorType = 0x03, + .wSignature[0] = 'M', + .wSignature[1] = 'S', + .wSignature[2] = 'F', + .wSignature[3] = 'T', + .wSignature[4] = '1', + .wSignature[5] = '0', + .wSignature[6] = '0', + .bVendorCode = 0x99, +}; + +usb_ms_cid_descr_t usb_ms_cid_descriptor = +{ + .dLength = 0x28, + .wVersion = 0x100, + .wCompatibilityId = USB_DESCRIPTOR_MS_COMPAT_ID, + .bSections = 1, + .bInterfaceNumber = 0, + .bReserved1 = 1, + + .bCompatibleId[0] = 'N', + .bCompatibleId[1] = 'Y', + .bCompatibleId[2] = 'X', + .bCompatibleId[3] = 'U', + .bCompatibleId[4] = 'S', + .bCompatibleId[5] = 'B', +}; + +usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums = +{ + .dLength = 0x48, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 1, + + .dPropertySize = 0x3E, + .dPropertyType = 4, // DWORD + + .wPropertyNameLength = 0x2C, + .wPropertyName[0] = 'M', // MaximumTransferLength. + .wPropertyName[1] = 'a', + .wPropertyName[2] = 'x', + .wPropertyName[3] = 'i', + .wPropertyName[4] = 'm', + .wPropertyName[5] = 'u', + .wPropertyName[6] = 'm', + .wPropertyName[7] = 'T', + .wPropertyName[8] = 'r', + .wPropertyName[9] = 'a', + .wPropertyName[10] = 'n', + .wPropertyName[11] = 's', + .wPropertyName[12] = 'f', + .wPropertyName[13] = 'e', + .wPropertyName[14] = 'r', + .wPropertyName[15] = 'L', + .wPropertyName[16] = 'e', + .wPropertyName[17] = 'n', + .wPropertyName[18] = 'g', + .wPropertyName[19] = 't', + .wPropertyName[20] = 'h', + .wPropertyName[21] = 0, + + .dPropertyDataLength = 0x4, + .wPropertyData[0] = 0x00, // 1MB. + .wPropertyData[1] = 0x10, +}; + +usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid = +{ + .dLength = 7, + .wVersion = 0x100, + .wExtendedProperty = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES, + .wSections = 0, +}; + +usb_dev_descr_t usb_device_descriptor_hid_jc = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E1, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_dev_descr_t usb_device_descriptor_hid_touch = +{ + .bLength = 18, + .bDescriptorType = USB_DESCRIPTOR_DEVICE, + .bcdUSB = 0x210, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 0x40, + .idVendor = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955 + .idProduct = 0xA7E2, // Switch: 0x2000, usbd: 0x3000 + .bcdDevice = 0x0101, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigs = 1 +}; + +usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x110, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = 0x43, + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. +}; + +u8 usb_vendor_string_descriptor_hid[22] = +{ + 16, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'U', 0, 'S', 0, 'B', 0 +}; + +u8 usb_product_string_descriptor_hid_jc[24] = +{ + 24, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0 +}; + +u8 usb_product_string_descriptor_hid_touch[26] = +{ + 26, 0x03, + 'N', 0, 'y', 0, 'x', 0, ' ', 0, + 'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0 +}; + +u8 hid_report_descriptor_jc[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop), + 0x09, 0x04, // USAGE (Joystick), + 0xa1, 0x01, // COLLECTION (Application), + 0xa1, 0x02, // COLLECTION (Logical), + 0x75, 0x08, // REPORT_SIZE (8), + 0x95, 0x04, // REPORT_COUNT (4), + 0x15, 0x00, // LOGICAL_MINIMUM (0), + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255), + 0x35, 0x00, // PHYSICAL_MINIMUM (0), + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255), + 0x09, 0x30, // USAGE (X_ID), + 0x09, 0x31, // USAGE (Y_ID), + 0x09, 0x32, // USAGE (Z_ID), + 0x09, 0x35, // USAGE (Rz_ID), + 0x81, 0x02, // INPUT (IOF_Variable), + 0x75, 0x04, // REPORT_SIZE (4), + 0x95, 0x01, // REPORT_COUNT (1), + 0x25, 0x07, // LOGICAL_MAXIMUM (7), + 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315), + 0x65, 0x14, // UNIT (Eng_Rot_Angular_Pos), + 0x09, 0x39, // USAGE (Hat_Switch), + 0x81, 0x42, // INPUT (IOF_NullposVar), + 0x65, 0x00, // UNIT (Unit_None), + 0x75, 0x01, // REPORT_SIZE (1), + 0x95, 0x0c, // REPORT_COUNT (12), + 0x25, 0x01, // LOGICAL_MAXIMUM (1), + 0x45, 0x01, // PHYSICAL_MAXIMUM (1), + 0x05, 0x09, // USAGE_PAGE (Button_ID), + 0x19, 0x01, // USAGE_MINIMUM (1), + 0x29, 0x0c, // USAGE_MAXIMUM (12), + 0x81, 0x02, // INPUT (IOF_Variable), + 0xc0, // END_COLLECTION(), + 0xc0 // END_COLLECTION(), +}; + +u8 hid_report_descriptor_touch[] = +{ + 0x05, 0x0d, // USAGE_PAGE (Digitizers) + 0x09, 0x05, // USAGE (Touch Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x05, // REPORT_ID (Touch pad) + 0x09, 0x22, // USAGE (Finger) + 0xa1, 0x02, // COLLECTION (Logical) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x09, 0x42, // USAGE (Tip switch) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x15, 0x00, // LOGICAL_MINIMUM (1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x09, 0x54, // USAGE (Contact Count) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x0A, // LOGICAL_MAXIMUM (10) + 0x09, 0x51, // USAGE (Contact Identifier) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // 0x15, 0x00, // LOGICAL_MINIMUM (0) + // 0x26, 0xF8, 0x2A, // LOGICAL_MAXIMUM (11000) + // 0x95, 0x01, // REPORT_COUNT (1) + // 0x75, 0x08, // REPORT_SIZE (16) + // 0x09, 0x30, // USAGE (Pressure) + // 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x01, // USAGE_PAGE (Generic Desk.. + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x04, // LOGICAL_MAXIMUM (1279) + 0x75, 0x10, // REPORT_SIZE (16) + 0x55, 0x0e, // UNIT_EXPONENT (-2) + 0x65, 0x13, // UNIT(Inch,EngLinear) + 0x09, 0x30, // USAGE (X) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xFF, 0x04, // PHYSICAL_MAXIMUM (1279) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x26, 0xCF, 0x02, // LOGICAL_MAXIMUM (719) + 0x46, 0xCF, 0x02, // PHYSICAL_MAXIMUM (719) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x05, 0x0d, // USAGE PAGE (Digitizers) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; + +usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch = +{ + /* Configuration descriptor structure */ + .config.bLength = 9, + .config.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, + .config.wTotalLength = sizeof(usb_cfg_hid_descr_t), + .config.bNumInterfaces = 0x01, + .config.bConfigurationValue = 0x01, + .config.iConfiguration = 0x00, + .config.bmAttributes = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD, + .config.bMaxPower = 32 / 2, + + /* Interface descriptor structure */ + .interface.bLength = 9, + .interface.bDescriptorType = USB_DESCRIPTOR_INTERFACE, + .interface.bInterfaceNumber = 0, + .interface.bAlternateSetting = 0, + .interface.bNumEndpoints = 2, + .interface.bInterfaceClass = 0x03, // Human Interface Device Class. + .interface.bInterfaceSubClass = 0x00, // SCSI Transparent Command Set. + .interface.bInterfaceProtocol = 0x00, // Bulk-Only Transport. + .interface.iInterface = 0x00, + + .hid.bLength = 9, + .hid.bDescriptorType = USB_DESCRIPTOR_HID, + .hid.bcdHID = 0x111, + .hid.bCountryCode = 0, + .hid.bNumDescriptors = 1, + .hid.bClassDescriptorType = USB_DESCRIPTOR_HID_REPORT, + .hid.bDescriptorLength = sizeof(hid_report_descriptor_touch), + + /* Endpoint descriptor structure EP1 IN */ + .endpoint[0].bLength = 7, + .endpoint[0].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN. + .endpoint[0].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[0].wMaxPacketSize = 0x200, + .endpoint[0].bInterval = 4, // 4ms on FS, 8ms on HS. + + /* Endpoint descriptor structure EP1 OUT */ + .endpoint[1].bLength = 7, + .endpoint[1].bDescriptorType = USB_DESCRIPTOR_ENDPOINT, + .endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT. + .endpoint[1].bmAttributes = USB_EP_TYPE_INTR, + .endpoint[1].wMaxPacketSize = 0x200, + .endpoint[1].bInterval = 4 // 4ms on FS, 8ms on HS. +}; + +usb_desc_t usb_gadget_ums_descriptors = +{ + .dev = &usb_device_descriptor_ums, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = &usb_configuration_descriptor_ums, + .cfg_other = &usb_other_speed_config_descriptor_ums, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_ums, + .product = usb_product_string_descriptor_ums, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_ums +}; + +usb_desc_t usb_gadget_hid_jc_descriptors = +{ + .dev = &usb_device_descriptor_hid_jc, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_jc, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_jc, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; + +usb_desc_t usb_gadget_hid_touch_descriptors = +{ + .dev = &usb_device_descriptor_hid_touch, + .dev_qual = &usb_device_qualifier_descriptor, + .cfg = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_touch, + .cfg_other = NULL, + .dev_bot = &usb_device_binary_object_descriptor, + .vendor = usb_vendor_string_descriptor_hid, + .product = usb_product_string_descriptor_hid_touch, + .ms_os = &usb_ms_os_descriptor, + .ms_cid = &usb_ms_cid_descriptor, + .mx_ext = &usb_ms_ext_prop_descriptor_hid +}; + +#endif diff --git a/ariane/src/bdk/usb/usb_gadget_hid.c b/ariane/src/bdk/usb/usb_gadget_hid.c new file mode 100644 index 0000000..e26dd9a --- /dev/null +++ b/ariane/src/bdk/usb/usb_gadget_hid.c @@ -0,0 +1,432 @@ +/* + * USB Gadget HID driver for Tegra X1 + * + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +typedef struct _gamepad_report_t +{ + u8 x; + u8 y; + u8 z; + u8 rz; + + u8 hat:4; + u8 btn1:1; + u8 btn2:1; + u8 btn3:1; + u8 btn4:1; + + u8 btn5:1; + u8 btn6:1; + u8 btn7:1; + u8 btn8:1; + u8 btn9:1; + u8 btn10:1; + u8 btn11:1; + u8 btn12:1; +} __attribute__((packed)) gamepad_report_t; + +typedef struct _jc_cal_t +{ + bool cl_done; + bool cr_done; + u16 clx_max; + u16 clx_min; + u16 cly_max; + u16 cly_min; + u16 crx_max; + u16 crx_min; + u16 cry_max; + u16 cry_min; +} jc_cal_t; + +static jc_cal_t jc_cal_ctx; + +static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad) +{ + // Calibrate left stick. + if (!jc_cal_ctx.cl_done) + { + if (jc_pad->conn_l + && jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400 + && jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00) + { + jc_cal_ctx.clx_max = jc_pad->lstick_x + 0x72; + jc_cal_ctx.clx_min = jc_pad->lstick_x - 0x72; + jc_cal_ctx.cly_max = jc_pad->lstick_y + 0x72; + jc_cal_ctx.cly_min = jc_pad->lstick_y - 0x72; + jc_cal_ctx.cl_done = true; + } + else + return false; + } + + // Calibrate right stick. + if (!jc_cal_ctx.cr_done) + { + if (jc_pad->conn_r + && jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400 + && jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00) + { + jc_cal_ctx.crx_max = jc_pad->rstick_x + 0x72; + jc_cal_ctx.crx_min = jc_pad->rstick_x - 0x72; + jc_cal_ctx.cry_max = jc_pad->rstick_y + 0x72; + jc_cal_ctx.cry_min = jc_pad->rstick_y - 0x72; + jc_cal_ctx.cr_done = true; + } + else + return false; + } + + return true; +} + +static bool _jc_poll(gamepad_report_t *rpt) +{ + // Poll Joy-Con. + jc_gamepad_rpt_t *jc_pad = joycon_poll(); + + if (!jc_pad) + return false; + + // Exit emulation if Left stick and Home are pressed. + if (jc_pad->l3 && jc_pad->home) + return true; + + if (!jc_cal_ctx.cl_done || !jc_cal_ctx.cr_done) + { + if (!_jc_calibration(jc_pad)) + return false; + } + + // Re-calibrate on disconnection. + if (!jc_pad->conn_l) + jc_cal_ctx.cl_done = false; + if (!jc_pad->conn_r) + jc_cal_ctx.cr_done = false; + + // Calculate left analog stick. + if (jc_pad->lstick_x <= jc_cal_ctx.clx_max && jc_pad->lstick_x >= jc_cal_ctx.clx_min) + rpt->x = 0x7F; + else if (jc_pad->lstick_x > jc_cal_ctx.clx_max) + { + u16 x_raw = (jc_pad->lstick_x - jc_cal_ctx.clx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.clx_min - jc_pad->lstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->x = 0x7F - x_raw; + } + + if (jc_pad->lstick_y <= jc_cal_ctx.cly_max && jc_pad->lstick_y >= jc_cal_ctx.cly_min) + rpt->y = 0x7F; + else if (jc_pad->lstick_y > jc_cal_ctx.cly_max) + { + u16 y_raw = (jc_pad->lstick_y - jc_cal_ctx.cly_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->y = 0x7F - y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cly_min - jc_pad->lstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->y = 0x7F + y_raw; + } + + // Calculate right analog stick. + if (jc_pad->rstick_x <= jc_cal_ctx.crx_max && jc_pad->rstick_x >= jc_cal_ctx.crx_min) + rpt->z = 0x7F; + else if (jc_pad->rstick_x > jc_cal_ctx.crx_max) + { + u16 x_raw = (jc_pad->rstick_x - jc_cal_ctx.crx_max) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F + x_raw; + } + else + { + u16 x_raw = (jc_cal_ctx.crx_min - jc_pad->rstick_x) / 7; + if (x_raw > 0x7F) + x_raw = 0x7F; + rpt->z = 0x7F - x_raw; + } + + if (jc_pad->rstick_y <= jc_cal_ctx.cry_max && jc_pad->rstick_y >= jc_cal_ctx.cry_min) + rpt->rz = 0x7F; + else if (jc_pad->rstick_y > jc_cal_ctx.cry_max) + { + u16 y_raw = (jc_pad->rstick_y - jc_cal_ctx.cry_max) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->rz = 0x7F - y_raw; + } + else + { + u16 y_raw = (jc_cal_ctx.cry_min - jc_pad->rstick_y) / 7; + if (y_raw > 0x7F) + y_raw = 0x7F; + rpt->rz = 0x7F + y_raw; + } + + // Set D-pad. + switch ((jc_pad->buttons >> 16) & 0xF) + { + case 0: // none + rpt->hat = 0xF; + break; + case 1: // down + rpt->hat = 4; + break; + case 2: // up + rpt->hat = 0; + break; + case 4: // right + rpt->hat = 2; + break; + case 5: // down + right + rpt->hat = 3; + break; + case 6: // up + right + rpt->hat = 1; + break; + case 8: // left + rpt->hat = 6; + break; + case 9: // down + left + rpt->hat = 5; + break; + case 10: // up + left + rpt->hat = 7; + break; + default: + rpt->hat = 0xF; + break; + } + + // Set buttons. + rpt->btn1 = jc_pad->b; // x. + rpt->btn2 = jc_pad->a; // a. + rpt->btn3 = jc_pad->y; // b. + rpt->btn4 = jc_pad->x; // y. + + rpt->btn5 = jc_pad->l; + rpt->btn6 = jc_pad->r; + rpt->btn7 = jc_pad->zl; + rpt->btn8 = jc_pad->zr; + rpt->btn9 = jc_pad->minus; + rpt->btn10 = jc_pad->plus; + rpt->btn11 = jc_pad->l3; + rpt->btn12 = jc_pad->r3; + + //rpt->btn13 = jc_pad->cap; + //rpt->btn14 = jc_pad->home; + + return false; +} + +typedef struct _touchpad_report_t +{ + u8 rpt_id; + u8 tip_switch:1; + u8 count:7; + + u8 id; + + //u16 z; + u16 x; + u16 y; +} __attribute__((packed)) touchpad_report_t; + +static bool _fts_touch_read(touchpad_report_t *rpt) +{ + static touch_event touchpad; + + touch_poll(&touchpad); + + rpt->rpt_id = 5; + rpt->count = 1; + + // Decide touch enable. + switch (touchpad.type & STMFTS_MASK_EVENT_ID) + { + //case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 1; + break; + case STMFTS_EV_MULTI_TOUCH_LEAVE: + rpt->x = touchpad.x; + rpt->y = touchpad.y; + //rpt->z = touchpad.z; + rpt->id = touchpad.fingers ? touchpad.fingers - 1 : 0; + rpt->tip_switch = 0; + break; + case STMFTS_EV_NO_EVENT: + return false; + } + + return true; +} + +static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len) +{ + u8 status = usb_device_write_ep1_in((u8 *)USB_EP_BULK_IN_BUF_ADDR, len, NULL, true); + + if (status == 26) + { + usbs->set_text(usbs->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(3); + } + + // Linux mitigation: If timed out, clear status. + if (status == 3) + return 0; + + return status; +} + +static bool _hid_poll_jc(usb_ctxt_t *usbs) +{ + if (_jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR)) + return true; + + // Send HID report. + if (_hid_transfer_start(usbs, sizeof(gamepad_report_t))) + return true; // EP Error. + + return false; +} + +static bool _hid_poll_touch(usb_ctxt_t *usbs) +{ + _fts_touch_read((touchpad_report_t *)USB_EP_BULK_IN_BUF_ADDR); + + // Send HID report. + if (_hid_transfer_start(usbs, sizeof(touchpad_report_t))) + return true; // EP Error. + + return false; +} + +int usb_device_gadget_hid(usb_ctxt_t *usbs) +{ + int res = 0; + u32 gadget_type; + u32 polling_time; + + if (usbs->type == USB_HID_GAMEPAD) + { + polling_time = 8000; + gadget_type = USB_GADGET_HID_GAMEPAD; + } + else + { + polling_time = 4000; + gadget_type = USB_GADGET_HID_TOUCHPAD; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_device_init()) + { + usbd_end(false, true); + return 1; + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_device_ep0_initialize(gadget_type)) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Waiting for HID report request"); + + if (usb_device_get_hid_report()) + goto error; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started HID emulation"); + + u32 timer_sys = get_tmr_ms() + 5000; + while (true) + { + u32 timer = get_tmr_us(); + + // Parse input device. + if (usbs->type == USB_HID_GAMEPAD) + { + if (_hid_poll_jc(usbs)) + break; + } + else + { + if (_hid_poll_touch(usbs)) + break; + } + + // Check for suspended USB in case the cable was pulled. + if (usb_device_get_suspended()) + break; // Disconnected. + + // Handle control endpoint. + usbd_handle_ep0_pending_control_transfer(); + + // Wait max gadget timing. + timer = get_tmr_us() - timer; + if (timer < polling_time) + usleep(polling_time - timer); + + if (timer_sys < get_tmr_ms()) + { + usbs->system_maintenance(true); + timer_sys = get_tmr_ms() + 5000; + } + } + + usbs->set_text(usbs->label, "#C7EA46 Status:# HID ended"); + goto exit; + +error: + usbs->set_text(usbs->label, "#C7EA46 Status:# Timed out or canceled"); + res = 1; + +exit: + usbd_end(true, false); + + return res; +} diff --git a/ariane/src/bdk/usb/usb_gadget_ums.c b/ariane/src/bdk/usb/usb_gadget_ums.c new file mode 100644 index 0000000..7b16624 --- /dev/null +++ b/ariane/src/bdk/usb/usb_gadget_ums.c @@ -0,0 +1,1891 @@ +/* + * USB Gadget UMS driver for Tegra X1 + * + * Copyright (c) 2003-2008 Alan Stern + * Copyright (c) 2009 Samsung Electronics + * Author: Michal Nazarewicz + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DPRINTF(...) + +#define UMS_MAX_LUN 1 // Only 1 disk/partition for now. + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 // USBC. +#define USB_BULK_IN_FLAG 0x80 + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 // USBS. + +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +#define UMS_DISK_LBA_SHIFT 9 +#define UMS_DISK_LBA_SIZE (1 << UMS_DISK_LBA_SHIFT) + +#define UMS_DISK_MAX_IO_TRANSFER_64K (USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT) +#define UMS_DISK_MAX_IO_TRANSFER_32K (UMS_DISK_MAX_IO_TRANSFER_64K / 2) + +#define UMS_SCSI_TRANSFER_512K (0x80000 >> UMS_DISK_LBA_SHIFT) + +#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER >> UMS_DISK_LBA_SHIFT) + +// Length of a SCSI Command Data Block. +#define SCSI_MAX_CMD_SZ 16 + +// SCSI device types +#define SCSI_TYPE_DISK 0x00 + +// SCSI commands. +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_LOG_SENSE 0x4D +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1A +#define SC_MODE_SENSE_10 0x5A +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xA8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_READ_HEADER 0x44 +#define SC_READ_TOC 0x43 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1D +#define SC_START_STOP_UNIT 0x1B +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2F +#define SC_WRITE_6 0x0A +#define SC_WRITE_10 0x2A +#define SC_WRITE_12 0xAA + +// SCSI Sense Key/Additional Sense Code/ASC Qualifier values. +#define SS_NO_SENSE 0x0 +#define SS_COMMUNICATION_FAILURE 0x40800 +#define SS_INVALID_COMMAND 0x52000 +#define SS_INVALID_FIELD_IN_CDB 0x52400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x52100 +#define SS_MEDIUM_NOT_PRESENT 0x23A00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x55302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x62800 +#define SS_RESET_OCCURRED 0x62900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x53900 +#define SS_UNRECOVERED_READ_ERROR 0x31100 +#define SS_WRITE_ERROR 0x30C02 +#define SS_WRITE_PROTECTED 0x72700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + +enum ums_state { + UMS_STATE_NORMAL = 0, + UMS_STATE_ABORT_BULK_OUT, + UMS_STATE_PROTOCOL_RESET, + UMS_STATE_EXIT, + UMS_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +enum buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +typedef struct _bulk_recv_pkt_t { + u32 Signature; // 'USBC'. + u32 Tag; // Unique per command id. + u32 DataTransferLength; // Size of the data. + u8 Flags; // Direction in bit 7. + u8 Lun; // LUN (normally 0). + u8 Length; // Of the CDB, <= SCSI_MAX_CMD_SZ. + u8 CDB[16]; // Command Data Block. +} bulk_recv_pkt_t; + +typedef struct _bulk_send_pkt_t { + u32 Signature; // 'USBS'. + u32 Tag; // Same as original command. + u32 Residue; // Amount not transferred. + u8 Status; +} bulk_send_pkt_t; + +typedef struct _logical_unit_t +{ + sdmmc_t *sdmmc; + sdmmc_storage_t *storage; + + u32 num_sectors; + u32 offset; + + int unmounted; + + u32 ro; + u32 type; + u32 partition; + u32 removable; + u32 prevent_medium_removal; + + u32 info_valid; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; +} logical_unit_t; + +typedef struct _bulk_ctxt_t { + u32 bulk_in; + int bulk_in_status; + u32 bulk_in_length; + u32 bulk_in_length_actual; + u8 *bulk_in_buf; + enum buffer_state bulk_in_buf_state; + + u32 bulk_out; + int bulk_out_status; + u32 bulk_out_length; + u32 bulk_out_length_actual; + int bulk_out_ignore; + u8 *bulk_out_buf; + enum buffer_state bulk_out_buf_state; +} bulk_ctxt_t; + +typedef struct _usbd_gadget_ums_t { + bulk_ctxt_t bulk_ctxt; + + int cmnd_size; + u8 cmnd[SCSI_MAX_CMD_SZ]; + + u32 lun_idx; // lun index + logical_unit_t lun; + + u32 bulk_out_maxpacket; // 512 + enum ums_state state; // For exception handling. + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + + u32 phase_error; + u32 short_packet_received; + + int thread_wakeup_needed; + int can_stall; + + u32 timeouts; + + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usbd_gadget_ums_t; + +static inline void put_array_le_to_be16(u16 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 8; + _p[1] = val; +} + +static inline void put_array_le_to_be32(u32 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 24; + _p[1] = val >> 16; + _p[2] = val >> 8; + _p[3] = val; +} + +static inline u16 get_array_be_to_le16(const void *p) +{ + const u8 *_p = p; + u16 val = _p[0] << 8 | _p[1]; + return val; +} + +static inline u32 get_array_be_to_le24(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 16) | (_p[1] << 8) | _p[2]; + return val; +} + +static inline u32 get_array_be_to_le32(const void *p) +{ + const u8 *_p = p; + u32 val = (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3]; + return val; +} + +static void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state) +{ + /* Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. */ + if (ums->state <= new_state) { + ums->state = new_state; + ums->thread_wakeup_needed = 1; + } +} + +static void ums_handle_ep0_ctrl(usbd_gadget_ums_t *ums) +{ + if (usbd_handle_ep0_pending_control_transfer()) + raise_exception(ums, UMS_STATE_PROTOCOL_RESET); +} + +static int ums_wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums) +{ + /* usbd_set_ep_wedge(bulk_ctxt->bulk_in); */ + + return 0; +} + +static int ums_set_stall(u32 ep) +{ + usbd_set_ep_stall(ep, 1); + + return 0; +} + +static int ums_clear_stall(u32 ep) +{ + usbd_set_ep_stall(ep, 0); + + return 0; +} + +static void _ums_transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, bool sync) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_device_write_ep1_in( + bulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length, + &bulk_ctxt->bulk_in_length_actual, sync); + + if (bulk_ctxt->bulk_in_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(bulk_ctxt->bulk_in); + } + + if (sync) + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_device_read_ep1_out( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual, sync); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + if (sync) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _ums_transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_out_status = usb_device_read_ep1_out_big_reads( + bulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length, + &bulk_ctxt->bulk_out_length_actual); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; +} + +static void _ums_transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep) +{ + if (ep == bulk_ctxt->bulk_in) + { + bulk_ctxt->bulk_in_status = usb_device_ep1_in_writing_finish(&bulk_ctxt->bulk_in_length_actual); + + if (bulk_ctxt->bulk_in_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP IN"); + usbd_flush_endpoint(bulk_ctxt->bulk_in); + } + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + } + else + { + bulk_ctxt->bulk_out_status = usb_device_ep1_out_reading_finish(&bulk_ctxt->bulk_out_length_actual); + + if (bulk_ctxt->bulk_out_status == 26) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error EP OUT"); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + } + + bulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL; + } +} + +static void _ums_reset_buffer(bulk_ctxt_t *bulk_ctxt, u32 ep) +{ + if (ep == bulk_ctxt->bulk_in) + bulk_ctxt->bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + else + bulk_ctxt->bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; +} + +/* + * The following are old data based on max 64KB SCSI transfers. + * The endpoint xfer is actually 41.2 MB/s and SD card max 39.2 MB/s, with higher SCSI + * transfers, but the concurrency still helps and increases speeds by 20%. + * + * Concurrency of the SDMMC and USB xfers is very important with no cache. + * The worst offender being the SD card. We are already limited by bus, so + * concurrency helps minimize the SDMMC overhead. + * Max achieved bulk endpoint rate on a Tegra X1 and USB2.0 is 39.4 MB/s. + * + * USB bulk endpoint raw max transfer rate: + * 39.4MB/S - SCSI 128KB. + * 38.2MB/s - SCSI 64KB. + * + * 128 KB, 64 KB, 32 KB, 16 KB, 8 KB - Internal SDMMC I\O Sizes + * ------------------------------------------------------------------------------------- + * eMMC - Toshiba - 4MB reads: 314.8 MB/s: + * 225.9 MB/s, 168.6 MB/s, 114.7 MB/s, 86.4 MB/s, 50.3 MB/s - RAW SDMMC. + * 33.5 MB/s, 31.9 MB/s, 29.3 MB/s, 27.1 MB/s, 22.1 MB/s - SCSI 128KB, No concurrency. + * 33.5 MB/s, 35.3 MB/s, 36.3 MB/s, 37.3 MB/s, 37.8 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 31.1 MB/s, 28.7 MB/s, 26.5 MB/s, 21.7 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 31.1 MB/s, 32.7 MB/s, 34.4 MB/s, 35.0 MB/s - SCSI 64KB, Concurrency. + * + * SD Card - Samsung Evo+ 128GB - 4MB reads: 91.6 MB/s: + * 72.6 MB/s, 62.8 MB/s, 47.4 MB/s, 31.1 MB/s, 18.5 MB/s - RAW SDMMC. + * 25.5 MB/s, 24.2 MB/s, 21.5 MB/s, 17.4 MB/s, 12.6 MB/s - SCSI 128KB, No concurrency. + * 25.5 MB/s, 30.0 MB/s, 32.6 MB/s, 28.3 MB/s, 18.0 MB/s - SCSI 128KB, Concurrency. + * --.- --/-, 23.8 MB/s, 21.2 MB/s, 17.1 MB/s, 12.5 MB/s - SCSI 64KB, No concurrency. + * --.- --/-, 23.8 MB/s, 27.2 MB/s, 25.8 MB/s, 17.5 MB/s - SCSI 64KB, Concurrency. + */ + +static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 lba_offset; + bool first_read = true; + u8 *sdmmc_buf = (u8 *)SDXC_BUF_ALIGNED; + + // Get the starting LBA and check that it's not too big. + if (ums->cmnd[0] == SC_READ_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits, but we don't use them. + if ((ums->cmnd[1] & ~0x18) != 0) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + // Check that request data size is not 0. + u32 amount_left = ums->data_size_from_cmnd >> UMS_DISK_LBA_SHIFT; + if (!amount_left) + return -5; // I/O error. /* No default reply */ + + // Limit IO transfers based on request for faster concurrent reads. + u32 max_io_transfer = (amount_left >= UMS_SCSI_TRANSFER_512K) ? + UMS_DISK_MAX_IO_TRANSFER_64K : UMS_DISK_MAX_IO_TRANSFER_32K; + + while (true) + { + // Max io size and end sector limits. + u32 amount = MIN(amount_left, max_io_transfer); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + + // Check if it is a read past the end sector. + if (!amount) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + bulk_ctxt->bulk_in_length = 0; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + break; + } + + // Do the SDMMC read. + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf)) + amount = 0; + + // Wait for the async USB transfer to finish. + if (!first_read) + _ums_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in); + + lba_offset += amount; + amount_left -= amount; + ums->residue -= amount << UMS_DISK_LBA_SHIFT; + + bulk_ctxt->bulk_in_length = amount << UMS_DISK_LBA_SHIFT; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + bulk_ctxt->bulk_in_buf = sdmmc_buf; + + // If an error occurred, report it and its position. + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Read"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + // Last SDMMC read. Last part will be sent by the finish reply function. + if (!amount_left) + break; + + // Start the USB transfer. + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, false); + first_read = false; + + // Increment our buffer to read new data. + sdmmc_buf += amount << UMS_DISK_LBA_SHIFT; + } + + return -5; // I/O error no default reply here. /* No default reply */ +} + +/* + * Writes are another story. + * Tests showed that big writes are faster than concurrent 32K usb reads + writes. + * The only thing that can help here is caching the writes. But for the simplicity + * of this implementation it will not be implemented yet. + */ + +static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + static char txt_buf[256]; + u32 amount_left_to_req, amount_left_to_write; + u32 usb_lba_offset, lba_offset; + u32 amount; + + if (ums->lun.ro) + { + ums->lun.sense_data = SS_WRITE_PROTECTED; + + return -22; // Invalid argument. + } + + if (ums->cmnd[0] == SC_WRITE_6) + lba_offset = get_array_be_to_le24(&ums->cmnd[1]); + else + { + lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + + // We allow DPO and FUA bypass cache bits. We only implement FUA by performing synchronous output. + if (ums->cmnd[1] & ~0x18) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + + // Check that starting LBA is not past the end sector offset. + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + /* Carry out the file writes */ + usb_lba_offset = lba_offset; + amount_left_to_req = ums->data_size_from_cmnd; + amount_left_to_write = ums->data_size_from_cmnd; + + while (amount_left_to_write > 0) + { + + /* Queue a request for more data from the host */ + if (amount_left_to_req) + { + + // Limit write to max supported read from EP OUT. + amount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER << UMS_DISK_LBA_SHIFT); + + if (usb_lba_offset >= ums->lun.num_sectors) //////////Check if it works with concurrency + { + ums->set_text(ums->label, "#C7EA46 Status:# Write Error - Past last sector"); + amount_left_to_req = 0; + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = usb_lba_offset; + ums->lun.info_valid = 1; + continue; + } + + // Get the next buffer. + usb_lba_offset += amount >> UMS_DISK_LBA_SHIFT; + ums->usb_amount_left -= amount; + amount_left_to_req -= amount; + + bulk_ctxt->bulk_out_length = amount; + + _ums_transfer_out_big_read(ums, bulk_ctxt); + } + + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + { + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // Did something go wrong with the transfer?. + if (bulk_ctxt->bulk_out_status != 0) + { + ums->lun.sense_data = SS_COMMUNICATION_FAILURE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + s_printf(txt_buf, "#C7EA46 Status:# Write Error - Comm failure %d", bulk_ctxt->bulk_out_status); + ums->set_text(ums->label, txt_buf); + break; + } + + amount = bulk_ctxt->bulk_out_length_actual; + + if ((ums->lun.num_sectors - lba_offset) < (amount >> UMS_DISK_LBA_SHIFT)) + { + DPRINTF("write %X @ %X beyond end %X\n", amount, lba_offset, ums->lun.num_sectors); + amount = (ums->lun.num_sectors - lba_offset) << UMS_DISK_LBA_SHIFT; + } + + /* + * Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = MIN(amount, bulk_ctxt->bulk_out_length); + + /* Don't write a partial block */ + amount -= (amount & 511); + if (amount == 0) + goto empty_write; + + /* Perform the write */ + if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset, + amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf)) + amount = 0; + +DPRINTF("file write %X @ %X\n", amount, lba_offset); + + lba_offset += amount >> UMS_DISK_LBA_SHIFT; + amount_left_to_write -= amount; + ums->residue -= amount; + + /* If an error occurred, report it and its position */ + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error SDMMC Write"); + ums->lun.sense_data = SS_WRITE_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + empty_write: + // Did the host decide to stop early? + if (bulk_ctxt->bulk_out_length_actual < bulk_ctxt->bulk_out_length) + { + ums->set_text(ums->label, "#C7EA46 Status:# Empty Write"); + ums->short_packet_received = 1; + break; + } + } + } + + return -5; // I/O error. /* No default reply */ +} + +static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + // Check that start LBA is past the end sector offset. + u32 lba_offset = get_array_be_to_le32(&ums->cmnd[2]); + if (lba_offset >= ums->lun.num_sectors) + { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + + return -22; // Invalid argument. + } + + // We allow DPO but we don't implement it. Check that nothing else is enabled. + if (ums->cmnd[1] & ~0x10) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + u32 verification_length = get_array_be_to_le16(&ums->cmnd[7]); + if (verification_length == 0) + return -5; // I/O error. /* No default reply */ + + u32 amount; + while (verification_length > 0) + { + + // Limit to EP buffer size and end sector offset. + amount = MIN(verification_length, USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT); + amount = MIN(amount, ums->lun.num_sectors - lba_offset); + if (amount == 0) { + ums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + + if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)) + amount = 0; + +DPRINTF("File read %X @ %X\n", amount, lba_offset); + + if (!amount) + { + ums->set_text(ums->label, "#C7EA46 Status:# Error file verify"); + ums->lun.sense_data = SS_UNRECOVERED_READ_ERROR; + ums->lun.sense_data_info = lba_offset; + ums->lun.info_valid = 1; + break; + } + lba_offset += amount; + verification_length -= amount; + } + return 0; +} + +static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + memset(buf, 0, 36); + + // Enable Vital Product Data (EVPD) and Unit Serial Number. + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) + { + buf[0] = 0; + buf[1] = ums->cmnd[2]; + buf[2] = 0; + buf[3] = 20; // Additional length. + + buf += 4; + s_printf((char *)buf, "%04X%s", + ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC "); + + switch (ums->lun.partition) + { + case 0: + strcpy((char *)buf + strlen((char *)buf), "RAW"); + break; + case EMMC_GPP + 1: + s_printf((char *)buf + strlen((char *)buf), "GPP"); + break; + case EMMC_BOOT0 + 1: + s_printf((char *)buf + strlen((char *)buf), "BOOT0"); + break; + case EMMC_BOOT1 + 1: + s_printf((char *)buf + strlen((char *)buf), "BOOT1"); + break; + } + + for (u32 i = strlen((char *)buf); i < 20; i++) + buf[i] = ' '; + + return 24; + } + else /* if (ums->cmnd[1] == 0 && ums->cmnd[2] == 0) */ // Standard inquiry. + { + buf[0] = SCSI_TYPE_DISK; + buf[1] = ums->lun.removable ? 0x80 : 0; + buf[2] = 6; // ANSI INCITS 351-2001 (SPC-2).////////SPC2: 4, SPC4: 6 + buf[3] = 2; // SCSI-2 INQUIRY data format. + buf[4] = 31; // Additional length. + // buf5-7: No special options. + + // Vendor ID. Max 8 chars. + buf += 8; + strcpy((char *)buf, "hekate"); + + // Product ID. Max 16 chars. + buf += 8; + switch (ums->lun.partition) + { + case 0: + s_printf((char *)buf, "%s", "SD RAW"); + break; + case EMMC_GPP + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP"); + break; + case EMMC_BOOT0 + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0"); + break; + case EMMC_BOOT1 + 1: + s_printf((char *)buf, "%s%s", + ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1"); + break; + } + + // Rev ID. Max 4 chars. + buf += 16; + strcpy((char *)buf, "1.00"); + + return 36; + } +} + +static int _scsi_request_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 sd, sdinfo; + int valid; + + sd = ums->lun.sense_data; + sdinfo = ums->lun.sense_data_info; + valid = ums->lun.info_valid << 7; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + + memset(buf, 0, 18); + buf[0] = valid | 0x70; // Valid, current error. + buf[2] = SK(sd); + put_array_le_to_be32(sdinfo, &buf[3]); // Sense information. + buf[7] = 18 - 8; // Additional sense length. + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + + return 18; +} + +static int _scsi_read_capacity(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u32 lba = get_array_be_to_le32(&ums->cmnd[2]); + int pmi = ums->cmnd[8]; + + // Check the PMI and LBA fields. + if (pmi > 1 || (pmi == 0 && lba != 0)) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + put_array_le_to_be32(ums->lun.num_sectors - 1, &buf[0]); // Max logical block. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + + return 8; +} + +static int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + u8 sub_page_code = ums->cmnd[3]; + + if (ums->cmnd[1] & 1) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return -22; // Invalid argument. + } + + if (pc != 1) // Current cumulative values. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + memset(buf, 0, 8); + if (page_code == 0x00 && !sub_page_code) // Supported pages. + { + valid_page = true; + buf[0] = 0x00; // Page code. + buf += 4; + + buf[0] = 0x00; // Page 0. + buf[1] = 0x0D; // Page 1. + + buf += 2; + } + else if (page_code == 0x0d && !sub_page_code) // Temperature. + { + valid_page = true; + buf[0] = 0x0D; + buf += 4; + + put_array_le_to_be16(0, &buf[0]); // Param code. + buf[2] = 1; // Param control byte. + buf[3] = 2; // Param length. + buf[4] = 0; // Reserved. + buf[5] = 35; // Temperature (C) current (PCB here). + + put_array_le_to_be16(0, &buf[6]); // PARAMETER CODE + buf[8] = 1; // Param control byte. + buf[9] = 2; // Param length. + buf[10] = 0; // Reserved. + buf[11] = 60; // Temperature (C) reference. + + buf += 12; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + put_array_le_to_be16(len - 4, &buf0[2]); + + return len; +} + +static int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + u8 *buf0 = buf; + bool valid_page = false; + + u8 pc = ums->cmnd[2] >> 6; + u8 page_code = ums->cmnd[2] & 0x3F; + bool changeable_values = pc == 1; + bool all_pages = page_code == 0x3F; + + if ((ums->cmnd[1] & ~0x08) != 0) // Mask away DBD. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + if (pc == 3) + { + ums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + + return -22; // Invalid argument. + } + + /* Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. */ + memset(buf, 0, 8); + if (ums->cmnd[0] == SC_MODE_SENSE_6) + { + buf[2] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 4; + } + else // SC_MODE_SENSE_10. + { + buf[3] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA. + buf += 8; + } + + // The only page we support is the Caching page. + // What about x1C + if (page_code == 0x08 || all_pages) + { + valid_page = true; + buf[0] = 0x08; // Page code. + buf[1] = 18; // Page length. + memset(buf + 2, 0, 18); // Set all parameters to 0. + + // None of the fields are changeable. + if (!changeable_values) + { + // Write Cache enable, Read Cache not disabled, Multiplication Factor off. + buf[2] = 0x04; + + // Multiplication Factor is disabled, so all values below are 1x LBA. + put_array_le_to_be16(0xFFFF, &buf[4]); // Disable Prefetch if >32MB. + put_array_le_to_be16(0x0000, &buf[6]); // Minimum Prefetch 0MB. + put_array_le_to_be16(0xFFFF, &buf[8]); // Maximum Prefetch 32MB. + put_array_le_to_be16(0xFFFF, &buf[10]); // Maximum Prefetch ceiling 32MB. + } + + buf += 20; + } + + // Check that a valid page mode data length was requested. + u32 len = buf - buf0; + if (!valid_page) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + /* Store the mode data length */ + if (ums->cmnd[0] == SC_MODE_SENSE_6) + buf0[0] = len - 1; + else + put_array_le_to_be16(len - 2, buf0); + + return len; +} + +static int _scsi_start_stop(usbd_gadget_ums_t *ums) +{ + int loej, start; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return -22; // Invalid argument. + } + else if ((ums->cmnd[1] & ~0x01) != 0 || // Mask away Immed. + (ums->cmnd[4] & ~0x03) != 0) // Mask LoEj, Start. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; + } + + loej = ums->cmnd[4] & 0x02; + start = ums->cmnd[4] & 0x01; + + // We do not support re-mounting. + if (start) + { + if (ums->lun.unmounted) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return -22; + } + + return 0; + } + + // Check if we are allowed to unload the media. + if (ums->lun.prevent_medium_removal) + { + ums->set_text(ums->label, "#C7EA46 Status:# Unload attempt prevented"); + ums->lun.sense_data = SS_MEDIUM_REMOVAL_PREVENTED; + + return -22; + } + + if (!loej) + return 0; + + // Unmount means we exit UMS because of ejection. + ums->lun.unmounted = 1; + + return 0; +} + +static int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums) +{ + int prevent; + + if (!ums->lun.removable) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + + return -22; // Invalid argument. + } + + prevent = ums->cmnd[4] & 0x01; + if ((ums->cmnd[4] & ~0x01) != 0) // Mask away Prevent. + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + + // Notify for possible unmounting? + // Normally we sync here but we do synced writes to SDMMC. + if (ums->lun.prevent_medium_removal && !prevent) + ; + + ums->lun.prevent_medium_removal = prevent; + + return 0; +} + +static int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 *buf = (u8 *)bulk_ctxt->bulk_in_buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; // Only the Current/Maximum Capacity Descriptor. + buf += 4; + + put_array_le_to_be32(ums->lun.num_sectors, &buf[0]); // Number of blocks. + put_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]); // Block length. + buf[4] = 0x02; // Current capacity. + + return 12; +} + +// Check whether the command is properly formed and whether its data size +// and direction agree with the values we already have. +static int _ums_check_scsi_cmd(usbd_gadget_ums_t *ums, int cmnd_size, + enum data_direction data_dir, u32 mask, int needs_medium) +{ +//const char dirletter[4] = {'u', 'o', 'i', 'n'}; +DPRINTF("SCSI command: %X; Dc=%d, D%c=%X; Hc=%d, H%c=%X\n", + ums->cmnd[0], cmnd_size, dirletter[(int)ums->data_dir], + ums->data_size_from_cmnd, ums->cmnd_size, + dirletter[(int)data_dir], ums->data_size); + + // We can't reply if we don't know the direction and size. + if (ums->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + + // This is a phase error but we continue and only transfer as much we can. + if (ums->data_size < ums->data_size_from_cmnd) + { + ums->data_size_from_cmnd = ums->data_size; + ums->phase_error = 1; + } + + ums->residue = ums->data_size; + ums->usb_amount_left = ums->data_size; + + if (ums->data_dir != data_dir && ums->data_size_from_cmnd > 0) + { + ums->phase_error = 1; + + return -22; // Invalid argument. + } + + // Cmd length verification. + if (cmnd_size != ums->cmnd_size) + { + + // Special case workaround for Windows and Xbox 360. + if (cmnd_size <= ums->cmnd_size) + cmnd_size = ums->cmnd_size; + else + { + ums->phase_error = 1; + + return -22; // Invalid argument. + } + } + + // check that LUN ums->cmnd[1] >> 5 is 0 because of only one. + + if (ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + // If a unit attention condition exists, only INQUIRY and REQUEST SENSE + // commands are allowed. + if (ums->lun.unit_attention_data != SS_NO_SENSE && ums->cmnd[0] != SC_INQUIRY && + ums->cmnd[0] != SC_REQUEST_SENSE) + { + ums->lun.sense_data = ums->lun.unit_attention_data; + ums->lun.unit_attention_data = SS_NO_SENSE; + + return -22; + } + + // Check that only command bytes listed in the mask are set. + ums->cmnd[1] &= 0x1F; // Mask away the LUN. + for (u32 i = 1; i < cmnd_size; ++i) + { + if (ums->cmnd[i] && !(mask & (1 << i))) + { + ums->lun.sense_data = SS_INVALID_FIELD_IN_CDB; + + return -22; // Invalid argument. + } + } + + // If the medium isn't mounted and the command needs to access it, return an error. + if (ums->lun.unmounted && needs_medium) + { + ums->lun.sense_data = SS_MEDIUM_NOT_PRESENT; + + return -22; + } + + return 0; +} + +static int _ums_parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u32 len; + int reply = -22; // Invalid argument. + + ums->phase_error = 0; + ums->short_packet_received = 0; + + switch (ums->cmnd[0]) + { + case SC_INQUIRY: + ums->data_size_from_cmnd = ums->cmnd[4]; + u32 mask = (1<<4); + if (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) // Inquiry S/N. + mask = (1<<1) | (1<<2) | (1<<4); + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, mask, 0); + if (reply == 0) + reply = _scsi_inquiry(ums, bulk_ctxt); + break; + + case SC_LOG_SENSE: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_log_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SELECT_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (1<<1) | (1<<4), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; + } + break; + + case SC_MODE_SELECT_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (3<<7), 0); + if (reply == 0) + { + // We don't support MODE SELECT. + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; + } + break; + + case SC_MODE_SENSE_6: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (1<<4), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_MODE_SENSE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0); + if (reply == 0) + reply = _scsi_mode_sense(ums, bulk_ctxt); + break; + + case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<4), 0); + if (reply == 0) + reply = _scsi_prevent_allow_removal(ums); + break; + + case SC_READ_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_read(ums, bulk_ctxt); + break; + + case SC_READ_CAPACITY: + ums->data_size_from_cmnd = 8; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (0xf<<2) | (1<<8), 1); + if (reply == 0) + reply = _scsi_read_capacity(ums, bulk_ctxt); + break; + case SC_READ_FORMAT_CAPACITIES: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]); + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (3<<7), 1); + if (reply == 0) + reply = _scsi_read_format_capacities(ums, bulk_ctxt); + break; + + case SC_REQUEST_SENSE: + ums->data_size_from_cmnd = ums->cmnd[4]; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<4), 0); + if (reply == 0) + reply = _scsi_request_sense(ums, bulk_ctxt); + break; + + case SC_START_STOP_UNIT: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<1) | (1<<4), 0); + if (reply == 0) + reply = _scsi_start_stop(ums); + break; + + case SC_SYNCHRONIZE_CACHE: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_NONE, (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = 0; // Don't bother + break; + + case SC_TEST_UNIT_READY: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_NONE, 0, 1); + break; + + // This command is used by Windows. We support a minimal version and BytChk must be 0. + case SC_VERIFY: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_NONE, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_verify(ums, bulk_ctxt); + break; + + case SC_WRITE_6: + len = ums->cmnd[4]; + ums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_10: + ums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + case SC_WRITE_12: + ums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT; + reply = _ums_check_scsi_cmd(ums, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1); + if (reply == 0) + reply = _scsi_write(ums, bulk_ctxt); + break; + + // Mandatory commands that we don't implement. No need. + case SC_READ_HEADER: + case SC_READ_TOC: + case SC_FORMAT_UNIT: + case SC_RELEASE: + case SC_RESERVE: + case SC_SEND_DIAGNOSTIC: + default: + ums->data_size_from_cmnd = 0; + reply = _ums_check_scsi_cmd(ums, ums->cmnd_size, DATA_DIR_UNKNOWN, 0xFF, 0); + if (reply == 0) + { + ums->lun.sense_data = SS_INVALID_COMMAND; + reply = -22; // Invalid argument. + } + break; + } + + if (reply == -22) // Invalid argument. + reply = 0; // Error reply length. + + // Set up reply buffer for finish_reply(). Otherwise it's already set. + if (reply >= 0 && ums->data_dir == DATA_DIR_TO_HOST) + { + reply = MIN((u32)reply, ums->data_size_from_cmnd); + bulk_ctxt->bulk_in_length = reply; + bulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL; + ums->residue -= reply; + } + + return 0; +} + +static int pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; // For the first iteration. + u32 current_len_to_keep = bulk_ctxt->bulk_in_length; + ums->usb_amount_left = current_len_to_keep + ums->residue; + + while (ums->usb_amount_left > 0) + { + u32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + memset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep); + bulk_ctxt->bulk_in_length = nsend; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + ums->usb_amount_left -= nsend; + current_len_to_keep = 0; + } + + return 0; +} + +static int throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + if (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY || ums->usb_amount_left > 0) + { + // Try to submit another request if we need one. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_EMPTY && ums->usb_amount_left > 0) + { + u32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE); + + bulk_ctxt->bulk_out_length = amount; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + ums->usb_amount_left -= amount; + + return 0; + } + + // Throw away the data in a filled buffer. + if (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL) + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + // A short packet or an error ends everything. + if (bulk_ctxt->bulk_out_length_actual != bulk_ctxt->bulk_out_length || + bulk_ctxt->bulk_out_status != 0) + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + return -4; // Interrupted system call + } + } + return 0; +} + +static int finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = 0; + + switch (ums->data_dir) { + case DATA_DIR_NONE: + break; // Nothing to send. + + // If this is a CB or CBI with an unknown command, we mustn't + // try to send or receive any data. Stall if we can and wait reset. + case DATA_DIR_UNKNOWN: + if (ums->can_stall) + { + ums_set_stall(bulk_ctxt->bulk_out); + rc = ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# Direction unknown. Stalled both EP"); + } // Else do nothing. + break; + + // All but the last buffer of data have already been sent. + case DATA_DIR_TO_HOST: + if (ums->data_size) + { + // If there's no residue, simply send the last buffer. + if (!ums->residue) + { + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't + * stall, pad out the remaining data with 0's. */ + } + else if (ums->can_stall) + { + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); + rc = ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# Residue. Stalled EP IN"); + } + else + rc = pad_with_zeros(ums, bulk_ctxt); + } + + // In case we used SDMMC transfer, reset the buffer address. + _ums_reset_buffer(bulk_ctxt, bulk_ctxt->bulk_in); + break; + + // We have processed all we want from the data the host has sent. + // There may still be outstanding bulk-out requests. + case DATA_DIR_FROM_HOST: + if (ums->residue) + { + if (ums->short_packet_received) // Did the host stop sending unexpectedly early? + { + raise_exception(ums, UMS_STATE_ABORT_BULK_OUT); + rc = -4; // Interrupted system call + } + else // We can't stall. Read in the excess data and throw it away. + rc = throw_away_data(ums, bulk_ctxt); + } + + break; + } + + return rc; +} + +/* + * Medium ejection heuristics. + * + * Windows: + * Uses Start/Stop Unit. Only Stop with LoEj. Observed ONLY on very specific windows machines. + * Uses Prevent/Allow Medium Removal. (For big reads and ANY write.) //////Except trivial writes. Needs check with prefetch ON + * Sends Test Unit Ready every 1s at idle. (Needs 1 EP Timeout protection: 2s) + * Does not send data when ejects. In the case it does, + * it loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0 and only goes in J-State when it ejects. + * + * Linux: + * Uses Start/Stop Unit. Stops with LoEj when Media prevention is off. + * Uses Prevent/Allow Medium Removal. (For big read and any write.) + * Sends Test Unit Ready every 2s at idle. (Needs 2 EP Timeouts protection: 4s) + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + * + * Mac OS: + * Uses Start/Stop. Stops with LoEj when Allow Medium Removal is enabled. + * Uses Prevent/Allow Medium Removal. (Properly. Enables at mount and only disables it when ejects.) + * Does not send Test Unit Ready at idle. But Prevent Medium Removal is enabled. + * Loops into Request Sense and Test Unit Ready when ejects. + * Line always at SE0. + */ + +static int received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + /* Was this a real packet? Should it be ignored? */ + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore || ums->lun.unmounted) + { + if (bulk_ctxt->bulk_out_status || ums->lun.unmounted) + { + DPRINTF("USB: EP timeout\n"); + // In case we disconnected, exit UMS. + // Raise timeout if removable and didn't got a unit ready command inside 4s. + if (bulk_ctxt->bulk_out_status == 28 || + (bulk_ctxt->bulk_out_status == 3 && ums->lun.removable && !ums->lun.prevent_medium_removal)) + { + if (bulk_ctxt->bulk_out_status == 3) + { + if (usb_device_get_port_status() == 0x885) + { + ums->set_text(ums->label, "#C7EA46 Status:# EP in sleep"); + ums->timeouts += 10; + } + else + DPRINTF("USB: EP removable\n"); + } + else + { + gfx_printf("USB: EP disabled\n"); + msleep(500); + } + + ums->timeouts += 4; + } + + if (ums->lun.unmounted) + { + ums->set_text(ums->label, "#C7EA46 Status:# Medium unmounted"); + ums->timeouts++; + } + + if (ums->timeouts > 20) + raise_exception(ums, UMS_STATE_EXIT); + } + + if (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore) + return -22; // Invalid argument. + } + + /* Is the CBW valid? */ + bulk_recv_pkt_t *cbw = (bulk_recv_pkt_t *)bulk_ctxt->bulk_out_buf; + if (bulk_ctxt->bulk_out_length_actual != USB_BULK_CB_WRAP_LEN || cbw->Signature != USB_BULK_CB_SIG) + { + gfx_printf("USB: invalid CBW: len %X sig 0x%X\n", bulk_ctxt->bulk_out_length_actual, cbw->Signature); + + // The Bulk-only spec says we MUST stall the IN endpoint + // (6.6.1), so it's unavoidable. It also says we must + // retain this state until the next reset, but there's + // no way to tell the controller driver it should ignore + // Clear-Feature(HALT) requests. + // + // We aren't required to halt the OUT endpoint; instead + // we can simply accept and discard any data received + // until the next reset. + ums_wedge_bulk_in_endpoint(ums); + bulk_ctxt->bulk_out_ignore = 1; + return -22; // Invalid argument. + } + + /* Is the CBW meaningful? */ + if (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length <= 0 || cbw->Length > SCSI_MAX_CMD_SZ) + { + gfx_printf("USB: non-meaningful CBW: lun = %X, flags = 0x%X, cmdlen %X\n", + cbw->Lun, cbw->Flags, cbw->Length); + + /* We can do anything we want here, so let's stall the + * bulk pipes if we are allowed to. */ + if (ums->can_stall) + { + ums_set_stall(bulk_ctxt->bulk_out); + ums_set_stall(bulk_ctxt->bulk_in); + ums->set_text(ums->label, "#C7EA46 Status:# CBW unknown - Stalled both EP"); + } + + return -22; // Invalid argument. + } + + /* Save the command for later */ + ums->cmnd_size = cbw->Length; + memcpy(ums->cmnd, cbw->CDB, ums->cmnd_size); + + if (cbw->Flags & USB_BULK_IN_FLAG) + ums->data_dir = DATA_DIR_TO_HOST; + else + ums->data_dir = DATA_DIR_FROM_HOST; + + ums->data_size = cbw->DataTransferLength; + + if (ums->data_size == 0) + ums->data_dir = DATA_DIR_NONE; + + ums->lun_idx = cbw->Lun; + ums->tag = cbw->Tag; + + if (!ums->lun.unmounted) + ums->timeouts = 0; + + return 0; +} + +static int get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + int rc = 0; + + /* Wait for the next buffer to become available */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY) + // { + // //wait irq. + // } + + bulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN; + + /* Queue a request to read a Bulk-only CBW */ + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, true); + + /* We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. */ + + /* Wait for the CBW to arrive */ + // while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_FULL) + // { + // //wait irq. + // } + + rc = received_cbw(ums, bulk_ctxt); + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + return rc; +} + +static void send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + u8 status = USB_STATUS_PASS; + u32 sd = ums->lun.sense_data; + + if (ums->phase_error) + { + ums->set_text(ums->label, "#C7EA46 Status:# Phase-error"); + status = USB_STATUS_PHASE_ERROR; + sd = SS_INVALID_COMMAND; + } + else if (sd != SS_NO_SENSE) + { + DPRINTF("USB: CMD fail\n"); + status = USB_STATUS_FAIL; + DPRINTF("USB: Sense: SK x%02X, ASC x%02X, ASCQ x%02X; info x%X\n", + SK(sd), ASC(sd), ASCQ(sd), ums->lun.sense_data_info); + } + + /* Store and send the Bulk-only CSW */ + bulk_send_pkt_t *csw = (bulk_send_pkt_t *)bulk_ctxt->bulk_in_buf; + + csw->Signature = USB_BULK_CS_SIG; + csw->Tag = ums->tag; + csw->Residue = ums->residue; + csw->Status = status; + + bulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN; + _ums_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, true); +} + +static void handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt) +{ + enum ums_state old_state; + + /* Clear out the controller's fifos */ + usbd_flush_endpoint(bulk_ctxt->bulk_in); + usbd_flush_endpoint(bulk_ctxt->bulk_out); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ + + bulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; + bulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY; + + old_state = ums->state; + + if (old_state != UMS_STATE_ABORT_BULK_OUT) + { + ums->lun.prevent_medium_removal = 0; + ums->lun.sense_data = SS_NO_SENSE; + ums->lun.unit_attention_data = SS_NO_SENSE; + ums->lun.sense_data_info = 0; + ums->lun.info_valid = 0; + } + + ums->state = UMS_STATE_NORMAL; + + /* Carry out any extra actions required for the exception */ + switch (old_state) + { + case UMS_STATE_NORMAL: + break; + case UMS_STATE_ABORT_BULK_OUT: + send_status(ums, bulk_ctxt); + break; + + case UMS_STATE_PROTOCOL_RESET: + /* In case we were forced against our will to halt a + * bulk endpoint, clear the halt now. (The SuperH UDC + * requires this.) */ + if (bulk_ctxt->bulk_out_ignore) + { + bulk_ctxt->bulk_out_ignore = 0; + ums_clear_stall(bulk_ctxt->bulk_in); + } + ums->lun.unit_attention_data = SS_RESET_OCCURRED; + break; + + case UMS_STATE_EXIT: + ums->state = UMS_STATE_TERMINATED; /* Stop the thread */ + break; + + default: + break; + } +} + +static inline void _system_maintainance(usbd_gadget_ums_t *ums) +{ + static u32 timer_dram = 0; + static u32 timer_status_bar = 0; + + u32 time = get_tmr_ms(); + + if (timer_dram < time) + { + minerva_periodic_training(); + timer_dram = get_tmr_ms() + 100; + } + else if (timer_status_bar < time) + { + ums->system_maintenance(true); + timer_status_bar = get_tmr_ms() + 30000; + } +} + +int usb_device_gadget_ums(usb_ctxt_t *usbs) +{ + int res = 0; + sdmmc_t sdmmc; + sdmmc_storage_t storage; + + usbs->set_text(usbs->label, "#C7EA46 Status:# Started USB"); + + if (usb_device_init()) + { + usbd_end(false, true); + return 1; + } + + usbd_gadget_ums_t ums; + memset(&ums, 0, sizeof(usbd_gadget_ums_t)); + + ums.bulk_out_maxpacket = usbd_get_max_pkt_length(USB_EP_BULK_IN); + ums.state = UMS_STATE_NORMAL; + ums.can_stall = 0; + + ums.bulk_ctxt.bulk_in = 3; + ums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR; + + ums.bulk_ctxt.bulk_out = 2; + ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR; + + // Set LUN parameters. + ums.lun.ro = usbs->ro; + ums.lun.type = usbs->type; + ums.lun.partition = usbs->partition; + ums.lun.offset = usbs->offset; + ums.lun.removable = 1; // Always removable to force OSes to use prevent media removal. + ums.lun.unit_attention_data = SS_RESET_OCCURRED; + + // Set system functions + ums.label = usbs->label; + ums.set_text = usbs->set_text; + ums.system_maintenance = usbs->system_maintenance; + + ums.set_text(ums.label, "#C7EA46 Status:# Mounting disk"); + + // Initialize sdmmc. + if (usbs->type == MMC_SD) + { + sd_mount(); + sd_unmount(); + ums.lun.sdmmc = &sd_sdmmc; + ums.lun.storage = &sd_storage; + } + else + { + ums.lun.sdmmc = &sdmmc; + ums.lun.storage = &storage; + sdmmc_storage_init_mmc(ums.lun.storage, ums.lun.sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400); + sdmmc_storage_set_mmc_partition(ums.lun.storage, ums.lun.partition - 1); + } + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for connection"); + + // Initialize Control Endpoint. + if (usb_device_ep0_initialize(USB_GADGET_UMS)) + goto error; + + ums.set_text(ums.label, "#C7EA46 Status:# Waiting for LUN"); + + if (usb_device_get_max_lun(0)) // One device for now. + goto error; + + ums.set_text(ums.label, "#C7EA46 Status:# Started UMS"); + + if (usbs->sectors) + ums.lun.num_sectors = usbs->sectors; + else + ums.lun.num_sectors = ums.lun.storage->sec_cnt; + + do + { + // Do DRAM training and update system tasks. + _system_maintainance(&ums); + + // Check for force unmount button combo. + if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + { + // Check if we are allowed to unload the media. + if (ums.lun.prevent_medium_removal) + ums.set_text(ums.label, "#C7EA46 Status:# Unload attempt prevented"); + else + break; + } + + if (ums.state != UMS_STATE_NORMAL) + { + handle_exception(&ums, &ums.bulk_ctxt); + continue; + } + + ums_handle_ep0_ctrl(&ums); + + if (get_next_command(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + ums_handle_ep0_ctrl(&ums); + + if (_ums_parse_scsi_cmd(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + ums_handle_ep0_ctrl(&ums); + + if (finish_reply(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL)) + continue; + + send_status(&ums, &ums.bulk_ctxt); + } while (ums.state != UMS_STATE_TERMINATED); + + ums.set_text(ums.label, "#C7EA46 Status:# Disk ejected"); + goto exit; + +error: + ums.set_text(ums.label, "#C7EA46 Status:# Timed out or canceled"); + res = 1; + +exit: + if (ums.lun.type == MMC_EMMC) + sdmmc_storage_end(ums.lun.storage); + + usbd_end(true, false); + + return res; +} diff --git a/ariane/src/bdk/usb/usb_t210.h b/ariane/src/bdk/usb/usb_t210.h new file mode 100644 index 0000000..d670317 --- /dev/null +++ b/ariane/src/bdk/usb/usb_t210.h @@ -0,0 +1,172 @@ +/* + * USB driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _USB_T210_H_ +#define _USB_T210_H_ + +#include + +/* General USB registers */ +#define USB1_IF_USB_SUSP_CTRL 0x400 +#define SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV (1 << 3) +#define SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV (1 << 4) +#define SUSP_CTRL_USB_PHY_CLK_VALID (1 << 7) +#define SUSP_CTRL_UTMIP_RESET (1 << 11) +#define SUSP_CTRL_UTMIP_PHY_ENB (1 << 12) +#define SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET (1 << 25) +#define USB1_IF_USB_PHY_VBUS_SENSORS 0x404 +#define USB1_UTMIP_XCVR_CFG0 0x808 +#define USB1_UTMIP_BIAS_CFG0 0x80C +#define USB1_UTMIP_HSRX_CFG0 0x810 +#define USB1_UTMIP_HSRX_CFG1 0x814 +#define USB1_UTMIP_TX_CFG0 0x820 +#define USB1_UTMIP_MISC_CFG1 0x828 +#define USB1_UTMIP_DEBOUNCE_CFG0 0x82C +#define USB1_UTMIP_SPARE_CFG0 0x834 +#define USB1_UTMIP_XCVR_CFG1 0x838 +#define USB1_UTMIP_BIAS_CFG1 0x83C +#define USB1_UTMIP_BIAS_CFG2 0x850 +#define USB1_UTMIP_XCVR_CFG2 0x854 +#define USB1_UTMIP_XCVR_CFG3 0x858 + +/* USB Queue Head Descriptor */ +#define USB2_QH_USB2D_QH_EP_BASE (USB_BASE + 0x1000) +#define USB_QHD_EP_CAP_IOS_ENABLE (1 << 15) +#define USB_QHD_EP_CAP_MAX_PKT_LEN_MASK 0x7FF +#define USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS (1 << 29) +#define USB_QHD_EP_CAP_MULTI_NON_ISO (0 << 30) +#define USB_QHD_EP_CAP_MULTI_1 (1 << 30) +#define USB_QHD_EP_CAP_MULTI_2 (2 << 30) +#define USB_QHD_EP_CAP_MULTI_3 (3 << 30) + +#define USB_QHD_TOKEN_XFER_ERROR (1 << 3) +#define USB_QHD_TOKEN_BUFFER_ERROR (1 << 5) +#define USB_QHD_TOKEN_HALTED (1 << 6) +#define USB_QHD_TOKEN_ACTIVE (1 << 7) +#define USB_QHD_TOKEN_MULT_OVERR_MASK (2 << 10) +#define USB_QHD_TOKEN_IRQ_ON_COMPLETE (1 << 15) +#define USB_QHD_TOKEN_TOTAL_BYTES_SHIFT 16 + +/* USB_OTG/USB_1 controllers register bits */ +#define USB2D_PORTSC1_SUSP (1 << 7) + +#define USB2D_USBCMD_RUN (1 << 0) +#define USB2D_USBCMD_RESET (1 << 1) +#define USB2D_USBCMD_ITC_MASK (0xFF << 16) + +#define USB2D_USBSTS_UI (1 << 0) +#define USB2D_USBSTS_UEI (1 << 1) +#define USB2D_USBSTS_PCI (1 << 2) +#define USB2D_USBSTS_FRI (1 << 3) +#define USB2D_USBSTS_SEI (1 << 4) +#define USB2D_USBSTS_AAI (1 << 5) +#define USB2D_USBSTS_URI (1 << 6) +#define USB2D_USBSTS_SRI (1 << 7) +#define USB2D_USBSTS_SLI (1 << 8) + +#define USB2D_USBMODE_CM_MASK (3 << 0) +#define USB2D_USBMODE_CM_IDLE 0 +#define USB2D_USBMODE_CM_RSVD 1 +#define USB2D_USBMODE_CM_DEVICE 2 +#define USB2D_USBMODE_CM_HOST 3 + +#define USB2D_ENDPT_STATUS_RX_OFFSET (1 << 0) +#define USB2D_ENDPT_STATUS_TX_OFFSET (1 << 16) + +#define USB2D_ENDPTCTRL_RX_EP_STALL (1 << 0) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL (0 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_ISO (1 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_BULK (2 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_INTR (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_TYPE_MASK (3 << 2) +#define USB2D_ENDPTCTRL_RX_EP_INHIBIT (1 << 5) +#define USB2D_ENDPTCTRL_RX_EP_RESET (1 << 6) +#define USB2D_ENDPTCTRL_RX_EP_ENABLE (1 << 7) +#define USB2D_ENDPTCTRL_TX_EP_STALL (1 << 16) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL (0 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_ISO (1 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_BULK (2 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_INTR (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_TYPE_MASK (3 << 18) +#define USB2D_ENDPTCTRL_TX_EP_INHIBIT (1 << 21) +#define USB2D_ENDPTCTRL_TX_EP_RESET (1 << 22) +#define USB2D_ENDPTCTRL_TX_EP_ENABLE (1 << 23) + +#define USB2D_HOSTPC1_DEVLC_ASUS (1 << 17) +#define USB2D_HOSTPC1_DEVLC_PHCD (1 << 22) +#define USB2D_HOSTPC1_DEVLC_PSPD_MASK (3 << 25) + +#define USB2D_OTGSC_USB_ID_PULLUP (1 << 5) +#define USB2D_OTGSC_USB_IRQ_STS_MASK (0x7F << 16) + +/* USB_OTG/USB_1 controllers registers */ +typedef struct _t210_usb2d_t +{ + vu32 id; + vu32 unk0; + vu32 hw_host; + vu32 hw_device; + vu32 hw_txbuf; + vu32 hw_rxbuf; + vu32 unk1[26]; + vu32 gptimer0ld; + vu32 gptimer0ctrl; + vu32 gptimer1ld; + vu32 gptimer1ctrl; + vu32 unk2[28]; + vu16 caplength; + vu16 hciversion; + vu32 hcsparams; + vu32 hccparams; + vu32 unk3[5]; + vu32 dciversion; + vu32 dccparams; + vu32 extsts; + vu32 usbextintr; + vu32 usbcmd; + vu32 usbsts; + vu32 usbintr; + vu32 frindex; + vu32 unk4; + vu32 periodiclistbase; + vu32 asynclistaddr; + vu32 asyncttsts; + vu32 burstsize; + vu32 txfilltuning; + vu32 unk6; + vu32 icusb_ctrl; + vu32 ulpi_viewport; + vu32 rsvd0[4]; + vu32 portsc1; + vu32 rsvd1[15]; + vu32 hostpc1_devlc; + vu32 rsvd2[15]; + vu32 otgsc; + vu32 usbmode; + vu32 unk10; + vu32 endptnak; + vu32 endptnak_enable; + vu32 endptsetupstat; + vu32 endptprime; + vu32 endptflush; + vu32 endptstatus; + vu32 endptcomplete; + vu32 endptctrl[16]; +} t210_usb2d_t; + +#endif diff --git a/ariane/src/bdk/usb/usbd.c b/ariane/src/bdk/usb/usbd.c new file mode 100644 index 0000000..2952ce8 --- /dev/null +++ b/ariane/src/bdk/usb/usbd.c @@ -0,0 +1,1696 @@ +/* + * USB Device driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef enum +{ + USB_HW_EP0 = 0, + USB_HW_EP1 = 1 +} usb_hw_ep_t; + +typedef enum +{ + USB_EP_ADDR_CTRL_OUT = 0x00, + USB_EP_ADDR_CTRL_IN = 0x80, + USB_EP_ADDR_BULK_OUT = 0x01, + USB_EP_ADDR_BULK_IN = 0x81, +} usb_ep_addr_t; + +typedef enum +{ + USB_EP_CFG_RESET = 0, + USB_EP_CFG_STALL = 1 +} usb_ep_cfg_t; + +typedef enum +{ + USB_EP_STATUS_IDLE = 0, + USB_EP_STATUS_ACTIVE = 1, + USB_EP_STATUS_ERROR = 2, + USB_EP_STATUS_NO_CONFIG = 3, + USB_EP_STATUS_STALLED = 4, + USB_EP_STATUS_DISABLED = 5 +} usb_ep_status_t; + +typedef enum { + USB_SETUP_RECIPIENT_DEVICE = 0, + USB_SETUP_RECIPIENT_INTERFACE = 1, + USB_SETUP_RECIPIENT_ENDPOINT = 2, + USB_SETUP_RECIPIENT_OTHER = 3, + + USB_SETUP_TYPE_STANDARD = 0x00, + USB_SETUP_TYPE_CLASS = 0x20, + USB_SETUP_TYPE_VENDOR = 0x40, + USB_SETUP_TYPE_RESERVED = 0x60, + + USB_SETUP_HOST_TO_DEVICE = 0x00, + USB_SETUP_DEVICE_TO_HOST = 0x80, +} usb_setup_req_type_t; + +typedef enum { + USB_REQUEST_GET_STATUS = 0, + USB_REQUEST_CLEAR_FEATURE = 1, + USB_REQUEST_SET_FEATURE = 3, + USB_REQUEST_SET_ADDRESS = 5, + USB_REQUEST_GET_DESCRIPTOR = 6, + USB_REQUEST_SET_DESCRIPTOR = 7, + USB_REQUEST_GET_CONFIGURATION = 8, + USB_REQUEST_SET_CONFIGURATION = 9, + USB_REQUEST_GET_INTERFACE = 10, + USB_REQUEST_SET_INTERFACE = 11, + USB_REQUEST_SYNCH_FRAME = 12, + + USB_REQUEST_GET_MS_DESCRIPTOR = 0x99, + + USB_REQUEST_BULK_GET_MAX_LUN = 0xFE, + USB_REQUEST_BULK_RESET = 0xFF +} usb_standard_req_t; + +typedef enum { + USB_FEATURE_ENDPOINT_HALT = 0, + USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +} usb_get_status_req_t; + +typedef enum { + USB_STATUS_EP_OK = 0, + USB_STATUS_EP_HALTED = 1, + + USB_STATUS_DEV_SELF_POWERED = 1, + USB_STATUS_DEV_REMOTE_WAKE = 2, +} usb_set_clear_feature_req_t; + +typedef enum { + USB_XFER_DIR_OUT = 0, + USB_XFER_DIR_IN = 1, +} usb_xfer_dir_t; + +typedef enum { + USB_SPEED_LOW = 0, + USB_SPEED_FULL = 1, + USB_SPEED_HIGH = 2, + USB_SPEED_SUPER = 3, +} usb_speed_t; + +typedef enum { + USB_XFER_TYPE_CONTROL = 0, + USB_XFER_TYPE_ISOCHRONOUS = 1, + USB_XFER_TYPE_BULK = 2, + USB_XFER_TYPE_INTERRUPT = 3, +} usb_xfer_type_t; + +typedef struct _dTD_t +{ + vu32 next_dTD; + vu32 info; + vu32 pages[5]; + vu32 reserved; +} dTD_t; + +typedef struct _dQH_t +{ + vu32 ep_capabilities; + vu32 curr_dTD_ptr; + vu32 next_dTD_ptr; + vu32 token; + vu32 buffers[5]; // hmmm. + vu32 reserved; + vu32 setup[2]; + vu32 gap[4]; +} dQH_t; + +typedef struct _usbd_t +{ + volatile dTD_t dtds[4 * 4]; // 4 dTD per endpoint. + volatile dQH_t *qhs; + int ep_configured[4]; + int ep_bytes_requested[4]; +} usbd_t; + +typedef struct _usb_ctrl_setup_t +{ + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} usb_ctrl_setup_t; + +typedef struct _usbd_controller_t +{ + u32 port_speed; + t210_usb2d_t *regs; + usb_ctrl_setup_t control_setup; + usb_desc_t *desc; + usb_gadget_type type; + u8 configuration_set; + u8 usb_phy_ready; + u8 configuration; + u8 interface; + u8 max_lun; + u8 max_lun_set; + u8 bulk_reset_req; + u8 hid_report_sent; + bool charger_detect; +} usbd_controller_t; + +u8 usb_serial_string_descriptor[26] = +{ + 26, 0x03, + 'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00, + '9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00 +}; + +u8 usb_lang_id_string_descriptor[] = +{ + 4, 3, + 0x09, 0x04 +}; + +usbd_t *usbdaemon; + +usbd_controller_t *usbd_otg; +usbd_controller_t usbd_usb_otg_controller_ctxt; + +bool usb_init_done = false; + +u8 *usb_ep0_ctrl_buf = (u8 *)USB_EP_CONTROL_BUF_ADDR; + +static int _usbd_reset_usb_otg_phy_device_mode() +{ + usbd_otg->usb_phy_ready = 0; + + // Clear UTMIP reset. + USB(USB1_IF_USB_SUSP_CTRL) &= ~SUSP_CTRL_UTMIP_RESET; + + // Wait for PHY clock to get validated. + u32 retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return 1; + usleep(1); + } + usbd_otg->usb_phy_ready = 1; + + // Clear all device addresses, enabled setup requests and transmit events. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Set controller mode to idle. + usbd_otg->regs->usbmode &= ~USB2D_USBMODE_CM_MASK; + + // Reset the controller. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RESET; + + // Wait for the reset to complete. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->usbcmd & USB2D_USBCMD_RESET) + { + retries--; + if (!retries) + return 2; + usleep(1); + } + + // Wait for PHY clock to get validated after reset. + retries = 100000; // 200ms timeout. + while (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID)) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Set controller to Device mode. + usbd_otg->regs->usbmode = (usbd_otg->regs->usbmode & ~USB2D_USBMODE_CM_MASK) | USB2D_USBMODE_CM_DEVICE; + + // Wait for the selected mode to be enabled. + retries = 100000; // 200ms timeout. + while ((usbd_otg->regs->usbmode & USB2D_USBMODE_CM_MASK) != USB2D_USBMODE_CM_DEVICE) + { + retries--; + if (!retries) + return 4; + usleep(1); + } + + // Disable all interrupts. + usbd_otg->regs->usbintr = 0; + + // Set the ID pullup and disable all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_ID_PULLUP; + + // Clear all relevant interrupt statuses. + usbd_otg->regs->usbsts = + USB2D_USBSTS_UI | USB2D_USBSTS_UEI | USB2D_USBSTS_PCI | + USB2D_USBSTS_FRI | USB2D_USBSTS_SEI | USB2D_USBSTS_AAI | + USB2D_USBSTS_URI | USB2D_USBSTS_SRI | USB2D_USBSTS_SLI; + + // Disable and clear all OTGSC interrupts. + usbd_otg->regs->otgsc = USB2D_OTGSC_USB_IRQ_STS_MASK; + + // Clear EP0, EP1, EP2 setup requests. + usbd_otg->regs->endptsetupstat = 7; //TODO: Shouldn't this be endptsetupstat = endptsetupstat? + + // Set all interrupts to immediate. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_ITC_MASK; + + return 0; +} + +static void _usb_charger_detect() +{ + // Charger detect init. + usbd_otg->charger_detect = 0; + bool charger_detect_enable = FUSE(FUSE_RESERVED_SW) & 0x10; // Disabled on Switch production. + if (charger_detect_enable) + { + usbd_otg->charger_detect |= 1; + // Configure detect pin. + PINMUX_AUX(PINMUX_AUX_LCD_GPIO1) &= ~(PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_config(GPIO_PORT_V, GPIO_PIN_3, GPIO_MODE_GPIO); + + // Configure charger pin. + PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) &= + ~(PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK); + gpio_config(GPIO_PORT_CC, GPIO_PIN_5, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_5, GPIO_OUTPUT_ENABLE); + + // Enable charger. + if (gpio_read(GPIO_PORT_V, GPIO_PIN_3)) + { + usbd_otg->charger_detect |= 2; + gpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH); + usbd_otg->charger_detect |= 0x100; + USB(USB1_UTMIP_BAT_CHRG_CFG0) = BAT_CHRG_CFG0_OP_SRC_EN; // Clears UTMIP_PD_CHRG and enables charger detect. + usleep(5000); + } + } +} + +int usb_device_init() +{ + if (usb_init_done) + return 0; + + // Configure PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) = CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) | 0x20000000; // Disable reference clock. + u32 pllu_cfg = (((((CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) >> 8 << 8) | 2) & 0xFFFF00FF) | ((0x19 << 8) & 0xFFFF)) & 0xFFE0FFFF) | (1<< 16) | 0x1000000; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | 0x40000000; // Enable. + + // Wait for PLL to stabilize. + u32 timeout = (u32)TMR(TIMERUS_CNTR_1US) + 1300; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & (1 << 27))) // PLL_LOCK. + if ((u32)TMR(TIMERUS_CNTR_1US) > timeout) + break; + usleep(10); + + // Enable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) | 0x2600000 | 0x800000; + + // Enable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = (1 << 22); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = (1 << 22); + usleep(2); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = (1 << 22); + usleep(2); + + // Clear XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = (1 << 14); + + // Enable USB PHY and reset for programming. + u32 usb_susp_ctrl = USB(USB1_IF_USB_SUSP_CTRL); + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_RESET; + USB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_PHY_ENB | SUSP_CTRL_UTMIP_RESET; + + // Disable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) &= 0xFFFFFFFD; + usleep(10); + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) &= 0xBFFFFFFF; + + // Set B_SESS_VLD. + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x1000; + USB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x800; + + // Set UTMIPLL dividers and enable it. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | 0x190000 | 0x100; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | 0x600000; // Set delay count for 38.4Mhz osc crystal. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = ((CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) & 0x7FFF000) | 0x8000 | 0x177) & 0xFFFFAFFF; + + // Wait for UTMIPLL to stabilize. + u32 retries = 10; // Wait 20us + while (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0x80000000) && retries) + { + usleep(1); + retries--; + } + + // Configure UTMIP Transceiver Cells. + u32 fuse_usb_calib = FUSE(FUSE_USB_CALIB); + USB(USB1_UTMIP_XCVR_CFG0) = (((USB(USB1_UTMIP_XCVR_CFG0) & 0xFFFFFFF0) | (fuse_usb_calib & 0xF)) & 0xFE3FFFFF) | ((fuse_usb_calib & 0x3F) << 25 >> 29 << 22); + USB(USB1_UTMIP_XCVR_CFG1) = (USB(USB1_UTMIP_XCVR_CFG1) & 0xFFC3FFFF) | ((fuse_usb_calib << 21) >> 28 << 18); + USB(USB1_UTMIP_XCVR_CFG3) = (USB(USB1_UTMIP_XCVR_CFG3) & 0xFFFFC1FF) | ((FUSE(FUSE_USB_CALIB_EXT) & 0x1F) << 9); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFDFFFFF; + USB(USB1_UTMIP_XCVR_CFG2) = (USB(USB1_UTMIP_XCVR_CFG2) & 0xFFFFF1FF) | 0x400; + usleep(1); + + // Configure misc UTMIP. + USB(USB1_UTMIP_DEBOUNCE_CFG0) = (USB(USB1_UTMIP_DEBOUNCE_CFG0) & 0xFFFF0000) | 0xBB80; + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFC0FF) | 0x100; // when osc is 38.4KHz + + //USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFEE7; unpatched0 + USB(USB1_UTMIP_BIAS_CFG2) |= 2; //patched0 - UTMIP_HSSQUELCH_LEVEL_NEW: 2. + USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFE67; //patched0 - FUSE_HS_IREF_CAP_CFG + USB(USB1_UTMIP_TX_CFG0) |= 0x80000; + + //USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xFFF003FF) | 0x88000 | 0x4000; unpatched1 + USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xF0F003FF) | 0x88000 | 0x4000; //patched1 - reset UTMIP_PCOUNT_UPDN_DIV: From 1 to 0. + USB(USB1_UTMIP_BIAS_CFG2) &= 0xFFFFFFF8; //patched1 - UTMIP_HSSQUELCH_LEVEL_NEW: 0 + + USB(USB1_UTMIP_HSRX_CFG1) = (USB(USB1_UTMIP_HSRX_CFG1) & 0xFFFFFFC1) | 0x12; + USB(USB1_UTMIP_MISC_CFG1) |= 0x40000000; + + // Enable crystal clock. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= 0x40000000; + // Enable USB2 tracking. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= 0x40000; + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4. + + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFC03F07) | 0x78000 | 0x50; // Set delays. + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFFFFFBFF; // Disable Power down bias circuit. + usleep(1); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE) | 2; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + usleep(3); + + // Force PDTRK input into power up. + USB(USB1_UTMIP_BIAS_CFG1) = USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE; + usleep(100); + + // TRK cycle done. Force PDTRK input into power down. + USB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1; + + // Disable USB2_TRK clock and configure UTMIP misc. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) &= 0xFFFBFFFF; + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFEA) | 0x2000000 | 0x28 | 2; + usleep(1); + + USB(USB1_UTMIP_BIAS_CFG0) &= 0xFF3FF7FF; + usleep(1); + + // Clear power downs on UTMIP ID and VBUS wake up, PD, PD2, PDZI, PDCHRP, PDDR. + PMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFFBFFF; // UTMIP_FORCE_PD_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFEFFFF; // UTMIP_FORCE_PD2_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFBFFFF; // UTMIP_FORCE_PDZI_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFFB; // UTMIP_FORCE_PDCHRP_POWERDOWN. + usleep(1); + USB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFEF; // UTMIP_FORCE_PDDR_POWERDOWN. + usleep(1); + + // AHB USB performance cfg. + AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_USB_IMMEDIATE; + AHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) |= ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) = + MEM_PREFETCH_ENABLE | (MEM_PREFETCH_AHB_MST_USB << 26) | (12 << 21) | 0x1000; // addr boundary 64KB + + // Set software and hardware context storage and clear it. + usbdaemon = (usbd_t *)USBD_ADDR; // Depends on USB_TD_BUFFER_PAGE_SIZE aligned address. + usbd_otg = &usbd_usb_otg_controller_ctxt; + memset(usbd_otg, 0, sizeof(usbd_controller_t)); + memset(usbdaemon, 0, sizeof(usbd_t)); + + usbd_otg->regs = (t210_usb2d_t *)USB_OTG_BASE; + usbd_otg->usb_phy_ready = 0; + + // Initialize USB PHY on the USB_OTG Controller (#1) in Device mode. + int result = _usbd_reset_usb_otg_phy_device_mode(); + usbd_otg->configuration_set = 0; + + _usb_charger_detect(); + + if (!result) + usb_init_done = true; + + return result; +} + +static void _usb_device_power_down() +{ + // Enable PHY low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_PHCD; + // Do not use any controller regs after the above! + // A reset or clear of the PHCD suspend bit must happen. + + // Power down OTG and Bias circuits. + USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 11) | (1 << 10); // UTMIP_OTGPD, UTMIP_BIASPD. + + // Power down ID detectors. + USB(USB1_UTMIP_BIAS_CFG0) |= (1 << 23) | (1 << 22); //UTMIP_IDPD_SEL, UTMIP_IDPD_VAL. + + if (usbd_otg->charger_detect) + { + USB(USB1_UTMIP_BAT_CHRG_CFG0) = 1; //UTMIP_PD_CHRG + usbd_otg->charger_detect = 0; + } + + // Power down the UTMIP transceivers. + // UTMIP_FORCE_PDZI_POWERDOWN, UTMIP_FORCE_PD2_POWERDOWN, UTMIP_FORCE_PD_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG0) |= (1 << 18) | (1 << 16) |(1 << 14); + // UTMIP_FORCE_PDDR_POWERDOWN, UTMIP_FORCE_PDCHRP_POWERDOWN, UTMIP_FORCE_PDDISC_POWERDOWN. + USB(USB1_UTMIP_XCVR_CFG1) |= (1 << 4) | (1 << 2) | (1 << 0); + + // Keep UTMIP in reset. + USB(USB1_IF_USB_SUSP_CTRL) |= SUSP_CTRL_UTMIP_RESET; + + // Power down PD trunk. + USB(USB1_UTMIP_BIAS_CFG1) |= (1 << 0); //UTMIP_FORCE_PDTRK_POWERDOWN. + + // Force UTMIP_PLL power down. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 14); // UTMIP_FORCE_PLL_ENABLE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 12); // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= (1 << 4) | (1 << 0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= (1 << 16); // UTMIP_FORCE_PLLU_POWERDOWN. + + // Disable crystal clock. + USB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF; + + // Enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 2; + + // Set XUSB_PADCTL reset + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = (1 << 14); + + // Disable USBD clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = (1 << 22); + + // Completely disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M. + CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x40000000; // Disable PLLU. + CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~0x20000000; // Enable reference clock. + + usb_init_done = false; +} + +static void _usbd_stall_reset_ep1(usb_xfer_dir_t direction, usb_ep_cfg_t stall) +{ + stall &= 1; + if (direction == USB_XFER_DIR_IN) + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16); + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + } + else + { + usbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_RX_EP_STALL) | stall; + if (!stall) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + } +} + +void usbd_end(bool reset_ep, bool only_controller) +{ + if (reset_ep) + { + usbd_flush_endpoint(USB_EP_ALL); + _usbd_stall_reset_ep1(0, USB_EP_CFG_RESET); // EP1 Bulk IN. + _usbd_stall_reset_ep1(1, USB_EP_CFG_RESET); // EP1 Bulk OUT. + //TODO: what about EP0 simultaneous in/out reset. + + usbd_otg->configuration = 0; + usbd_otg->interface = 0; + usbd_otg->configuration_set = 0; + usbd_otg->max_lun_set = 0; + } + + // Stop device controller. + usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; + + // Enable PHY auto low power suspend. + usbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS; + + if (!only_controller) + _usb_device_power_down(); +} + +void usb_device_stall_ep1_bulk_out() +{ + _usbd_stall_reset_ep1(USB_XFER_DIR_OUT, USB_EP_CFG_STALL); +} + +void usb_device_stall_ep1_bulk_in() +{ + _usbd_stall_reset_ep1(USB_XFER_DIR_IN, USB_EP_CFG_STALL); +} + +int usbd_get_max_pkt_length(int endpoint) +{ + switch (endpoint) + { + case USB_EP_CTRL_OUT: + case USB_EP_CTRL_IN: + return 64; + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + if (usbd_otg->port_speed == 2) + return 512; + else + return 64; + default: + return 64; + } +} + +static void _usbd_initialize_ep_ctrl(u32 endpoint) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + + if (!endpoint) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + usbdaemon->qhs[endpoint].next_dTD_ptr = 1; // TERMINATE_SET + + u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16; + + if (direction == USB_XFER_DIR_IN) + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK; + if (actual_ep) + endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK; + else + endpoint_type |= USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_ENABLE; + } + else // EP Bulk OUT. + { + u32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_RX_EP_TYPE_MASK; + if (actual_ep) + { + endpoint_type |= usbd_otg->type ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK; + } + else + endpoint_type |= USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL; + + usbd_otg->regs->endptctrl[actual_ep] = endpoint_type; + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; + + if (actual_ep == USB_HW_EP1) + usbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET; + + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_ENABLE; + } +} + +/*static*/ int _usbd_initialize_ep0() +{ + memset((void *)usbdaemon->qhs, 0, sizeof(dQH_t) * 4); // Clear all used EP queue heads. + memset((void *)usbdaemon->dtds, 0, sizeof(dTD_t) * 4); // Clear all used EP0 token heads. + + usbd_otg->regs->asynclistaddr = (u32)usbdaemon->qhs; + + _usbd_initialize_ep_ctrl(USB_EP_CTRL_OUT); + _usbd_initialize_ep_ctrl(USB_EP_CTRL_IN); + + // Disable Auto Low Power. + usbd_otg->regs->hostpc1_devlc &= ~USB2D_HOSTPC1_DEVLC_ASUS; + + // Initiate an attach event. + usbd_otg->regs->usbcmd |= USB2D_USBCMD_RUN; + + u32 retries = 100000; // 200ms timeout. + while (!(usbd_otg->regs->usbcmd & USB2D_USBCMD_RUN)) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + return 0; +} + +// static void _disable_usb_wdt4() +// { +// if (TIMER_WDT4_STATUS & 1)// active +// { +// TIMER_TMR0_TMR_PTV &= 0x7FFFFFFF; // Disable timer +// TIMER_WDT4_UNLOCK_PATTERN = 0xC45A; // Alow writes to disable counter bit. +// TIMER_WDT4_COMMAND |= 2; // Disable counter +// TIMER_TMR0_TMR_PCR |= 0x40000000;// INTR_CLR +// } +// } + +int usbd_flush_endpoint(u32 endpoint) +{ + + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + u32 reg_mask = endpoint; + + // Flash all endpoints or 1. + if (endpoint != USB_EP_ALL) + { + if (direction == USB_XFER_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + } + usbd_otg->regs->endptflush = reg_mask; + + u32 retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptflush & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Wait for the endpoint to finish all transactions (buffer not ready). + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptstatus & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + // Wait for the endpoint to clear the primed status. + retries = 100000; // 200ms timeout. + while (usbd_otg->regs->endptprime & reg_mask) + { + retries--; + if (!retries) + return 3; + usleep(1); + } + + return 0; +} + +static void _usbd_mark_ep_complete(u32 endpoint) +{ + u32 complete_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + usbd_flush_endpoint(endpoint); + memset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4); + memset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t)); + usbdaemon->ep_configured[endpoint] = 0; + usbdaemon->ep_bytes_requested[endpoint] = 0; + + if (direction == USB_XFER_DIR_IN) + complete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + complete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + usbd_otg->regs->endptcomplete |= complete_bit; +} + +static usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint) +{ + //gfx_printf("_usbd_get_ep_status\n"); + bool status; + u32 reg_val; + u32 reg_mask; + u32 actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + if (direction == USB_XFER_DIR_IN) + reg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + else + reg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + if (actual_ep == USB_HW_EP1) + reg_val = usbd_otg->regs->endptctrl[1]; + else + reg_val = usbd_otg->regs->endptctrl[0]; + + // Check stalled status. + if (direction == USB_XFER_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL; + + if (status) + return USB_EP_STATUS_STALLED; + + // Check enabled status. + if (direction == USB_XFER_DIR_IN) + status = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE; + else + status = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE; + + if (!status) + return USB_EP_STATUS_DISABLED; + + // CHeck qHD error status. + u32 token_error_mask = USB_QHD_TOKEN_HALTED | USB_QHD_TOKEN_BUFFER_ERROR | USB_QHD_TOKEN_XFER_ERROR; + if (usbdaemon->qhs[endpoint].token & token_error_mask) + { + gfx_printf("token %d \n", usbdaemon->qhs[endpoint].token); + if (usbdaemon->qhs[endpoint].token & USB_QHD_TOKEN_HALTED) + { + gfx_printf("USB_QHD_TOKEN_HALTED\n"); + } + if (usbdaemon->qhs[endpoint].token & USB_QHD_TOKEN_BUFFER_ERROR) + { + gfx_printf("USB_QHD_TOKEN_BUFFER_ERROR\n"); + } + if (usbdaemon->qhs[endpoint].token & USB_QHD_TOKEN_XFER_ERROR) + { + gfx_printf("USB_QHD_TOKEN_XFER_ERROR\n"); + } + return USB_EP_STATUS_ERROR; + } + // Check if endpoint has a request or a ready buffer. + if ((usbd_otg->regs->endptprime & reg_mask) || (usbd_otg->regs->endptstatus & reg_mask)) + return USB_EP_STATUS_ACTIVE; // RX/TX active. + + // Return idle or not configured status. + if (!usbdaemon->ep_configured[endpoint]) + return USB_EP_STATUS_NO_CONFIG; + + return USB_EP_STATUS_IDLE; +} + +static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, bool sync) +{ + if (!buf) + len = 0; + + u32 prime_bit; + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + u32 length_left = len; + u32 dtd_ep_idx = endpoint * 4; + + _usbd_mark_ep_complete(endpoint); + + if (endpoint == USB_EP_CTRL_OUT) + usbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE; + + u32 max_packet_len = usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK; + usbdaemon->qhs[endpoint].ep_capabilities |= (max_packet_len << 16) | USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS; + usbdaemon->qhs[endpoint].next_dTD_ptr = 0; // Clear terminate bit. + //usbdaemon->qhs[endpoint].ep_capabilities |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + usbdaemon->ep_configured[endpoint] = 1; + usbdaemon->ep_bytes_requested[endpoint] = len; + + // Configure dTD. + u32 dtd_idx = 0; + do + { + if (dtd_idx) + usbdaemon->dtds[dtd_ep_idx + dtd_idx - 1].next_dTD = (u32)&usbdaemon->dtds[dtd_ep_idx + dtd_idx]; + + u32 dtd_size = MIN(length_left, USB_TD_BUFFER_MAX_SIZE); // 16KB max per dTD. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].info = (dtd_size << 16) | USB_QHD_TOKEN_ACTIVE; + // usbdaemon->dtds[dtd_ep_idx + dtd_idx].info |= USB_QHD_TOKEN_IRQ_ON_COMPLETE; + + // Set buffers addresses to all page pointers. + u32 dt_buffer_offset = dtd_idx * USB_TD_BUFFER_MAX_SIZE; + for (u32 i = 0; i < 4; i++) + usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = + (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * i)]; + + //usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[5] = + // (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * 4)]; // Last buffer. Unused. + + length_left -= dtd_size; + if (length_left) + dtd_idx++; + } + while (length_left); + + // Last dTD, terminate it. + usbdaemon->dtds[dtd_ep_idx + dtd_idx].next_dTD = 1; + + // Set first dTD address to queue head next dTD. + usbdaemon->qhs[endpoint].next_dTD_ptr |= (u32)&usbdaemon->dtds[dtd_ep_idx] & 0xFFFFFFE0; + + // Flush AHB prefetcher. + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE; + AHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |= MEM_PREFETCH_ENABLE; + + if (direction == USB_XFER_DIR_IN) + { + prime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep; + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + } + else + prime_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep; + + // Prime endpoint. + usbd_otg->regs->endptprime |= prime_bit; // USB2_CONTROLLER_USB2D_ENDPTPRIME. + + int res = 0; + usb_ep_status_t ep_status; + if (sync) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status == USB_EP_STATUS_ACTIVE) + { + u32 retries = 1000000; // Timeout 2s. + while (retries) + { + ep_status = _usbd_get_ep_status(endpoint); + if (ep_status != USB_EP_STATUS_ACTIVE) + { + if (ep_status == USB_EP_STATUS_DISABLED) + res = 28; + goto out; + } + retries--; + usleep(1); + } + res = 3; + } + else if (ep_status == USB_EP_STATUS_DISABLED) + res = 28; +out: + if (res) + _usbd_mark_ep_complete(endpoint); + else + { + usb_ep_status_t status = _usbd_get_ep_status(endpoint); + if (status != USB_EP_STATUS_IDLE) + { + //gfx_printf("status is %d\n", status); + res = 26; + } + } + } + + if (direction == USB_XFER_DIR_OUT) + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + return res; +} + +static int _usbd_ep_ack(usb_ep_t ep) +{ + return _usbd_ep_operation(ep, NULL, 0, true); +} + +static void _usbd_set_ep0_stall() +{ + // EP Control endpoints must be always stalled together. + usbd_otg->regs->endptctrl[0] = + USB2D_ENDPTCTRL_TX_EP_ENABLE | USB2D_ENDPTCTRL_TX_EP_STALL | + USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL; +} + +void usbd_set_ep_stall(u32 endpoint, int ep_stall) +{ + usb_hw_ep_t actual_ep = (endpoint & 2) >> 1; + usb_xfer_dir_t direction = endpoint & 1; + + if (ep_stall) + { + if (direction == USB_XFER_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT. + } + else + { + if (direction == USB_XFER_DIR_IN) + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN. + else + usbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT. + } +} + +static void _usbd_handle_get_class_request(bool *transmit_data, u8 *descriptor, int *size, int *ep_stall) +{ + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wLength = usbd_otg->control_setup.wLength; + + bool valid_interface = _wIndex == usbd_otg->interface; + bool valid_len = _bRequest == USB_REQUEST_BULK_GET_MAX_LUN ? 1 : 0; + + if (!valid_interface || _wValue != 0 || _wLength != valid_len) + { + *ep_stall = 1; + return; + } + + switch (_bRequest) + { + case USB_REQUEST_BULK_RESET: + _usbd_ep_ack(USB_EP_CTRL_IN); + usbd_otg->bulk_reset_req = 1; + break; // DELAYED_STATUS; + case USB_REQUEST_BULK_GET_MAX_LUN: + *transmit_data = 1; + descriptor[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported. + usbd_otg->max_lun_set = 1; + break; + default: + *ep_stall = 1; + break; + } +} + +static void _usbd_handle_get_descriptor(bool *transmit_data, void **descriptor, int *size, int *ep_stall) +{ + u8 descriptor_type = usbd_otg->control_setup.wValue >> 8; + u8 descriptor_subtype = usbd_otg->control_setup.wValue & 0xFF; + + switch (descriptor_type) + { + case USB_DESCRIPTOR_DEVICE: + { +/* + u32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV); + usb_device_descriptor.idProduct = (soc_rev >> 8) & 0xFF; // chip_id. + usb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM. + usb_device_descriptor.bcdDevice = (soc_rev >> 16) & 0xF; // MINORREV. + usb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV. +*/ + *descriptor = usbd_otg->desc->dev; + *size = usbd_otg->desc->dev->bLength; + *transmit_data = 1; + return; + } + case USB_DESCRIPTOR_CONFIGURATION: + if (usbd_otg->type == USB_GADGET_UMS) + { + if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x200; + } + else // Full speed. 64 bytes. + { + usbd_otg->desc->cfg->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg->endpoint[1].wMaxPacketSize = 0x40; + } + } + else + { + usb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_otg->desc->cfg; + if (usbd_otg->port_speed == 2) // High speed. 512 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x200; + tmp->endpoint[1].wMaxPacketSize = 0x200; + } + else // Full speed. 64 bytes. + { + tmp->endpoint[0].wMaxPacketSize = 0x40; + tmp->endpoint[1].wMaxPacketSize = 0x40; + } + } + *descriptor = usbd_otg->desc->cfg; + *size = usbd_otg->desc->cfg->config.wTotalLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_STRING: + switch (descriptor_subtype) + { + case 1: + *descriptor = usbd_otg->desc->vendor; + *size = usbd_otg->desc->vendor[0]; + break; + case 2: + *descriptor = usbd_otg->desc->product; + *size = usbd_otg->desc->product[0]; + break; + case 3: + *descriptor = usb_serial_string_descriptor; + *size = usb_serial_string_descriptor[0]; + break; + case 0xEE: + *descriptor = usbd_otg->desc->ms_os; + *size = usbd_otg->desc->ms_os->bLength; + break; + default: + *descriptor = usb_lang_id_string_descriptor; + *size = 4; + break; + } + *transmit_data = 1; + return; + case USB_DESCRIPTOR_DEVICE_QUALIFIER: + if (!usbd_otg->desc->dev_qual) + goto exit; + *descriptor = usbd_otg->desc->dev_qual; + *size = usbd_otg->desc->dev_qual->bLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + if (!usbd_otg->desc->cfg_other) + goto exit; + if (usbd_otg->port_speed == 2) + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x40; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x40; + } + else + { + usbd_otg->desc->cfg_other->endpoint[0].wMaxPacketSize = 0x200; + usbd_otg->desc->cfg_other->endpoint[1].wMaxPacketSize = 0x200; + } + if ((usbd_otg->charger_detect & 1) && (usbd_otg->charger_detect & 2)) + usbd_otg->desc->cfg_other->config.bMaxPower = 500 / 2; + *descriptor = usbd_otg->desc->cfg_other; + *size = usbd_otg->desc->cfg_other->config.wTotalLength; + *transmit_data = 1; + return; + case USB_DESCRIPTOR_DEVICE_BINARY_OBJECT: + *descriptor = usbd_otg->desc->dev_bot; + *size = usbd_otg->desc->dev_bot->wTotalLength; + *transmit_data = 1; + return; + default: + *transmit_data = 0; + *ep_stall = 1; + return; + } +exit: + *transmit_data = 0; + *ep_stall = 1; + return; +} + +static int _usbd_handle_set_request(int *ep_stall) +{ + int ret = 0; + u8 bRequest = usbd_otg->control_setup.bRequest; + if (bRequest == USB_REQUEST_SET_ADDRESS) + { + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + + // Set USB address for device mode. + if (!ret) + usbd_otg->regs->periodiclistbase = (usbd_otg->regs->periodiclistbase & 0x1FFFFFF) | ((usbd_otg->control_setup.wValue & 0xFF) << 25); + } + else if (bRequest == USB_REQUEST_SET_CONFIGURATION) + { + //gfx_printf("USB_REQUEST_SET_CONFIGURATION\n"); + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!ret) + { + usbd_otg->configuration = usbd_otg->control_setup.wValue; + _usbd_initialize_ep_ctrl(USB_EP_BULK_OUT); + _usbd_initialize_ep_ctrl(USB_EP_BULK_IN); + usbd_otg->configuration_set = 1; + } + } + else + *ep_stall = 1; + + return ret; +} + +static int _usbd_handle_ep0_control_transfer() +{ + int direction; + + int ret = 0; + bool transmit_data = 0; + u8 *descriptor = (u8 *)USB_DESCRIPTOR_ADDR; + int size = 0; + int ep_stall = 0; + + u8 _bmRequestType = usbd_otg->control_setup.bmRequestType; + u8 _bRequest = usbd_otg->control_setup.bRequest; + u16 _wValue = usbd_otg->control_setup.wValue; + u16 _wIndex = usbd_otg->control_setup.wIndex; + u16 _wLength = usbd_otg->control_setup.wLength; + + //gfx_printf("%02X %02X %04X %04X %04X\n", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength); + + switch (_bmRequestType) + { + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): + ret = _usbd_handle_set_request(&ep_stall); + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + if (!ret) + usbd_otg->interface = _wValue; + break; + + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + switch (_bRequest) + { + case USB_REQUEST_CLEAR_FEATURE: + case USB_REQUEST_SET_FEATURE: + if ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT) + { + switch (_wIndex) // endpoint + { + case USB_EP_ADDR_CTRL_OUT: + direction = 2; + break; + case USB_EP_ADDR_CTRL_IN: + direction = 3; + break; + case USB_EP_ADDR_BULK_OUT: + direction = 0; + break; + case USB_EP_ADDR_BULK_IN: + direction = 1; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + if (_bRequest == USB_REQUEST_CLEAR_FEATURE) + _usbd_stall_reset_ep1(direction, USB_EP_CFG_RESET); + else + _usbd_stall_reset_ep1(direction, USB_EP_CFG_STALL); + + ret = _usbd_ep_ack(USB_EP_CTRL_IN); + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + + break; + default: + ep_stall = 1; + break; + } + break; + case (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + break; + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_STANDARD): + switch (_bRequest) + { + case USB_REQUEST_GET_STATUS: + descriptor[0] = USB_STATUS_DEV_SELF_POWERED; + descriptor[1] = 0; // No support for remove wake up. + transmit_data = 1; + size = 2; + break; + case USB_REQUEST_GET_DESCRIPTOR: + _usbd_handle_get_descriptor(&transmit_data, (void **)&descriptor, &size, &ep_stall); + break; + case USB_REQUEST_GET_CONFIGURATION: + descriptor = (u8 *)&usbd_otg->configuration; + size = _wLength; + transmit_data = 1; + break; + default: + ep_stall = 1; + break; + } + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_STANDARD): + if (_bRequest == USB_REQUEST_GET_INTERFACE) + { + descriptor = (void *)&usbd_otg->interface; + } + else if (_bRequest == USB_REQUEST_GET_STATUS) + { + memset(descriptor, 0, _wLength); + } + else if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->type > USB_GADGET_UMS) + { + if (usbd_otg->type == USB_GADGET_HID_GAMEPAD) + { + descriptor = (u8 *)&hid_report_descriptor_jc; + _wLength = sizeof(hid_report_descriptor_jc); + } + else // USB_GADGET_HID_TOUCHPAD + { + descriptor = (u8 *)&hid_report_descriptor_touch; + _wLength = sizeof(hid_report_descriptor_touch); + } + + usbd_otg->hid_report_sent = 1; + } + else + { + ep_stall = 1; + break; + } + + size = _wLength; + transmit_data = 1; + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_ENDPOINT | USB_SETUP_TYPE_STANDARD): + if (_bRequest == USB_REQUEST_GET_STATUS) + { + int ep_req; + switch (_wIndex) + { + case 0: + ep_req = 0; + break; + case 1: + ep_req = 2; + break; + case 0x80: + ep_req = 1; + break; + case 0x81: + ep_req = 3; + break; + default: + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + goto out; + } + + size = _wLength; + memset(descriptor, 0, size); + + if (_usbd_get_ep_status(ep_req) == USB_EP_STATUS_STALLED) + descriptor[0] = USB_STATUS_EP_HALTED; + else + descriptor[0] = USB_STATUS_EP_OK; + + transmit_data = 1; + } + else + _usbd_stall_reset_ep1(3, USB_EP_CFG_STALL); + break; + + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS): + memset(descriptor, 0, _wLength); + + _usbd_handle_get_class_request(&transmit_data, descriptor, &size, &ep_stall); + size = _wLength; + break; + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR): + case (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR): + if (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR) + { + switch (_wIndex) + { + case USB_DESCRIPTOR_MS_COMPAT_ID: + descriptor = (u8 *)usbd_otg->desc->ms_cid; + size = usbd_otg->desc->ms_cid->dLength; + transmit_data = 1; + break; + case USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES: + descriptor = (u8 *)usbd_otg->desc->mx_ext; + size = usbd_otg->desc->mx_ext->dLength; + transmit_data = 1; + break; + default: + ep_stall = 1; + break; + } + } + else + ep_stall = 1; + break; + + default: + ep_stall = 1; + break; + } + + // Transmit data to HOST if any. + if (transmit_data) + { + memcpy(usb_ep0_ctrl_buf, descriptor, size); + + if (_wLength < size) + size = _wLength; + ret = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, true); + if (!ret) + ret = _usbd_ep_ack(USB_EP_CTRL_OUT); + } + +out: + if (ep_stall) + _usbd_set_ep0_stall(); + + //gfx_printf("ret is %d\n", ret); + + return ret; +} + +static int _usbd_ep0_initialize() +{ + bool enter = false; + if (usbd_otg->configuration_set) + enter = true; + else + { + usbdaemon->qhs = (volatile dQH_t *)USB2_QH_USB2D_QH_EP_BASE; + + if (!_usbd_initialize_ep0()) + enter = true; + } + + if (enter) + { + usbd_otg->configuration_set = 0; + usbd_otg->max_lun_set = 0; + + // Timeout if cable or communication isn't started in 1.5 minutes. + u32 timer = get_tmr_ms() + 90000; + while (true) + { + u32 usb_status_irqs = usbd_otg->regs->usbsts; + + // Clear all interrupt statuses. + usbd_otg->regs->usbsts = usb_status_irqs; + + // Check if a reset was received. + if (usb_status_irqs & USB2D_USBSTS_URI) + { + //_disable_usb_wdt4(); + + // Clear all device addresses, enabled setup requests, transmit events and flush all endpoints. + usbd_otg->regs->periodiclistbase = 0; + usbd_otg->regs->endptsetupstat = usbd_otg->regs->endptsetupstat; + usbd_otg->regs->endptcomplete = usbd_otg->regs->endptcomplete; + usbd_flush_endpoint(USB_EP_ALL); + } + + // Check if port change happened. + if (usb_status_irqs & USB2D_USBSTS_PCI) + usbd_otg->port_speed = (usbd_otg->regs->hostpc1_devlc & USB2D_HOSTPC1_DEVLC_PSPD_MASK) >> 25; + + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + //gfx_printf("ep0_setup_req %u\n", ep0_setup_req); + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + if (_usbd_handle_ep0_control_transfer()) + break; + } + if (usbd_otg->configuration_set) + return 0; + + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return 2; + } + } + + return 3; +} + +int usb_device_ep0_initialize(usb_gadget_type type) +{ + switch (type) + { + case USB_GADGET_UMS: + usbd_otg->desc = &usb_gadget_ums_descriptors; + break; + case USB_GADGET_HID_GAMEPAD: + usbd_otg->desc = &usb_gadget_hid_jc_descriptors; + break; + case USB_GADGET_HID_TOUCHPAD: + usbd_otg->desc = &usb_gadget_hid_touch_descriptors; + break; + } + + usbd_otg->type = type; + + int result = _usbd_ep0_initialize(); + + gfx_printf("_usbd_ep0_initialize %d\n", result); + + if (result) + result = 8; + return result; +} + +int usbd_handle_ep0_pending_control_transfer() +{ + // Acknowledge setup request for EP0 and copy its configuration. + u32 ep0_setup_req = usbd_otg->regs->endptsetupstat; + if (ep0_setup_req & 1) + { + usbd_otg->regs->endptsetupstat = ep0_setup_req; + memcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8); + _usbd_handle_ep0_control_transfer(); + memset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE); + } + + if (usbd_otg->bulk_reset_req) + { + usbd_otg->bulk_reset_req = 0; + return 1; + } + + return 0; +} + +static usb_ep_status_t _usbd_get_ep1_status(usb_xfer_dir_t dir) +{ + usb_ep_t ep; + if (dir == USB_XFER_DIR_OUT) + ep = USB_EP_BULK_OUT; + else + ep = USB_EP_BULK_IN; + return _usbd_get_ep_status(ep); +} + +int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int result = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync); + + if (sync && bytes_read) + { + if (result) + *bytes_read = 0; + else + *bytes_read = len; + } + + return result; +} + +int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read) +{ + if (len > USB_EP_BULK_OUT_MAX_XFER) + len = USB_EP_BULK_OUT_MAX_XFER; + + int result; + u32 bytes = 0; + *bytes_read = 0; + u8 *buf_curr = buf; + + while (len) + { + u32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE); + + result = usb_device_read_ep1_out(buf_curr, len_ep, &bytes, true); + if (!result) + { + len -= len_ep; + buf_curr += len_ep; + *bytes_read = *bytes_read + bytes; + } + else + break; + } + + return result; +} + +static int _usbd_get_ep1_out_bytes_read() +{ + if (_usbd_get_ep_status(2) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[2] - (usbdaemon->qhs[2].token >> 16)); +} + +int usb_device_ep1_out_reading_finish(u32 *pending_bytes) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_XFER_DIR_OUT); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_pending_control_transfer(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_out_bytes_read(); + + if (ep_status == USB_EP_STATUS_IDLE) + return 0; + else if (ep_status == USB_EP_STATUS_DISABLED) + return 28; + else + return 26; +} + +int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync) +{ + if (len > USB_EP_BUFFER_MAX_SIZE) + len = USB_EP_BUFFER_MAX_SIZE; + + int result = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync); + + if (sync && bytes_written) + { + if (result) + *bytes_written = 0; + else + *bytes_written = len; + } + + return result; +} + +static int _usbd_get_ep1_in_bytes_written() +{ + if (_usbd_get_ep_status(3) != USB_EP_STATUS_IDLE) + return 0; + else + return (usbdaemon->ep_bytes_requested[3] - (usbdaemon->qhs[3].token >> 16)); +} + +int usb_device_ep1_in_writing_finish(u32 *pending_bytes) +{ + usb_ep_status_t ep_status; + do + { + ep_status = _usbd_get_ep1_status(USB_XFER_DIR_IN); + if ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED)) + break; + + usbd_handle_ep0_pending_control_transfer(); + } + while ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED)); + + *pending_bytes = _usbd_get_ep1_in_bytes_written(); + + if (ep_status == USB_EP_STATUS_IDLE) + return 0; + else if (ep_status == USB_EP_STATUS_DISABLED) + return 28; + + usb_device_stall_ep1_bulk_out(); + return 26; +} + +bool usb_device_get_suspended() +{ + u32 suspended = usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP; + return (suspended ? true : false); +} + +u32 usb_device_get_port_status() +{ + return (usbd_otg->regs->portsc1); +} + +bool usb_device_get_max_lun(u8 max_lun) +{ + // Timeout if get MAX_LUN request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + usbd_otg->max_lun = max_lun; + + while (!usbd_otg->max_lun_set) + { + usbd_handle_ep0_pending_control_transfer(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + return false; +} + +bool usb_device_get_hid_report() +{ + // Timeout if get GET_HID_REPORT request doesn't happen in 10s. + u32 timer = get_tmr_ms() + 10000; + + while (!usbd_otg->hid_report_sent) + { + usbd_handle_ep0_pending_control_transfer(); + if (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN)) + return true; + } + + return false; +} diff --git a/ariane/src/bdk/usb/usbd.h b/ariane/src/bdk/usb/usbd.h new file mode 100644 index 0000000..82a73e2 --- /dev/null +++ b/ariane/src/bdk/usb/usbd.h @@ -0,0 +1,86 @@ +/* + * USB Device driver for Tegra X1 + * + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _USB_H_ +#define _USB_H_ + +#include + +#define USB_TD_BUFFER_PAGE_SIZE 0x1000 +#define USB_TD_BUFFER_MAX_SIZE (USB_TD_BUFFER_PAGE_SIZE * 4) +//#define USB_HW_BUFFER_5_PAGES 0x5000 +#define USB_EP_BUFFER_1_TD (USB_TD_BUFFER_MAX_SIZE) +#define USB_EP_BUFFER_2_TD (USB_TD_BUFFER_MAX_SIZE * 2) +#define USB_EP_BUFFER_4_TD (USB_TD_BUFFER_MAX_SIZE * 4) +#define USB_EP_BUFFER_MAX_SIZE (USB_EP_BUFFER_4_TD) + +typedef struct _usb_ctxt_t +{ + u32 type; + u32 partition; + u32 offset; + u32 sectors; + u32 ro; + void (*system_maintenance)(bool); + void *label; + void (*set_text)(void *, const char *); +} usb_ctxt_t; + +typedef enum _usb_hid_type +{ + USB_HID_GAMEPAD, + USB_HID_TOUCHPAD +} usb_hid_type; + +typedef enum _usb_gadget_type +{ + USB_GADGET_UMS, + USB_GADGET_HID_GAMEPAD, + USB_GADGET_HID_TOUCHPAD +} usb_gadget_type; + +typedef enum +{ + USB_EP_CTRL_OUT = 0, // EP0. + USB_EP_CTRL_IN = 1, // EP0. + USB_EP_BULK_OUT = 2, // EP1. + USB_EP_BULK_IN = 3, // EP1. + USB_EP_ALL = 0xFFFFFFFF +} usb_ep_t; + +int usbd_flush_endpoint(u32 ep); +void usbd_set_ep_stall(u32 endpoint, int ep_stall); +int usbd_get_max_pkt_length(int endpoint); +int usbd_handle_ep0_pending_control_transfer(); +void usbd_end(bool reset_ep, bool only_controller); +int usb_device_init(); +int usb_device_ep0_initialize(usb_gadget_type type); +int usb_device_read_ep1_out(u8 *buf, u32 len, u32 *bytes_read, bool sync); +int usb_device_read_ep1_out_big_reads(u8 *buf, u32 len, u32 *bytes_read); +int usb_device_ep1_out_reading_finish(u32 *pending_bytes); +int usb_device_write_ep1_in(u8 *buf, u32 len, u32 *bytes_written, bool sync); +int usb_device_ep1_in_writing_finish(u32 *pending_bytes); +bool usb_device_get_suspended(); + +int usb_device_gadget_ums(usb_ctxt_t *usbs); +int usb_device_gadget_hid(usb_ctxt_t *usbs); +bool usb_device_get_max_lun(u8 max_lun); +bool usb_device_get_hid_report(); +u32 usb_device_get_port_status(); + +#endif \ No newline at end of file diff --git a/ariane/src/bdk/utils/aarch64_util.h b/ariane/src/bdk/utils/aarch64_util.h new file mode 100644 index 0000000..456bfc8 --- /dev/null +++ b/ariane/src/bdk/utils/aarch64_util.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ARM64_H_ +#define _ARM64_H_ + +#include + +#define LSL0 0 +#define LSL16 16 +#define LSL32 32 + +#define _PAGEOFF(x) ((x) & 0xFFFFF000) + +#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F)) +#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _NOP() 0xD503201F + +#endif diff --git a/ariane/src/bdk/utils/btn.c b/ariane/src/bdk/utils/btn.c new file mode 100644 index 0000000..9ffe275 --- /dev/null +++ b/ariane/src/bdk/utils/btn.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "btn.h" +#include +#include +#include +#include +#include + +u8 btn_read() +{ + u8 res = 0; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) + res |= BTN_VOL_DOWN; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) + res |= BTN_VOL_UP; + if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) + res |= BTN_POWER; + return res; +} + +u8 btn_read_vol() +{ + u8 res = 0; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) + res |= BTN_VOL_DOWN; + if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) + res |= BTN_VOL_UP; + return res; +} + +u8 btn_wait() +{ + u8 res = 0, btn = btn_read(); + bool pwr = false; + + //Power button down, raise a filter. + if (btn & BTN_POWER) + { + pwr = true; + btn &= ~BTN_POWER; + } + + do + { + res = btn_read(); + //Power button up, remove filter. + if (!(res & BTN_POWER) && pwr) + pwr = false; + else if (pwr) //Power button still down. + res &= ~BTN_POWER; + } while (btn == res); + + return res; +} + +u8 btn_wait_timeout(u32 time_ms, u8 mask) +{ + u32 timeout = get_tmr_ms() + time_ms; + u8 res = btn_read() & mask; + + while (get_tmr_ms() < timeout) + { + if (res == mask) + break; + else + res = btn_read() & mask; + }; + + return res; +} + +u8 btn_wait_timeout_single(u32 time_ms, u8 mask) +{ + u8 single_button = mask & BTN_SINGLE; + mask &= ~BTN_SINGLE; + + u32 timeout = get_tmr_ms() + time_ms; + u8 res = btn_read(); + + while (get_tmr_ms() < timeout) + { + if ((res & mask) == mask) + { + if (single_button && (res & ~mask)) // Undesired button detected. + res = btn_read(); + else + return (res & mask); + } + else + res = btn_read(); + }; + + // Timed out. + if (!single_button || !time_ms) + return (res & mask); + else + return 0; // Return no button press if single button requested. +} diff --git a/ariane/src/bdk/utils/btn.h b/ariane/src/bdk/utils/btn.h new file mode 100644 index 0000000..f284748 --- /dev/null +++ b/ariane/src/bdk/utils/btn.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _BTN_H_ +#define _BTN_H_ + +#include + +#define BTN_POWER (1 << 0) +#define BTN_VOL_DOWN (1 << 1) +#define BTN_VOL_UP (1 << 2) +#define BTN_SINGLE (1 << 7) + +u8 btn_read(); +u8 btn_read_vol(); +u8 btn_wait(); +u8 btn_wait_timeout(u32 time_ms, u8 mask); +u8 btn_wait_timeout_single(u32 time_ms, u8 mask); + +#endif diff --git a/ariane/src/bdk/utils/dirlist.c b/ariane/src/bdk/utils/dirlist.c new file mode 100644 index 0000000..5732683 --- /dev/null +++ b/ariane/src/bdk/utils/dirlist.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include + +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs) +{ + u8 max_entries = 61; + + int res = 0; + u32 i = 0, j = 0, k = 0; + DIR dir; + FILINFO fno; + + char *dir_entries = (char *)calloc(max_entries, 256); + char *temp = (char *)calloc(1, 256); + + if (!pattern && !f_opendir(&dir, directory)) + { + for (;;) + { + res = f_readdir(&dir, &fno); + if (res || !fno.fname[0]) + break; + + bool curr_parse = parse_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR); + + if (curr_parse) + { + if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + strcpy(dir_entries + (k * 256), fno.fname); + k++; + if (k > (max_entries - 1)) + break; + } + } + } + f_closedir(&dir); + } + else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0]) + { + do + { + if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + strcpy(dir_entries + (k * 256), fno.fname); + k++; + if (k > (max_entries - 1)) + break; + } + res = f_findnext(&dir, &fno); + } while (fno.fname[0] && !res); + f_closedir(&dir); + } + + if (!k) + { + free(temp); + free(dir_entries); + + return NULL; + } + + // Reorder ini files by ASCII ordering. + for (i = 0; i < k - 1 ; i++) + { + for (j = i + 1; j < k; j++) + { + if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + { + strcpy(temp, &dir_entries[i * 256]); + strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); + strcpy(&dir_entries[j * 256], temp); + } + } + } + + free(temp); + + return dir_entries; +} diff --git a/ariane/src/bdk/utils/dirlist.h b/ariane/src/bdk/utils/dirlist.h new file mode 100644 index 0000000..32197f3 --- /dev/null +++ b/ariane/src/bdk/utils/dirlist.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs); diff --git a/ariane/src/bdk/utils/ini.c b/ariane/src/bdk/utils/ini.c new file mode 100644 index 0000000..538435e --- /dev/null +++ b/ariane/src/bdk/utils/ini.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ini.h" +#include +#include +#include + +static char *_strdup(char *str) +{ + if (!str) + return NULL; + + // Remove starting space. + if (str[0] == ' ' && strlen(str)) + str++; + + char *res = (char *)malloc(strlen(str) + 1); + strcpy(res, str); + + // Remove trailing space. + if (strlen(res) && res[strlen(res) - 1] == ' ') + res[strlen(res) - 1] = 0; + + return res; +} + +u32 _find_section_name(char *lbuf, u32 lblen, char schar) +{ + u32 i; + // Depends on 'FF_USE_STRFUNC 2' that removes \r. + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++) + ; + lbuf[i] = 0; + + return i; +} + +ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) +{ + if (csec) + list_append(dst, &csec->link); + + csec = (ini_sec_t *)calloc(sizeof(ini_sec_t), 1); + csec->name = _strdup(name); + csec->type = type; + + return csec; +} + +int ini_parse(link_t *dst, char *ini_path, bool is_dir) +{ + u32 lblen; + u32 pathlen = strlen(ini_path); + u32 k = 0; + char lbuf[512]; + char *filelist = NULL; + FIL fp; + ini_sec_t *csec = NULL; + + char *filename = (char *)malloc(256); + + strcpy(filename, ini_path); + + // Get all ini filenames. + if (is_dir) + { + filelist = dirlist(filename, "*.ini", false, false); + if (!filelist) + { + free(filename); + return 0; + } + strcpy(filename + pathlen, "/"); + pathlen++; + } + + do + { + // Copy ini filename in path string. + if (is_dir) + { + if (filelist[k * 256]) + { + strcpy(filename + pathlen, &filelist[k * 256]); + k++; + } + else + break; + } + + // Open ini. + if (f_open(&fp, filename, FA_READ) != FR_OK) + { + free(filelist); + free(filename); + + return 0; + } + + do + { + // Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. + if (lblen && lbuf[lblen - 1] == '\n') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') // Create new section. + { + _find_section_name(lbuf, lblen, ']'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); + list_init(&csec->kvs); + } + else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'. + { + _find_section_name(lbuf, lblen, '}'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); + csec->color = 0xFF0AB9E6; + } + else if (lblen > 2 && lbuf[0] == '#') // Create comment. + { + csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); + } + else if (lblen < 2) // Create empty line. + { + csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); + } + else if (csec && csec->type == INI_CHOICE) // Extract key/value. + { + u32 i = _find_section_name(lbuf, lblen, '='); + + ini_kv_t *kv = (ini_kv_t *)calloc(sizeof(ini_kv_t), 1); + kv->key = _strdup(&lbuf[0]); + kv->val = _strdup(&lbuf[i + 1]); + list_append(&csec->kvs, &kv->link); + } + } while (!f_eof(&fp)); + + f_close(&fp); + + if (csec) + { + list_append(dst, &csec->link); + if (is_dir) + csec = NULL; + } + } while (is_dir); + + free(filename); + free(filelist); + + return 1; +} + +char *ini_check_payload_section(ini_sec_t *cfg) +{ + if (cfg == NULL) + return NULL; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) + { + if (!strcmp("payload", kv->key)) + return kv->val; + } + + return NULL; +} diff --git a/ariane/src/bdk/utils/ini.h b/ariane/src/bdk/utils/ini.h new file mode 100644 index 0000000..571d19d --- /dev/null +++ b/ariane/src/bdk/utils/ini.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _INI_H_ +#define _INI_H_ + +#include +#include + +#define INI_CHOICE 3 +#define INI_CAPTION 5 +#define INI_CHGLINE 6 +#define INI_NEWLINE 0xFE +#define INI_COMMENT 0xFF + +typedef struct _ini_kv_t +{ + char *key; + char *val; + link_t link; +} ini_kv_t; + +typedef struct _ini_sec_t +{ + char *name; + link_t kvs; + link_t link; + u32 type; + u32 color; +} ini_sec_t; + +int ini_parse(link_t *dst, char *ini_path, bool is_dir); +char *ini_check_payload_section(ini_sec_t *cfg); + +#endif + diff --git a/ariane/src/bdk/utils/list.h b/ariane/src/bdk/utils/list.h new file mode 100644 index 0000000..ece5402 --- /dev/null +++ b/ariane/src/bdk/utils/list.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _LIST_H_ +#define _LIST_H_ + +#include + +/*! Initialize list. */ +#define LIST_INIT(name) link_t name = {&name, &name} + +/*! Initialize static list. */ +#define LIST_INIT_STATIC(name) static link_t name = {&name, &name} + +/*! Iterate over all list links. */ +#define LIST_FOREACH(iter, list) \ + for(link_t *iter = (list)->next; iter != (list); iter = iter->next) + +/*! Safely iterate over all list links. */ +#define LIST_FOREACH_SAFE(iter, list) \ + for(link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next) + +/*! Iterate over all list members and make sure that the list has at least one entry. */ +#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ + if ((list)->next != (list)) \ + for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + +typedef struct _link_t +{ + struct _link_t *prev; + struct _link_t *next; +} link_t; + +static inline void link_init(link_t *l) +{ + l->prev = NULL; + l->next = NULL; +} + +static inline int link_used(link_t *l) +{ + if(l->next == NULL) + return 1; + return 0; +} + +static inline void list_init(link_t *lh) +{ + lh->prev = lh; + lh->next = lh; +} + +static inline void list_prepend(link_t *lh, link_t *l) +{ + l->next = lh->next; + l->prev = lh; + lh->next->prev = l; + lh->next = l; +} + +static inline void list_append(link_t *lh, link_t *l) +{ + l->prev = lh->prev; + l->next = lh; + lh->prev->next = l; + lh->prev = l; +} + +static inline void list_remove(link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; + link_init(l); +} + +static inline int list_empty(link_t *lh) +{ + if(lh->next == lh) + return 1; + return 0; +} + +#endif diff --git a/ariane/src/bdk/utils/sprintf.c b/ariane/src/bdk/utils/sprintf.c new file mode 100644 index 0000000..a35234b --- /dev/null +++ b/ariane/src/bdk/utils/sprintf.c @@ -0,0 +1,149 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2019-2020 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include + +#include + +char **sout_buf; + +static void _s_putc(char c) +{ + **sout_buf = c; + *sout_buf += 1; +} + +static void _s_puts(char *s) +{ + for (; *s; s++) + _s_putc(*s); +} + +static void _s_putn(u32 v, int base, char fill, int fcnt) +{ + char buf[65]; + static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return; + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) + { + while (c > 0) + { + *--p = fill; + c--; + } + } + + _s_puts(p); +} + +static void _s_putp(u32 *v, int base, char fill, int fcnt) +{ + _s_putn(*v, base, fill, fcnt); +} + +void s_printf(char *out_buf, const char *fmt, ...) +{ + va_list ap; + int fill, fcnt; + + sout_buf = &out_buf; + + va_start(ap, fmt); + while(*fmt) + { + if(*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') + { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } + else + { + fill = ' '; + fcnt -= '0'; + } + } + switch(*fmt) + { + case 'c': + _s_putc(va_arg(ap, u32)); + break; + case 's': + _s_puts(va_arg(ap, char *)); + break; + case 'd': + _s_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + _s_putp(va_arg(ap, u32*), 16, fill, fcnt); + break; + case 'x': + case 'X': + _s_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + case 'k': + //gfx_con.fgcol = va_arg(ap, u32); + break; + case 'K': + //gfx_con.bgcol = va_arg(ap, u32); + //gfx_con.fillbg = 1; + break; + case '%': + _s_putc('%'); + break; + case '\0': + goto out; + default: + _s_putc('%'); + _s_putc(*fmt); + break; + } + } + else + _s_putc(*fmt); + fmt++; + } + +out: + **sout_buf = '\0'; + va_end(ap); +} \ No newline at end of file diff --git a/ariane/src/hwinit/tsec.h b/ariane/src/bdk/utils/sprintf.h similarity index 79% rename from ariane/src/hwinit/tsec.h rename to ariane/src/bdk/utils/sprintf.h index 7aa112c..845f9b7 100644 --- a/ariane/src/hwinit/tsec.h +++ b/ariane/src/bdk/utils/sprintf.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018 naehrwert +* Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,11 +14,11 @@ * along with this program. If not, see . */ -#ifndef _TSEC_H_ -#define _TSEC_H_ +#ifndef _SPRINTF_H_ +#define _SPRINTF_H_ -#include "types.h" +#include -int tsec_query(u32 carveout, u8 *dst, u32 rev); +void s_printf(char *out_buf, const char *fmt, ...); -#endif +#endif \ No newline at end of file diff --git a/ariane/src/minerva_tc/mtc/types.h b/ariane/src/bdk/utils/types.h similarity index 53% rename from ariane/src/minerva_tc/mtc/types.h rename to ariane/src/bdk/utils/types.h index 9a4d414..00af900 100644 --- a/ariane/src/minerva_tc/mtc/types.h +++ b/ariane/src/bdk/utils/types.h @@ -20,13 +20,14 @@ #define NULL ((void *)0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) -typedef char s8; +typedef signed char s8; typedef short s16; typedef short SHORT; typedef int s32; @@ -51,4 +52,64 @@ typedef int bool; #define true 1 #define false 0 +#define BOOT_CFG_AUTOBOOT_EN (1 << 0) +#define BOOT_CFG_FROM_LAUNCH (1 << 1) +#define BOOT_CFG_FROM_ID (1 << 2) +#define BOOT_CFG_TO_EMUMMC (1 << 3) +#define BOOT_CFG_SEPT_RUN (1 << 7) + +#define EXTRA_CFG_KEYS (1 << 0) +#define EXTRA_CFG_PAYLOAD (1 << 1) +#define EXTRA_CFG_MODULE (1 << 2) + +#define EXTRA_CFG_NYX_BIS (1 << 4) +#define EXTRA_CFG_NYX_UMS (1 << 5) +#define EXTRA_CFG_NYX_RELOAD (1 << 6) +#define EXTRA_CFG_NYX_DUMP (1 << 7) + +typedef enum _nyx_ums_type +{ + NYX_UMS_SD_CARD = 0, + NYX_UMS_EMMC_BOOT0, + NYX_UMS_EMMC_BOOT1, + NYX_UMS_EMMC_GPP, + NYX_UMS_EMUMMC_BOOT0, + NYX_UMS_EMUMMC_BOOT1, + NYX_UMS_EMUMMC_GPP +} nyx_ums_type; + +typedef struct __attribute__((__packed__)) _boot_cfg_t +{ + u8 boot_cfg; + u8 autoboot; + u8 autoboot_list; + u8 extra_cfg; + union + { + struct + { + char id[8]; // 7 char ASCII null teminated. + char emummc_path[0x78]; // emuMMC/XXX, ASCII null teminated. + }; + u8 ums; // nyx_ums_type. + u8 xt_str[0x80]; + }; +} boot_cfg_t; + +typedef struct __attribute__((__packed__)) _ipl_ver_meta_t +{ + u32 magic; + u32 version; + u16 rsvd0; + u16 rsvd1; +} ipl_ver_meta_t; + +typedef struct __attribute__((__packed__)) _reloc_meta_t +{ + u32 start; + u32 stack; + u32 end; + u32 ep; +} reloc_meta_t; + #endif diff --git a/ariane/src/bdk/utils/util.c b/ariane/src/bdk/utils/util.c new file mode 100644 index 0000000..dd10781 --- /dev/null +++ b/ariane/src/bdk/utils/util.c @@ -0,0 +1,167 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (c) 2018 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USE_RTC_TIMER + +extern volatile nyx_storage_t *nyx_str; + +u32 get_tmr_s() +{ + return RTC(APBDEV_RTC_SECONDS); +} + +u32 get_tmr_ms() +{ + // The registers must be read with the following order: + // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) + return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); +} + +u32 get_tmr_us() +{ + return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US +} + +void msleep(u32 ms) +{ +#ifdef USE_RTC_TIMER + u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) + ; +#else + bpmp_msleep(ms); +#endif +} + +void usleep(u32 us) +{ +#ifdef USE_RTC_TIMER + u32 start = TMR(TIMERUS_CNTR_1US); + + // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. + if ((start + us) < start) + bpmp_usleep(us); + else + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! + ; +#else + bpmp_usleep(us); +#endif +} + +void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) +{ + for(u32 i = 0; i < num_ops; i++) + base[ops[i].off] = ops[i].val; +} + +u32 crc32_calc(u32 crc, const u8 *buf, u32 len) +{ + const u8 *p, *q; + static u32 *table = NULL; + + // Calculate CRC table. + if (!table) + { + table = calloc(256, sizeof(u32)); + for (u32 i = 0; i < 256; i++) + { + u32 rem = i; + for (u32 j = 0; j < 8; j++) + { + if (rem & 1) + { + rem >>= 1; + rem ^= 0xedb88320; + } + else + rem >>= 1; + } + table[i] = rem; + } + } + + crc = ~crc; + q = buf + len; + for (p = buf; p < q; p++) + { + u8 oct = *p; + crc = (crc >> 8) ^ table[(crc & 0xff) ^ oct]; + } + + return ~crc; +} + +void panic(u32 val) +{ + // Set panic code. + PMC(APBDEV_PMC_SCRATCH200) = val; + //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE; + TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN; + TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; + TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; + TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; + + while (true) + usleep(1); +} + +void reboot_normal() +{ + sd_end(); + reconfig_hw_workaround(false, 0); + + panic(0x21); // Bypass fuse programming in package1. +} + +void reboot_rcm() +{ + sd_end(); + reconfig_hw_workaround(false, 0); + + PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; + PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; + + while (true) + bpmp_halt(); +} + +void power_off() +{ + sd_end(); + reconfig_hw_workaround(false, 0); + + // Stop the alarm, in case we injected and powered off too fast. + max77620_rtc_stop_alarm(); + + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + + while (true) + bpmp_halt(); +} diff --git a/ariane/src/bdk/utils/util.h b/ariane/src/bdk/utils/util.h new file mode 100644 index 0000000..948e02c --- /dev/null +++ b/ariane/src/bdk/utils/util.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include +#include + +typedef enum +{ + NYX_CFG_BIS = (1 << 5), + NYX_CFG_UMS = (1 << 6), + NYX_CFG_DUMP = (1 << 7), +} nyx_cfg_t; + +typedef enum +{ + ERR_LIBSYS_LP0 = (1 << 0), + ERR_SYSOLD_NYX = (1 << 1), + ERR_SYSOLD_MTC = (1 << 2), + ERR_EXCEPT_ENB = (1 << 31), +} hekate_errors_t; + +#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ + ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) + +typedef struct _cfg_op_t +{ + u32 off; + u32 val; +} cfg_op_t; + +typedef struct _nyx_info_t +{ + u32 disp_id; + u32 errors; +} nyx_info_t; + +typedef struct _nyx_storage_t +{ + u32 version; + u32 cfg; + u8 irama[0x8000]; + u8 hekate[0x30000]; + u8 rsvd[0x800000 - sizeof(nyx_info_t)]; + nyx_info_t info; + mtc_config_t mtc_cfg; + emc_table_t mtc_table[10]; +} nyx_storage_t; + +u32 get_tmr_us(); +u32 get_tmr_ms(); +u32 get_tmr_s(); +void usleep(u32 us); +void msleep(u32 ms); +void panic(u32 val); +void reboot_normal(); +void reboot_rcm(); +void power_off(); +void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); +u32 crc32_calc(u32 crc, const u8 *buf, u32 len); + +#endif diff --git a/ariane/src/cbmem.c b/ariane/src/cbmem.c deleted file mode 100644 index 38768c1..0000000 --- a/ariane/src/cbmem.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "cbmem.h" -#include "hwinit/carveout.h" -#include "lib/printk.h" -#include -#include - -#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647 -typedef int ssize_t; -#else -typedef long ssize_t; -#endif - -void *cbmem_top(void) -{ - static uintptr_t addr; - - if (addr == 0) { - uintptr_t begin_mib; - uintptr_t end_mib; - - memory_in_range_below_4gb(&begin_mib, &end_mib); - /* Make sure we consume everything up to 4GIB. */ - if (end_mib == 4096) - addr = ~(uint32_t)0; - else - addr = end_mib << 20; - } - - return (void *)addr; -} - -void cbmem_initialize_empty(void) -{ - cbmem_initialize_empty_id_size(0, 0); -} - -/* - * The struct imd is a handle for working with an in-memory directory. - * - * NOTE: Do not directly touch any fields within this structure. An imd pointer - * is meant to be opaque, but the fields are exposed for stack allocation. - */ -struct imdr { - uintptr_t limit; - void *r; -}; -struct imd { - struct imdr lg; - struct imdr sm; -}; - -static const uint32_t IMD_ROOT_PTR_MAGIC = 0xc0389481; -static const uint32_t IMD_ENTRY_MAGIC = ~0xc0389481; -static const uint32_t SMALL_REGION_ID = CBMEM_ID_IMD_SMALL; -static const size_t LIMIT_ALIGN = 4096; - -static void imdr_init(struct imdr *ir, void *upper_limit) -{ - uintptr_t limit = (uintptr_t)upper_limit; - /* Upper limit is aligned down to 4KiB */ - ir->limit = ALIGN_DOWN(limit, LIMIT_ALIGN); - ir->r = NULL; -} - -/* Initialize imd handle. */ -static void imd_handle_init(struct imd *imd, void *upper_limit) -{ - imdr_init(&imd->lg, upper_limit); - imdr_init(&imd->sm, NULL); -} - -/* In-memory data structures. */ -struct imd_root_pointer { - uint32_t magic; - /* Relative to upper limit/offset. */ - int32_t root_offset; -} __packed; - -struct imd_entry { - uint32_t magic; - /* start is located relative to imd_root */ - int32_t start_offset; - uint32_t size; - uint32_t id; -} __packed; - -struct imd_root { - uint32_t max_entries; - uint32_t num_entries; - uint32_t flags; - uint32_t entry_align; - /* Used for fixing the size of an imd. Relative to the root. */ - int32_t max_offset; - struct imd_entry entries[0]; -} __packed; - -#define IMD_FLAG_LOCKED 1 - -static void imd_entry_assign(struct imd_entry *e, uint32_t id, - ssize_t offset, size_t size) -{ - e->magic = IMD_ENTRY_MAGIC; - e->start_offset = offset; - e->size = size; - e->id = id; -} - -static void *relative_pointer(void *base, ssize_t offset) -{ - intptr_t b = (intptr_t)base; - b += offset; - return (void *)b; -} - -static struct imd_root *imdr_root(const struct imdr *imdr) -{ - return imdr->r; -} - -/* - * The root pointer is relative to the upper limit of the imd. i.e. It sits - * just below the upper limit. - */ -static struct imd_root_pointer *imdr_get_root_pointer(const struct imdr *imdr) -{ - struct imd_root_pointer *rp; - - rp = relative_pointer((void *)imdr->limit, -sizeof(*rp)); - - return rp; -} - -static void imd_link_root(struct imd_root_pointer *rp, struct imd_root *r) -{ - rp->magic = IMD_ROOT_PTR_MAGIC; - rp->root_offset = (int32_t)((intptr_t)r - (intptr_t)rp); -} - -static struct imd_entry *root_last_entry(struct imd_root *r) -{ - return &r->entries[r->num_entries - 1]; -} - -static size_t root_num_entries(size_t root_size) -{ - size_t entries_size; - - entries_size = root_size; - entries_size -= sizeof(struct imd_root_pointer); - entries_size -= sizeof(struct imd_root); - - return entries_size / sizeof(struct imd_entry); -} - -static size_t imd_root_data_left(struct imd_root *r) -{ - struct imd_entry *last_entry; - - last_entry = root_last_entry(r); - - if (r->max_offset != 0) - return last_entry->start_offset - r->max_offset; - - return ~(size_t)0; -} - -static bool root_is_locked(const struct imd_root *r) -{ - return !!(r->flags & IMD_FLAG_LOCKED); -} - -static int imdr_create_empty(struct imdr *imdr, size_t root_size, - size_t entry_align) -{ - struct imd_root_pointer *rp; - struct imd_root *r; - struct imd_entry *e; - ssize_t root_offset; - - if (!imdr->limit) - return -1; - - /* root_size and entry_align should be a power of 2. */ - if (!IS_POWER_OF_2(root_size)) - { - dbg_print("IMDR root_size not a power of 2, given %u\n", root_size); - while (1) {} - } - if (!IS_POWER_OF_2(entry_align)) - { - dbg_print("IMDR entry_align not a power of 2, given %u\n", entry_align); - while (1) {} - } - - if (!imdr->limit) - return -1; - - /* - * root_size needs to be large enough to accommodate root pointer and - * root book keeping structure. The caller needs to ensure there's - * enough room for tracking individual allocations. - */ - if (root_size < (sizeof(*rp) + sizeof(*r))) - return -1; - - /* For simplicity don't allow sizes or alignments to exceed LIMIT_ALIGN. - */ - if (root_size > LIMIT_ALIGN || entry_align > LIMIT_ALIGN) - return -1; - - /* Additionally, don't handle an entry alignment > root_size. */ - if (entry_align > root_size) - return -1; - - rp = imdr_get_root_pointer(imdr); - - root_offset = -(ssize_t)root_size; - /* Set root pointer. */ - imdr->r = relative_pointer((void *)imdr->limit, root_offset); - r = imdr_root(imdr); - imd_link_root(rp, r); - - memset(r, 0, sizeof(*r)); - r->entry_align = entry_align; - - /* Calculate size left for entries. */ - r->max_entries = root_num_entries(root_size); - - /* Fill in first entry covering the root region. */ - r->num_entries = 1; - e = &r->entries[0]; - imd_entry_assign(e, CBMEM_ID_IMD_ROOT, 0, root_size); - - dbg_print("IMD: root @ %p %u entries.\n", r, r->max_entries); - return 0; -} - -static int imdr_limit_size(struct imdr *imdr, size_t max_size) -{ - struct imd_root *r; - ssize_t smax_size; - size_t root_size; - - r = imdr_root(imdr); - if (r == NULL) - return -1; - - root_size = imdr->limit - (uintptr_t)r; - - if (max_size < root_size) - return -1; - - /* Take into account the root size. */ - smax_size = max_size - root_size; - smax_size = -smax_size; - - r->max_offset = smax_size; - - return 0; -} - -static void *imdr_entry_at(const struct imdr *imdr, const struct imd_entry *e) -{ - return relative_pointer(imdr_root(imdr), e->start_offset); -} - -static struct imd_entry *imd_entry_add_to_root(struct imd_root *r, uint32_t id, - size_t size) -{ - struct imd_entry *entry; - struct imd_entry *last_entry; - ssize_t e_offset; - size_t used_size; - - if (r->num_entries == r->max_entries) - return NULL; - - /* Determine total size taken up by entry. */ - used_size = ALIGN_UP(size, r->entry_align); - - /* See if size overflows imd total size. */ - if (used_size > imd_root_data_left(r)) - return NULL; - - /* - * Determine if offset field overflows. All offsets should be lower - * than the previous one. - */ - last_entry = root_last_entry(r); - e_offset = last_entry->start_offset; - e_offset -= (ssize_t)used_size; - if (e_offset > last_entry->start_offset) - return NULL; - - entry = root_last_entry(r) + 1; - r->num_entries++; - - imd_entry_assign(entry, id, e_offset, size); - - return entry; -} - -static const struct imd_entry *imdr_entry_add(const struct imdr *imdr, - uint32_t id, size_t size) -{ - struct imd_root *r; - - r = imdr_root(imdr); - - if (r == NULL) - return NULL; - - if (root_is_locked(r)) - return NULL; - - return imd_entry_add_to_root(r, id, size); -} - -static int imd_create_tiered_empty(struct imd *imd, - size_t lg_root_size, size_t lg_entry_align, - size_t sm_root_size, size_t sm_entry_align) -{ - size_t sm_region_size; - const struct imd_entry *e; - struct imdr *imdr; - - imdr = &imd->lg; - - if (imdr_create_empty(imdr, lg_root_size, lg_entry_align) != 0) - return -1; - - /* Calculate the size of the small region to request. */ - sm_region_size = root_num_entries(sm_root_size) * sm_entry_align; - sm_region_size += sm_root_size; - sm_region_size = ALIGN_UP(sm_region_size, lg_entry_align); - - /* Add a new entry to the large region to cover the root and entries. */ - e = imdr_entry_add(imdr, SMALL_REGION_ID, sm_region_size); - - if (e == NULL) - goto fail; - - imd->sm.limit = (uintptr_t)imdr_entry_at(imdr, e); - imd->sm.limit += sm_region_size; - - if (imdr_create_empty(&imd->sm, sm_root_size, sm_entry_align) != 0 || - imdr_limit_size(&imd->sm, sm_region_size)) - goto fail; - - return 0; -fail: - imd_handle_init(imd, (void *)imdr->limit); - return -1; -} - -void cbmem_initialize_empty_id_size(u32 id, u64 size) -{ - struct imd *imd; - struct imd imd_backing; - - imd = &imd_backing; - imd_handle_init(imd, cbmem_top()); - - dbg_print("CBMEM:\n"); - - if (imd_create_tiered_empty(imd, CBMEM_ROOT_MIN_SIZE, CBMEM_LG_ALIGN, - CBMEM_SM_ROOT_SIZE, CBMEM_SM_ALIGN)) { - dbg_print("failed.\n"); - return; - } - - /* Add the specified range first */ - if (size) - dbg_print("CBMEM region can only be empty, while size of %llu specified!\n", size); -} diff --git a/ariane/src/cbmem.h b/ariane/src/cbmem.h deleted file mode 100644 index 7163aff..0000000 --- a/ariane/src/cbmem.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 coresystems GmbH - * Copyright (C) 2013 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _CBMEM_H_ -#define _CBMEM_H_ - -#include -#include -#include "hwinit/types.h" - -#define CBMEM_FSP_HOB_PTR 0x614 - -struct cbmem_entry; - -/* - * The dynamic cbmem infrastructure allows for growing cbmem dynamically as - * things are added. It requires an external function, cbmem_top(), to be - * implemented by the board or chipset to define the upper address where - * cbmem lives. This address is required to be a 32-bit address. Additionally, - * the address needs to be consistent in both romstage and ramstage. The - * dynamic cbmem infrastructure allocates new regions below the last allocated - * region. Regions are defined by a cbmem_entry struct that is opaque. Regions - * may be removed, but the last one added is the only that can be removed. - */ - -#define DYN_CBMEM_ALIGN_SIZE (4096) -#define CBMEM_ROOT_SIZE DYN_CBMEM_ALIGN_SIZE - -/* The root region is at least DYN_CBMEM_ALIGN_SIZE . */ -#define CBMEM_ROOT_MIN_SIZE DYN_CBMEM_ALIGN_SIZE -#define CBMEM_LG_ALIGN CBMEM_ROOT_MIN_SIZE - -/* Small allocation parameters. */ -#define CBMEM_SM_ROOT_SIZE 1024 -#define CBMEM_SM_ALIGN 32 - -/* Determine the size for CBMEM root and the small allocations */ -static inline size_t cbmem_overhead_size(void) -{ - return 2 * CBMEM_ROOT_MIN_SIZE; -} - -#define CBMEM_ID_IMD_ROOT 0xff4017ff -#define CBMEM_ID_IMD_SMALL 0x53a11439 - -/* Initialize cbmem to be empty. */ -void cbmem_initialize_empty(void); -void cbmem_initialize_empty_id_size(u32 id, u64 size); - -/* Return the top address for dynamic cbmem. The address returned needs to - * be consistent across romstage and ramstage, and it is required to be - * below 4GiB. - * x86 boards or chipsets must return NULL before the cbmem backing store has - * been initialized. */ -void *cbmem_top(void); - -#endif /* _CBMEM_H_ */ diff --git a/ariane/src/display/cfb_console.c b/ariane/src/display/cfb_console.c deleted file mode 100644 index 9b33889..0000000 --- a/ariane/src/display/cfb_console.c +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * (C) Copyright 2002 ELTEC Elektronik AG - * Frank Gottschling - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * cfb_console.c - * - * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel. - * - * At the moment only the 8x16 font is tested and the font fore- and - * background color is limited to black/white/gray colors. The Linux - * logo can be placed in the upper left corner and additional board - * information strings (that normaly goes to serial port) can be drawed. - * - * The console driver can use the standard PC keyboard interface (i8042) - * for character input. Character output goes to a memory mapped video - * framebuffer with little or big-endian organisation. - * With environment setting 'console=serial' the console i/o can be - * forced to serial port. - - The driver uses graphic specific defines/parameters/functions: - - VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian - VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill - VIDEO_HW_BITBLT - graphic driver supports hardware bit blt - - Console Parameters are set by config: - - CONFIG_VIDEO_VISIBLE_COLS - x resolution - CONFIG_VIDEO_VISIBLE_ROWS - y resolution - CONFIG_VIDEO_PIXEL_SIZE - storage size in byte per pixel - CONFIG_VIDEO_DATA_FORMAT - graphical data format GDF - - CONFIG_CONSOLE_CURSOR - on/off drawing cursor is done with delay - loop in VIDEO_TSTC_FCT (i8042) - CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate - CONFIG_CONSOLE_TIME - display time/date in upper right corner, - needs CONFIG_CMD_DATE and CONFIG_CONSOLE_CURSOR - CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner - CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo - CONFIG_CONSOLE_EXTRA_INFO - display additional board information strings - that normaly goes to serial port. This define - requires a board specific function: - video_drawstring (VIDEO_INFO_X, - VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT, - info); - that fills a info buffer at i=row. - s.a: board/eltec/bab7xx. -CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be initialised - as an output only device. The Keyboard driver - will not be set-up. This may be used, if you - have none or more than one Keyboard devices - (USB Keyboard, AT Keyboard). - -CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last character. No - blinking is provided. Uses the macros CURSOR_SET - and CURSOR_OFF. -CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability of the - graphic chip. Uses the macro CURSOR_SET. - ATTENTION: If booting an OS, the display driver - must disable the hardware register of the graphic - chip. Otherwise a blinking field is displayed -*/ - -#include "video_fb.h" -#include - - -#if defined(CONFIG_VIDEO_FONT_SMALL) -#include "video_font_small.h" -#else -#include "video_font_large.h" -#endif - -#if defined(CONFIG_CMD_DATE) -#include -#endif - -#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) -#include -#include - -#ifdef CONFIG_SPLASH_SCREEN_ALIGN -#define BMP_ALIGN_CENTER 0x7FFF -#endif - -#endif - -/*****************************************************************************/ -/* Cursor definition: */ -/* CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c) */ -/* to let the cursor blink. Uses the macros */ -/* CURSOR_OFF and CURSOR_ON. */ -/* CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No */ -/* blinking is provided. Uses the macros CURSOR_SET */ -/* and CURSOR_OFF. */ -/* CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the */ -/* graphic chip. Uses the macro CURSOR_SET. */ -/* ATTENTION: If booting an OS, the display driver */ -/* must disable the hardware register of the graphic */ -/* chip. Otherwise a blinking field is displayed */ -/*****************************************************************************/ -#if !defined(CONFIG_CONSOLE_CURSOR) && \ - !defined(CONFIG_VIDEO_SW_CURSOR) && \ - !defined(CONFIG_VIDEO_HW_CURSOR) -/* no Cursor defined */ -#define CURSOR_ON -#define CURSOR_OFF -#define CURSOR_SET -#endif - -#ifdef CONFIG_CONSOLE_CURSOR -#ifdef CURSOR_ON -#error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined -#endif -void console_cursor (int state); -#define CURSOR_ON console_cursor(1) -#define CURSOR_OFF console_cursor(0) -#define CURSOR_SET -#else -#ifdef CONFIG_CONSOLE_TIME -#error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME -#endif -#endif /* CONFIG_CONSOLE_CURSOR */ - -#ifdef CONFIG_VIDEO_SW_CURSOR -#ifdef CURSOR_ON -#error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined -#endif -#define CURSOR_ON -#define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\ - console_row * VIDEO_FONT_HEIGHT, ' ') -#define CURSOR_SET video_set_cursor() -#endif /* CONFIG_VIDEO_SW_CURSOR */ - - -#ifdef CONFIG_VIDEO_HW_CURSOR -#ifdef CURSOR_ON -#error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined -#endif -#define CURSOR_ON -#define CURSOR_OFF -#define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \ - (console_row * VIDEO_FONT_HEIGHT) + video_logo_height) -#endif /* CONFIG_VIDEO_HW_CURSOR */ - -#ifdef CONFIG_VIDEO_LOGO -#ifdef CONFIG_VIDEO_BMP_LOGO -#include -#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH -#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT -#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET -#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS - -#else /* CONFIG_VIDEO_BMP_LOGO */ -#define LINUX_LOGO_WIDTH 80 -#define LINUX_LOGO_HEIGHT 80 -#define LINUX_LOGO_COLORS 214 -#define LINUX_LOGO_LUT_OFFSET 0x20 -#define __initdata -#include -#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH -#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT -#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET -#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS -#endif /* CONFIG_VIDEO_BMP_LOGO */ -#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH) -#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2) -#else /* CONFIG_VIDEO_LOGO */ -#define VIDEO_LOGO_WIDTH 0 -#define VIDEO_LOGO_HEIGHT 0 -#endif /* CONFIG_VIDEO_LOGO */ - -#ifdef CONFIG_VIDEO_COLS -#define VIDEO_COLS CONFIG_VIDEO_COLS -#else -#define VIDEO_COLS CONFIG_VIDEO_VISIBLE_COLS -#endif - -#define VIDEO_ROWS CONFIG_VIDEO_VISIBLE_ROWS -#define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*CONFIG_VIDEO_PIXEL_SIZE) -#define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) -#define VIDEO_LINE_LEN (VIDEO_COLS*CONFIG_VIDEO_PIXEL_SIZE) -#define VIDEO_BURST_LEN (VIDEO_COLS/8) - -#ifdef CONFIG_VIDEO_LOGO -#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT) -#else -#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT) -#endif - -#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH) -#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN) -#define CONSOLE_ROW_FIRST (video_console_address) -#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE) -#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE) -#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS) -#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE) - -/* Macros */ -#ifdef VIDEO_FB_LITTLE_ENDIAN -#define SWAP16(x) ((((x) & 0x00ff) << 8) | ( (x) >> 8)) -#define SWAP32(x) ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8)|\ - (((x) & 0x00ff0000) >> 8) | (((x) & 0xff000000) >> 24) ) -#define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | (((x) & 0x0000ff00) >> 8)|\ - (((x) & 0x00ff0000) << 8) | (((x) & 0xff000000) >> 8) ) -#else -#define SWAP16(x) (x) -#define SWAP32(x) (x) -#if defined(VIDEO_FB_16BPP_WORD_SWAP) -#define SHORTSWAP32(x) ( ((x) >> 16) | ((x) << 16) ) -#else -#define SHORTSWAP32(x) (x) -#endif -#endif - -#if defined(DEBUG) || defined(DEBUG_CFB_CONSOLE) -#define PRINTD(x) printf(x) -#else -#define PRINTD(x) -#endif - - -#ifdef CONFIG_CONSOLE_EXTRA_INFO -extern void video_get_info_str ( /* setup a board string: type, speed, etc. */ - int line_number, /* location to place info string beside logo */ - char *info /* buffer for info string */ - ); - -#endif - -#define ALIGN_UP(addr, align) (((addr) + (align) - 1) & (~((align) - 1))) -#define WIDTH_BYTES (ALIGN_UP(VIDEO_FONT_WIDTH, 8) / 8) - -static void *video_fb_address; /* frame buffer address */ -static void *video_console_address; /* console buffer start address */ - -static int video_logo_height = VIDEO_LOGO_HEIGHT; - -static int console_col = 0; /* cursor col */ -static int console_row = 0; /* cursor row */ - -static uint32_t eorx, fgx, bgx; /* color pats */ - -static const int video_font_draw_table8[] = { - 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, - 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, - 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, - 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff }; - -static const int video_font_draw_table15[] = { - 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff }; - -static const int video_font_draw_table16[] = { - 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff }; - -static const int video_font_draw_table24[16][3] = { - { 0x00000000, 0x00000000, 0x00000000 }, - { 0x00000000, 0x00000000, 0x00ffffff }, - { 0x00000000, 0x0000ffff, 0xff000000 }, - { 0x00000000, 0x0000ffff, 0xffffffff }, - { 0x000000ff, 0xffff0000, 0x00000000 }, - { 0x000000ff, 0xffff0000, 0x00ffffff }, - { 0x000000ff, 0xffffffff, 0xff000000 }, - { 0x000000ff, 0xffffffff, 0xffffffff }, - { 0xffffff00, 0x00000000, 0x00000000 }, - { 0xffffff00, 0x00000000, 0x00ffffff }, - { 0xffffff00, 0x0000ffff, 0xff000000 }, - { 0xffffff00, 0x0000ffff, 0xffffffff }, - { 0xffffffff, 0xffff0000, 0x00000000 }, - { 0xffffffff, 0xffff0000, 0x00ffffff }, - { 0xffffffff, 0xffffffff, 0xff000000 }, - { 0xffffffff, 0xffffffff, 0xffffffff } }; - -static const int video_font_draw_table32[16][4] = { - { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00000000, 0x00000000, 0x00000000, 0x00ffffff }, - { 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 }, - { 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff }, - { 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 }, - { 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff }, - { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 }, - { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff }, - { 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff }, - { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 }, - { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff }, - { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 }, - { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff }, - { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 }, - { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff } }; - - -/******************************************************************************/ - -static void video_drawchars (int xx, int yy, unsigned char *s, int count) -{ - uint8_t *cdat, *dest, *dest0; - int rows, offset, c, cols, tbits; - - offset = yy * VIDEO_LINE_LEN + xx * CONFIG_VIDEO_PIXEL_SIZE; - dest0 = video_fb_address + offset; - - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - case GDF__8BIT_332RGB: - while (count--) { - c = *s; - cdat = video_fontdata + c * (VIDEO_FONT_HEIGHT * WIDTH_BYTES); - for (rows = VIDEO_FONT_HEIGHT, dest = dest0; - rows--; - dest += VIDEO_LINE_LEN) { - cols = 0; - tbits = VIDEO_FONT_WIDTH; - while (tbits > 0) { - uint8_t bits = *cdat++; - - ((uint32_t *) dest)[cols + 0] = (video_font_draw_table8[bits >> 4] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 1] = (video_font_draw_table8[bits & 15] & eorx) ^ bgx; - cols += 8; - tbits -= 8; - } - } - dest0 += VIDEO_FONT_WIDTH * CONFIG_VIDEO_PIXEL_SIZE; - s++; - } - break; - - case GDF_15BIT_555RGB: - while (count--) { - c = *s; - cdat = video_fontdata + c * (VIDEO_FONT_HEIGHT * WIDTH_BYTES); - for (rows = VIDEO_FONT_HEIGHT, dest = dest0; - rows--; - dest += VIDEO_LINE_LEN) { - cols = 0; - tbits = VIDEO_FONT_WIDTH; - while (tbits > 0) { - uint8_t bits = *cdat++; - - ((uint32_t *) dest)[cols + 0] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 6] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 1] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 4 & 3] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 2] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 2 & 3] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 3] = SHORTSWAP32 ((video_font_draw_table15 [bits & 3] & eorx) ^ bgx); - cols += 8; - tbits -= 8; - } - } - dest0 += VIDEO_FONT_WIDTH * CONFIG_VIDEO_PIXEL_SIZE; - s++; - } - break; - - case GDF_16BIT_565RGB: - while (count--) { - c = *s; - cdat = video_fontdata + c * (VIDEO_FONT_HEIGHT * WIDTH_BYTES); - for (rows = VIDEO_FONT_HEIGHT, dest = dest0; - rows--; - dest += VIDEO_LINE_LEN) { - cols = 0; - tbits = VIDEO_FONT_WIDTH; - while (tbits > 0) { - uint8_t bits = *cdat++; - - ((uint32_t *) dest)[cols + 0] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 6] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 1] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 4 & 3] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 2] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 2 & 3] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 3] = SHORTSWAP32 ((video_font_draw_table16 [bits & 3] & eorx) ^ bgx); - cols += 8; - tbits -= 8; - } - } - dest0 += VIDEO_FONT_WIDTH * CONFIG_VIDEO_PIXEL_SIZE; - s++; - } - break; - - case GDF_32BIT_X888RGB: - while (count--) { - c = *s; - cdat = video_fontdata + c * (VIDEO_FONT_HEIGHT * WIDTH_BYTES); - for (rows = VIDEO_FONT_HEIGHT, dest = dest0; - rows--; - dest += VIDEO_LINE_LEN) { - cols = 0; - tbits = VIDEO_FONT_WIDTH; - while (tbits > 0) { - uint8_t bits = *cdat++; - - ((uint32_t *) dest)[cols + 0] = SWAP32 ((video_font_draw_table32 [bits >> 4][0] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 1] = SWAP32 ((video_font_draw_table32 [bits >> 4][1] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 2] = SWAP32 ((video_font_draw_table32 [bits >> 4][2] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 3] = SWAP32 ((video_font_draw_table32 [bits >> 4][3] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 4] = SWAP32 ((video_font_draw_table32 [bits & 15][0] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 5] = SWAP32 ((video_font_draw_table32 [bits & 15][1] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 6] = SWAP32 ((video_font_draw_table32 [bits & 15][2] & eorx) ^ bgx); - ((uint32_t *) dest)[cols + 7] = SWAP32 ((video_font_draw_table32 [bits & 15][3] & eorx) ^ bgx); - cols += 8; - tbits -= 8; - } - } - dest0 += VIDEO_FONT_WIDTH * CONFIG_VIDEO_PIXEL_SIZE; - s++; - } - break; - - case GDF_24BIT_888RGB: - while (count--) { - c = *s; - cdat = video_fontdata + c * (VIDEO_FONT_HEIGHT * WIDTH_BYTES); - for (rows = VIDEO_FONT_HEIGHT, dest = dest0; - rows--; - dest += VIDEO_LINE_LEN) { - cols = 0; - tbits = VIDEO_FONT_WIDTH; - while (tbits > 0) { - uint8_t bits = *cdat++; - - ((uint32_t *) dest)[cols + 0] = (video_font_draw_table24[bits >> 4][0] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 1] = (video_font_draw_table24[bits >> 4][1] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 2] = (video_font_draw_table24[bits >> 4][2] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 3] = (video_font_draw_table24[bits & 15][0] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 4] = (video_font_draw_table24[bits & 15][1] & eorx) ^ bgx; - ((uint32_t *) dest)[cols + 5] = (video_font_draw_table24[bits & 15][2] & eorx) ^ bgx; - cols += 8; - tbits -= 8; - } - } - dest0 += VIDEO_FONT_WIDTH * CONFIG_VIDEO_PIXEL_SIZE; - s++; - } - break; - } -} - -/*****************************************************************************/ - -static inline void video_drawstring (int xx, int yy, unsigned char *s) -{ - video_drawchars (xx, yy, s, strlen ((char *)s)); -} - -/*****************************************************************************/ - -static void video_putchar (int xx, int yy, unsigned char c) -{ - video_drawchars (xx, yy + video_logo_height, &c, 1); -} - -/*****************************************************************************/ -#if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) -static void video_set_cursor (void) -{ - /* swap drawing colors */ - eorx = fgx; - fgx = bgx; - bgx = eorx; - eorx = fgx ^ bgx; - /* draw cursor */ - video_putchar (console_col * VIDEO_FONT_WIDTH, - console_row * VIDEO_FONT_HEIGHT, - ' '); - /* restore drawing colors */ - eorx = fgx; - fgx = bgx; - bgx = eorx; - eorx = fgx ^ bgx; -} -#endif -/*****************************************************************************/ -#ifdef CONFIG_CONSOLE_CURSOR -void console_cursor (int state) -{ - static int last_state = 0; - -#ifdef CONFIG_CONSOLE_TIME - struct rtc_time tm; - char info[16]; - - /* time update only if cursor is on (faster scroll) */ - if (state) { - rtc_get (&tm); - - sprintf (info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min, - tm.tm_sec); - video_drawstring (CONFIG_VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, - VIDEO_INFO_Y, (uchar *)info); - - sprintf (info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon, - tm.tm_year); - video_drawstring (CONFIG_VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, - VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT, (uchar *)info); - } -#endif - - if (state && (last_state != state)) { - video_set_cursor (); - } - - if (!state && (last_state != state)) { - /* clear cursor */ - video_putchar (console_col * VIDEO_FONT_WIDTH, - console_row * VIDEO_FONT_HEIGHT, - ' '); - } - - last_state = state; -} -#endif - -/*****************************************************************************/ - -#ifndef VIDEO_HW_RECTFILL -static void memsetl (int *p, int c, int v) -{ - while (c--) - *(p++) = v; -} -#endif - -/*****************************************************************************/ - -#ifdef SLOW_SCROLLING -static void console_scrollup (void) -{ - /* copy up rows ignoring the first one */ - -#ifdef VIDEO_HW_BITBLT - video_hw_bitblt (CONFIG_VIDEO_PIXEL_SIZE, /* bytes per pixel */ - 0, /* source pos x */ - video_logo_height + VIDEO_FONT_HEIGHT, /* source pos y */ - 0, /* dest pos x */ - video_logo_height, /* dest pos y */ - CONFIG_VIDEO_VISIBLE_COLS, /* frame width */ - CONFIG_VIDEO_VISIBLE_ROWS - video_logo_height - VIDEO_FONT_HEIGHT /* frame height */ - ); -#else - memcpy(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, - CONSOLE_SCROLL_SIZE); -#endif - - /* clear the last one */ -#ifdef VIDEO_HW_RECTFILL - video_hw_rectfill (CONFIG_VIDEO_PIXEL_SIZE, /* bytes per pixel */ - 0, /* dest pos x */ - CONFIG_VIDEO_VISIBLE_ROWS - VIDEO_FONT_HEIGHT, /* dest pos y */ - CONFIG_VIDEO_VISIBLE_COLS, /* frame width */ - VIDEO_FONT_HEIGHT, /* frame height */ - CONSOLE_BG_COL /* fill color */ - ); -#else - memsetl (CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL); -#endif -} -#endif - -/*****************************************************************************/ - -static void console_back (void) -{ - CURSOR_OFF; - console_col--; - - if (console_col < 0) { - console_col = CONSOLE_COLS - 1; - console_row--; - if (console_row < 0) - console_row = 0; - } - video_putchar (console_col * VIDEO_FONT_WIDTH, - console_row * VIDEO_FONT_HEIGHT, - ' '); -} - -/*****************************************************************************/ - -static void console_newline (void) -{ - /* Check if last character in the line was just drawn. If so, cursor was - overwriten and need not to be cleared. Cursor clearing without this - check causes overwriting the 1st character of the line if line lenght - is >= CONSOLE_COLS - */ - if (console_col < CONSOLE_COLS) - CURSOR_OFF; - console_row++; - console_col = 0; - - /* Check if we need to scroll the terminal */ - if (console_row >= CONSOLE_ROWS) { - #ifdef SLOW_SCROLLING - /* Scroll everything up */ - console_scrollup (); - - /* Decrement row number */ - console_row--; - #else - video_init(video_fb_address); - console_row = 0; - #endif - } -} - -static void console_cr (void) -{ - CURSOR_OFF; - console_col = 0; -} - -/*****************************************************************************/ - -void video_putc (const char c) -{ - static int nl = 1; - - switch (c) { - case 13: /* back to first column */ - console_cr (); - break; - - case '\n': /* next line */ - if (console_col || (!console_col && nl)) - console_newline (); - nl = 1; - break; - - case 9: /* tab 8 */ - CURSOR_OFF; - console_col |= 0x0008; - console_col &= ~0x0007; - - if (console_col >= CONSOLE_COLS) - console_newline (); - break; - - case 8: /* backspace */ - console_back (); - break; - - default: /* draw the char */ - video_putchar (console_col * VIDEO_FONT_WIDTH, - console_row * VIDEO_FONT_HEIGHT, - c); - console_col++; - - /* check for newline */ - if (console_col >= CONSOLE_COLS) { - console_newline (); - nl = 0; - } - } - CURSOR_SET; -} - - -/*****************************************************************************/ - -void video_puts (const char *s) -{ - int count = strlen (s); - - while (count--) - video_putc (*s++); -} - -/*****************************************************************************/ - -/* - * Do not enforce drivers (or board code) to provide empty - * video_set_lut() if they do not support 8 bpp format. - * Implement weak default function instead. - */ -void __video_set_lut (unsigned int index, unsigned char r, - unsigned char g, unsigned char b) -{ -} -void video_set_lut (unsigned int, unsigned char, unsigned char, unsigned char) - __attribute__((weak, alias("__video_set_lut"))); - -#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) - -#define FILL_8BIT_332RGB(r,g,b) { \ - *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \ - fb ++; \ -} - -#define FILL_15BIT_555RGB(r,g,b) { \ - *(unsigned short *)fb = SWAP16((unsigned short)(((r>>3)<<10) | ((g>>3)<<5) | (b>>3))); \ - fb += 2; \ -} - -#define FILL_16BIT_565RGB(r,g,b) { \ - *(unsigned short *)fb = SWAP16((unsigned short)((((r)>>3)<<11) | (((g)>>2)<<5) | ((b)>>3))); \ - fb += 2; \ -} - -#define FILL_32BIT_X888RGB(r,g,b) { \ - *(unsigned long *)fb = SWAP32((unsigned long)(((r<<16) | (g<<8) | b))); \ - fb += 4; \ -} - -#ifdef VIDEO_FB_LITTLE_ENDIAN -#define FILL_24BIT_888RGB(r,g,b) { \ - fb[0] = b; \ - fb[1] = g; \ - fb[2] = r; \ - fb += 3; \ -} -#else -#define FILL_24BIT_888RGB(r,g,b) { \ - fb[0] = r; \ - fb[1] = g; \ - fb[2] = b; \ - fb += 3; \ -} -#endif - -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) -static void inline fill_555rgb_pswap(uchar *fb, int x, - uint8_t r, uint8_t g, uint8_t b) -{ - ushort *dst = (ushort *)fb; - ushort color = (ushort)(((r >> 3) << 10) | - ((g >> 3) << 5) | - (b >> 3)); - if (x & 1) - *(--dst) = color; - else - *(++dst) = color; -} -#endif - -/* - * RLE8 bitmap support - */ - -#ifdef CONFIG_VIDEO_BMP_RLE8 -/* Pre-calculated color table entry */ -struct palette { - union { - unsigned short w; /* word */ - unsigned int dw; /* double word */ - } ce; /* color entry */ -}; - -/* - * Helper to draw encoded/unencoded run. - */ -static void draw_bitmap (uchar **fb, uchar *bm, struct palette *p, - int cnt, int enc) -{ - ulong addr = (ulong)*fb; - int *off; - int enc_off = 1; - int i; - - /* - * Setup offset of the color index in the bitmap. - * Color index of encoded run is at offset 1. - */ - off = enc ? &enc_off : &i; - - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - for (i = 0; i < cnt; i++) - *(unsigned char *)addr++ = bm[*off]; - break; - case GDF_15BIT_555RGB: - case GDF_16BIT_565RGB: - /* differences handled while pre-calculating palette */ - for (i = 0; i < cnt; i++) { - *(unsigned short *)addr = p[bm[*off]].ce.w; - addr += 2; - } - break; - case GDF_32BIT_X888RGB: - for (i = 0; i < cnt; i++) { - *(unsigned long *)addr = p[bm[*off]].ce.dw; - addr += 4; - } - break; - } - *fb = (uchar *)addr; /* return modified address */ -} - -static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff, - int width, int height) -{ - unsigned char *bm; - unsigned char *fbp; - unsigned int cnt, runlen; - int decode = 1; - int x, y, bpp, i, ncolors; - struct palette p[256]; - bmp_color_table_entry_t cte; - int green_shift, red_off; - - x = 0; - y = __le32_to_cpu(img->header.height) - 1; - ncolors = __le32_to_cpu(img->header.colors_used); - bpp = CONFIG_VIDEO_PIXEL_SIZE; - fbp = (unsigned char *)((unsigned int)video_fb_address + - (((y + yoff) * VIDEO_COLS) + xoff) * bpp); - - bm = (uchar *)img + __le32_to_cpu(img->header.data_offset); - - /* pre-calculate and setup palette */ - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - for (i = 0; i < ncolors; i++) { - cte = img->color_table[i]; - video_set_lut (i, cte.red, cte.green, cte.blue); - } - break; - case GDF_15BIT_555RGB: - case GDF_16BIT_565RGB: - if (CONFIG_VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) { - green_shift = 3; - red_off = 10; - } else { - green_shift = 2; - red_off = 11; - } - for (i = 0; i < ncolors; i++) { - cte = img->color_table[i]; - p[i].ce.w = SWAP16((unsigned short) - (((cte.red >> 3) << red_off) | - ((cte.green >> green_shift) << 5) | - cte.blue >> 3)); - } - break; - case GDF_32BIT_X888RGB: - for (i = 0; i < ncolors; i++) { - cte = img->color_table[i]; - p[i].ce.dw = SWAP32((cte.red << 16) | (cte.green << 8) | - cte.blue); - } - break; - default: - printf("RLE Bitmap unsupported in video mode 0x%x\n", - CONFIG_VIDEO_DATA_FORMAT); - return -1; - } - - while (decode) { - switch (bm[0]) { - case 0: - switch (bm[1]) { - case 0: - /* scan line end marker */ - bm += 2; - x = 0; - y--; - fbp = (unsigned char *) - ((unsigned int)video_fb_address + - (((y + yoff) * VIDEO_COLS) + - xoff) * bpp); - continue; - case 1: - /* end of bitmap data marker */ - decode = 0; - break; - case 2: - /* run offset marker */ - x += bm[2]; - y -= bm[3]; - fbp = (unsigned char *) - ((unsigned int)video_fb_address + - (((y + yoff) * VIDEO_COLS) + - x + xoff) * bpp); - bm += 4; - break; - default: - /* unencoded run */ - cnt = bm[1]; - runlen = cnt; - bm += 2; - if (y < height) { - if (x >= width) { - x += runlen; - goto next_run; - } - if (x + runlen > width) - cnt = width - x; - - draw_bitmap (&fbp, bm, p, cnt, 0); - x += runlen; - } -next_run: - bm += runlen; - if (runlen & 1) - bm++; /* 0 padding if length is odd */ - } - break; - default: - /* encoded run */ - if (y < height) { /* only draw into visible area */ - cnt = bm[0]; - runlen = cnt; - if (x >= width) { - x += runlen; - bm += 2; - continue; - } - if (x + runlen > width) - cnt = width - x; - - draw_bitmap (&fbp, bm, p, cnt, 1); - x += runlen; - } - bm += 2; - break; - } - } - return 0; -} -#endif - -/* - * Display the BMP file located at address bmp_image. - */ -int video_display_bitmap (ulong bmp_image, int x, int y) -{ - unsigned xcount, ycount; - unsigned *fb; - bmp_image_t *bmp = (bmp_image_t *) bmp_image; - uchar *bmap; - unsigned padded_line; - unsigned long width, height, bpp; - unsigned colors; - unsigned long compression; - bmp_color_table_entry_t cte; -#ifdef CONFIG_VIDEO_BMP_GZIP - unsigned char *dst = NULL; - ulong len; -#endif - - WATCHDOG_RESET (); - - if (!((bmp->header.signature[0] == 'B') && - (bmp->header.signature[1] == 'M'))) { - -#ifdef CONFIG_VIDEO_BMP_GZIP - /* - * Could be a gzipped bmp image, try to decrompress... - */ - len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; - dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); - if (dst == NULL) { - printf("Error: malloc in gunzip failed!\n"); - return(1); - } - if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)bmp_image, &len) != 0) { - printf ("Error: no valid bmp or bmp.gz image at %lx\n", bmp_image); - free(dst); - return 1; - } - if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) { - printf("Image could be truncated (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); - } - - /* - * Set addr to decompressed image - */ - bmp = (bmp_image_t *)dst; - - if (!((bmp->header.signature[0] == 'B') && - (bmp->header.signature[1] == 'M'))) { - printf ("Error: no valid bmp.gz image at %lx\n", bmp_image); - free(dst); - return 1; - } -#else - printf ("Error: no valid bmp image at %lx\n", bmp_image); - return 1; -#endif /* CONFIG_VIDEO_BMP_GZIP */ - } - - width = le32_to_cpu (bmp->header.width); - height = le32_to_cpu (bmp->header.height); - bpp = le16_to_cpu (bmp->header.bit_count); - colors = le32_to_cpu (bmp->header.colors_used); - compression = le32_to_cpu (bmp->header.compression); - - debug ("Display-bmp: %d x %d with %d colors\n", - width, height, colors); - - if (compression != BMP_BI_RGB -#ifdef CONFIG_VIDEO_BMP_RLE8 - && compression != BMP_BI_RLE8 -#endif - ) { - printf ("Error: compression type %ld not supported\n", - compression); -#ifdef CONFIG_VIDEO_BMP_GZIP - if (dst) - free(dst); -#endif - return 1; - } - - padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3; - -#ifdef CONFIG_SPLASH_SCREEN_ALIGN - if (x == BMP_ALIGN_CENTER) - x = max(0, (CONFIG_VIDEO_VISIBLE_COLS - width) / 2); - else if (x < 0) - x = max(0, CONFIG_VIDEO_VISIBLE_COLS - width + x + 1); - - if (y == BMP_ALIGN_CENTER) - y = max(0, (CONFIG_VIDEO_VISIBLE_ROWS - height) / 2); - else if (y < 0) - y = max(0, CONFIG_VIDEO_VISIBLE_ROWS - height + y + 1); -#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ - - if ((x + width) > CONFIG_VIDEO_VISIBLE_COLS) - width = CONFIG_VIDEO_VISIBLE_COLS - x; - if ((y + height) > CONFIG_VIDEO_VISIBLE_ROWS) - height = CONFIG_VIDEO_VISIBLE_ROWS - y; - - bmap = (uchar *) bmp + le32_to_cpu (bmp->header.data_offset); - fb = (uchar *) (video_fb_address + - ((y + height - 1) * VIDEO_COLS * CONFIG_VIDEO_PIXEL_SIZE) + - x * CONFIG_VIDEO_PIXEL_SIZE); - -#ifdef CONFIG_VIDEO_BMP_RLE8 - if (compression == BMP_BI_RLE8) { - return display_rle8_bitmap(bmp, - x, y, width, height); - } -#endif - - /* We handle only 4, 8, or 24 bpp bitmaps */ - switch (le16_to_cpu (bmp->header.bit_count)) { - case 4: - padded_line -= width / 2; - ycount = height; - - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF_32BIT_X888RGB: - while (ycount--) { - WATCHDOG_RESET (); - /* - * Don't assume that 'width' is an - * even number - */ - for (xcount = 0; xcount < width; xcount++) { - uchar idx; - - if (xcount & 1) { - idx = *bmap & 0xF; - bmap++; - } else - idx = *bmap >> 4; - cte = bmp->color_table[idx]; - FILL_32BIT_X888RGB(cte.red, cte.green, - cte.blue); - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * - CONFIG_VIDEO_PIXEL_SIZE; - } - break; - default: - puts("4bpp bitmap unsupported with current " - "video mode\n"); - break; - } - break; - - case 8: - padded_line -= width; - if (CONFIG_VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { - /* Copy colormap */ - for (xcount = 0; xcount < colors; ++xcount) { - cte = bmp->color_table[xcount]; - video_set_lut (xcount, cte.red, cte.green, cte.blue); - } - } - ycount = height; - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - *fb++ = *bmap++; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF__8BIT_332RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - cte = bmp->color_table[*bmap++]; - FILL_8BIT_332RGB (cte.red, cte.green, cte.blue); - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_15BIT_555RGB: - while (ycount--) { -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - int xpos = x; -#endif - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - cte = bmp->color_table[*bmap++]; -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - fill_555rgb_pswap (fb, xpos++, cte.red, - cte.green, cte.blue); - fb += 2; -#else - FILL_15BIT_555RGB (cte.red, cte.green, cte.blue); -#endif - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_16BIT_565RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - cte = bmp->color_table[*bmap++]; - FILL_16BIT_565RGB (cte.red, cte.green, cte.blue); - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_32BIT_X888RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - cte = bmp->color_table[*bmap++]; - FILL_32BIT_X888RGB (cte.red, cte.green, cte.blue); - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_24BIT_888RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - cte = bmp->color_table[*bmap++]; - FILL_24BIT_888RGB (cte.red, cte.green, cte.blue); - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - } - break; - case 24: - padded_line -= 3 * width; - ycount = height; - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_332RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - FILL_8BIT_332RGB (bmap[2], bmap[1], bmap[0]); - bmap += 3; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_15BIT_555RGB: - while (ycount--) { -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - int xpos = x; -#endif - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - fill_555rgb_pswap (fb, xpos++, bmap[2], - bmap[1], bmap[0]); - fb += 2; -#else - FILL_15BIT_555RGB (bmap[2], bmap[1], bmap[0]); -#endif - bmap += 3; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_16BIT_565RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - FILL_16BIT_565RGB (bmap[2], bmap[1], bmap[0]); - bmap += 3; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_32BIT_X888RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - FILL_32BIT_X888RGB (bmap[2], bmap[1], bmap[0]); - bmap += 3; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - case GDF_24BIT_888RGB: - while (ycount--) { - WATCHDOG_RESET (); - xcount = width; - while (xcount--) { - FILL_24BIT_888RGB (bmap[2], bmap[1], bmap[0]); - bmap += 3; - } - bmap += padded_line; - fb -= (CONFIG_VIDEO_VISIBLE_COLS + width) * CONFIG_VIDEO_PIXEL_SIZE; - } - break; - default: - printf ("Error: 24 bits/pixel bitmap incompatible with current video mode\n"); - break; - } - break; - default: - printf ("Error: %d bit/pixel bitmaps not supported by U-Boot\n", - le16_to_cpu (bmp->header.bit_count)); - break; - } - -#ifdef CONFIG_VIDEO_BMP_GZIP - if (dst) { - free(dst); - } -#endif - - return (0); -} -#endif - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_LOGO -void logo_plot (void *screen, int width, int x, int y) -{ - - int xcount, i; - int skip = (width - VIDEO_LOGO_WIDTH) * CONFIG_VIDEO_PIXEL_SIZE; - int ycount = video_logo_height; - unsigned char r, g, b, *logo_red, *logo_blue, *logo_green; - unsigned char *source; - unsigned char *dest = (unsigned char *)screen + - ((y * width * CONFIG_VIDEO_PIXEL_SIZE) + - x * CONFIG_VIDEO_PIXEL_SIZE); - -#ifdef CONFIG_VIDEO_BMP_LOGO - source = bmp_logo_bitmap; - - /* Allocate temporary space for computing colormap */ - logo_red = malloc (BMP_LOGO_COLORS); - logo_green = malloc (BMP_LOGO_COLORS); - logo_blue = malloc (BMP_LOGO_COLORS); - /* Compute color map */ - for (i = 0; i < VIDEO_LOGO_COLORS; i++) { - logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4; - logo_green[i] = (bmp_logo_palette[i] & 0x00f0); - logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4; - } -#else - source = linux_logo; - logo_red = linux_logo_red; - logo_green = linux_logo_green; - logo_blue = linux_logo_blue; -#endif - - if (CONFIG_VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { - for (i = 0; i < VIDEO_LOGO_COLORS; i++) { - video_set_lut (i + VIDEO_LOGO_LUT_OFFSET, - logo_red[i], logo_green[i], logo_blue[i]); - } - } - - while (ycount--) { -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - int xpos = x; -#endif - xcount = VIDEO_LOGO_WIDTH; - while (xcount--) { - r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; - g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; - b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; - - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - *dest = *source; - break; - case GDF__8BIT_332RGB: - *dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); - break; - case GDF_15BIT_555RGB: -#if defined(VIDEO_FB_16BPP_PIXEL_SWAP) - fill_555rgb_pswap (dest, xpos++, r, g, b); -#else - *(unsigned short *) dest = - SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3))); -#endif - break; - case GDF_16BIT_565RGB: - *(unsigned short *) dest = - SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3))); - break; - case GDF_32BIT_X888RGB: - *(unsigned long *) dest = - SWAP32 ((unsigned long) ((r << 16) | (g << 8) | b)); - break; - case GDF_24BIT_888RGB: -#ifdef VIDEO_FB_LITTLE_ENDIAN - dest[0] = b; - dest[1] = g; - dest[2] = r; -#else - dest[0] = r; - dest[1] = g; - dest[2] = b; -#endif - break; - } - source++; - dest += CONFIG_VIDEO_PIXEL_SIZE; - } - dest += skip; - } -#ifdef CONFIG_VIDEO_BMP_LOGO - free (logo_red); - free (logo_green); - free (logo_blue); -#endif -} - -/*****************************************************************************/ - -static void *video_logo (void) -{ - char info[128]; - extern char version_string; - int space, len, y_off = 0; - -#ifdef CONFIG_SPLASH_SCREEN - char *s; - ulong addr; - - if ((s = getenv ("splashimage")) != NULL) { - int x = 0, y = 0; - - addr = simple_strtoul (s, NULL, 16); -#ifdef CONFIG_SPLASH_SCREEN_ALIGN - if ((s = getenv ("splashpos")) != NULL) { - if (s[0] == 'm') - x = BMP_ALIGN_CENTER; - else - x = simple_strtol (s, NULL, 0); - - if ((s = strchr (s + 1, ',')) != NULL) { - if (s[1] == 'm') - y = BMP_ALIGN_CENTER; - else - y = simple_strtol (s + 1, NULL, 0); - } - } -#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ - - if (video_display_bitmap (addr, x, y) == 0) { - video_logo_height = 0; - return ((void *) (video_fb_address)); - } - } -#endif /* CONFIG_SPLASH_SCREEN */ - - logo_plot (video_fb_address, VIDEO_COLS, 0, 0); - - sprintf (info, " %s", &version_string); - - space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH; - len = strlen(info); - - if (len > space) { - video_drawchars (VIDEO_INFO_X, VIDEO_INFO_Y, - (uchar *)info, space); - video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH, - VIDEO_INFO_Y + VIDEO_FONT_HEIGHT, - (uchar *)info + space, len - space); - y_off = 1; - } else - video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *)info); - -#ifdef CONFIG_CONSOLE_EXTRA_INFO - { - int i, n = ((video_logo_height - VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT); - - for (i = 1; i < n; i++) { - video_get_info_str (i, info); - if (!*info) - continue; - - len = strlen(info); - if (len > space) { - video_drawchars (VIDEO_INFO_X, - VIDEO_INFO_Y + - (i + y_off) * VIDEO_FONT_HEIGHT, - (uchar *)info, space); - y_off++; - video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH, - VIDEO_INFO_Y + - (i + y_off) * VIDEO_FONT_HEIGHT, - (uchar *)info + space, - len - space); - } else { - video_drawstring (VIDEO_INFO_X, - VIDEO_INFO_Y + - (i + y_off) * VIDEO_FONT_HEIGHT, - (uchar *)info); - } - } - } -#endif - - return (video_fb_address + video_logo_height * VIDEO_LINE_LEN); -} -#endif - - -/*****************************************************************************/ - -int video_resume(void *videobase, int row, int col) { - unsigned char color8; - - video_fb_address = videobase; -#ifdef CONFIG_VIDEO_HW_CURSOR - video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT); -#endif - - /* Init drawing pats */ - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL); - video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL); - fgx = 0x01010101; - bgx = 0x00000000; - break; - case GDF__8BIT_332RGB: - color8 = ((CONSOLE_FG_COL & 0xe0) | - ((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6); - fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; - color8 = ((CONSOLE_BG_COL & 0xe0) | - ((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6); - bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; - break; - case GDF_15BIT_555RGB: - fgx = (((CONSOLE_FG_COL >> 3) << 26) | - ((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | - ((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) | - (CONSOLE_FG_COL >> 3)); - bgx = (((CONSOLE_BG_COL >> 3) << 26) | - ((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | - ((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) | - (CONSOLE_BG_COL >> 3)); - break; - case GDF_16BIT_565RGB: - fgx = (((CONSOLE_FG_COL >> 3) << 27) | - ((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | - ((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) | - (CONSOLE_FG_COL >> 3)); - bgx = (((CONSOLE_BG_COL >> 3) << 27) | - ((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | - ((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) | - (CONSOLE_BG_COL >> 3)); - break; - case GDF_32BIT_X888RGB: - fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; - bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; - break; - case GDF_24BIT_888RGB: - fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) | - (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; - bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) | - (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; - break; - } - eorx = fgx ^ bgx; - -#ifdef CONFIG_VIDEO_LOGO - /* Plot the logo and get start point of console */ - PRINTD ("Video: Drawing the logo ...\n"); - video_console_address = video_logo (); -#else - video_console_address = video_fb_address; -#endif - - /* Initialize the console */ - console_col = col; - console_row = row; - - return 0; -} - -int video_get_col(void) { - return console_col; -} - -int video_get_row(void) { - return console_row; -} - -void video_reposition(int row, int col) -{ - console_row = row; - console_col = col; -} - -void video_clear_line() -{ - while (console_col < CONSOLE_COLS && console_col != 0) - video_putc(' '); -} - -int video_init (void *videobase) -{ - unsigned char color8; - - video_fb_address = videobase; -#ifdef CONFIG_VIDEO_HW_CURSOR - video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT); -#endif - - /* Init drawing pats */ - switch (CONFIG_VIDEO_DATA_FORMAT) { - case GDF__8BIT_INDEX: - video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL); - video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL); - fgx = 0x01010101; - bgx = 0x00000000; - break; - case GDF__8BIT_332RGB: - color8 = ((CONSOLE_FG_COL & 0xe0) | - ((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6); - fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; - color8 = ((CONSOLE_BG_COL & 0xe0) | - ((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6); - bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; - break; - case GDF_15BIT_555RGB: - fgx = (((CONSOLE_FG_COL >> 3) << 26) | - ((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | - ((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) | - (CONSOLE_FG_COL >> 3)); - bgx = (((CONSOLE_BG_COL >> 3) << 26) | - ((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | - ((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) | - (CONSOLE_BG_COL >> 3)); - break; - case GDF_16BIT_565RGB: - fgx = (((CONSOLE_FG_COL >> 3) << 27) | - ((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | - ((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) | - (CONSOLE_FG_COL >> 3)); - bgx = (((CONSOLE_BG_COL >> 3) << 27) | - ((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | - ((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) | - (CONSOLE_BG_COL >> 3)); - break; - case GDF_32BIT_X888RGB: - fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; - bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; - break; - case GDF_24BIT_888RGB: - fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) | - (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; - bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) | - (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; - break; - } - eorx = fgx ^ bgx; - -#ifdef CONFIG_VIDEO_LOGO - /* Plot the logo and get start point of console */ - PRINTD ("Video: Drawing the logo ...\n"); - video_console_address = video_logo (); -#else - video_console_address = video_fb_address; -#endif - - /* Initialize the console */ - console_col = 0; - console_row = 0; - - memsetl(CONSOLE_ROW_FIRST, VIDEO_COLS * VIDEO_ROWS, - CONSOLE_BG_COL); - - return 0; -} diff --git a/ariane/src/display/video_fb.h b/ariane/src/display/video_fb.h deleted file mode 100644 index ee4cff8..0000000 --- a/ariane/src/display/video_fb.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * (C) Copyright 1997-2002 ELTEC Elektronik AG - * Frank Gottschling - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _VIDEO_FB_H_ -#define _VIDEO_FB_H_ - -#define CONSOLE_BG_COL 0x00 -#define CONSOLE_FG_COL 0xa0 - -/* Try using the small font */ -#define CONFIG_VIDEO_FONT_SMALL - -/* - * Graphic Data Format (GDF) bits for VIDEO_DATA_FORMAT - */ -#define GDF__8BIT_INDEX 0 -#define GDF_15BIT_555RGB 1 -#define GDF_16BIT_565RGB 2 -#define GDF_32BIT_X888RGB 3 -#define GDF_24BIT_888RGB 4 -#define GDF__8BIT_332RGB 5 - -#define CONFIG_VIDEO_FB_LITTLE_ENDIAN -#define CONFIG_VIDEO_VISIBLE_COLS 720 -#define CONFIG_VIDEO_VISIBLE_ROWS 1280 -#define CONFIG_VIDEO_COLS 768 -#define CONFIG_VIDEO_PIXEL_SIZE 4 -#define CONFIG_VIDEO_DATA_FORMAT GDF_32BIT_X888RGB /* BGR actually, but w/e */ - -int video_get_col(void); -int video_get_row(void); -void video_reposition(int row, int col); -void video_clear_line(); - -int video_init(void *fb); -int video_resume(void *fb, int row, int col); -void video_puts(const char *s); - -#endif /*_VIDEO_FB_H_ */ diff --git a/ariane/src/display/video_font_large.h b/ariane/src/display/video_font_large.h deleted file mode 100644 index 7bb504e..0000000 --- a/ariane/src/display/video_font_large.h +++ /dev/null @@ -1,6181 +0,0 @@ -/* - * (C) Copyright 2014 - * Andrey Warkentin - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _VIDEO_FONT_LARGE_ -#define _VIDEO_FONT_LARGE_ - -#define FONTDATAMAX 11264 - -#define VIDEO_FONT_CHARS 256 -#define VIDEO_FONT_WIDTH 12 -#define VIDEO_FONT_HEIGHT 22 -#define VIDEO_FONT_SIZE (VIDEO_FONT_CHARS * VIDEO_FONT_HEIGHT) - -static unsigned char video_fontdata[FONTDATAMAX] = { - - /* 0 0x00 '^@' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 1 0x01 '^A' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x30, 0x60, /* 001100000110 */ - 0x65, 0x30, /* 011001010011 */ - 0x6d, 0xb0, /* 011011011011 */ - 0x60, 0x30, /* 011000000011 */ - 0x62, 0x30, /* 011000100011 */ - 0x62, 0x30, /* 011000100011 */ - 0x60, 0x30, /* 011000000011 */ - 0x6f, 0xb0, /* 011011111011 */ - 0x67, 0x30, /* 011001110011 */ - 0x30, 0x60, /* 001100000110 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 2 0x02 '^B' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x7a, 0xf0, /* 011110101111 */ - 0x72, 0x70, /* 011100100111 */ - 0x7f, 0xf0, /* 011111111111 */ - 0x7d, 0xf0, /* 011111011111 */ - 0x7d, 0xf0, /* 011111011111 */ - 0x7f, 0xf0, /* 011111111111 */ - 0x70, 0x70, /* 011100000111 */ - 0x78, 0xf0, /* 011110001111 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 3 0x03 '^C' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 4 0x04 '^D' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x0f, 0x80, /* 000011111000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x07, 0x00, /* 000001110000 */ - 0x02, 0x00, /* 000000100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 5 0x05 '^E' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x07, 0x00, /* 000001110000 */ - 0x02, 0x00, /* 000000100000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x1a, 0xc0, /* 000110101100 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 6 0x06 '^F' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x36, 0xc0, /* 001101101100 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 7 0x07 '^G' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 8 0x08 '^H' */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xf9, 0xf0, /* 111110011111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xe0, 0x70, /* 111000000111 */ - 0xe0, 0x70, /* 111000000111 */ - 0xc0, 0x30, /* 110000000011 */ - 0xc0, 0x30, /* 110000000011 */ - 0xe0, 0x70, /* 111000000111 */ - 0xe0, 0x70, /* 111000000111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf9, 0xf0, /* 111110011111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - - /* 9 0x09 '^I' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 10 0x0a '^J' */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xf9, 0xf0, /* 111110011111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xe6, 0x70, /* 111001100111 */ - 0xe6, 0x70, /* 111001100111 */ - 0xcf, 0x30, /* 110011110011 */ - 0xcf, 0x30, /* 110011110011 */ - 0xe6, 0x70, /* 111001100111 */ - 0xe6, 0x70, /* 111001100111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf0, 0xf0, /* 111100001111 */ - 0xf9, 0xf0, /* 111110011111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - - /* 11 0x0b '^K' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x01, 0xe0, /* 000000011110 */ - 0x03, 0x60, /* 000000110110 */ - 0x06, 0x60, /* 000001100110 */ - 0x1e, 0x00, /* 000111100000 */ - 0x33, 0x00, /* 001100110000 */ - 0x33, 0x00, /* 001100110000 */ - 0x61, 0x80, /* 011000011000 */ - 0x61, 0x80, /* 011000011000 */ - 0x33, 0x00, /* 001100110000 */ - 0x33, 0x00, /* 001100110000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 12 0x0c '^L' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 13 0x0d '^M' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x0c, 0x60, /* 000011000110 */ - 0x0c, 0x60, /* 000011000110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x3c, 0x00, /* 001111000000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 14 0x0e '^N' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x19, 0xe0, /* 000110011110 */ - 0x1b, 0xe0, /* 000110111110 */ - 0x1b, 0xc0, /* 000110111100 */ - 0x79, 0x80, /* 011110011000 */ - 0xf8, 0x00, /* 111110000000 */ - 0xf0, 0x00, /* 111100000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 15 0x0f '^O' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x0d, 0x80, /* 000011011000 */ - 0x6d, 0xb0, /* 011011011011 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x6d, 0xb0, /* 011011011011 */ - 0x0d, 0x80, /* 000011011000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 16 0x10 '^P' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x20, /* 000000000010 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x01, 0xe0, /* 000000011110 */ - 0x03, 0xe0, /* 000000111110 */ - 0x07, 0xe0, /* 000001111110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x07, 0xe0, /* 000001111110 */ - 0x03, 0xe0, /* 000000111110 */ - 0x01, 0xe0, /* 000000011110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x20, /* 000000000010 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 17 0x11 '^Q' */ - 0x00, 0x00, /* 000000000000 */ - 0x40, 0x00, /* 010000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x7e, 0x00, /* 011111100000 */ - 0x7f, 0x00, /* 011111110000 */ - 0x7f, 0x80, /* 011111111000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x7f, 0x80, /* 011111111000 */ - 0x7f, 0x00, /* 011111110000 */ - 0x7e, 0x00, /* 011111100000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x40, 0x00, /* 010000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 18 0x12 '^R' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 19 0x13 '^S' */ - 0x00, 0x00, /* 000000000000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 20 0x14 '^T' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xf0, /* 000111111111 */ - 0x3c, 0xc0, /* 001111001100 */ - 0x7c, 0xc0, /* 011111001100 */ - 0x7c, 0xc0, /* 011111001100 */ - 0x7c, 0xc0, /* 011111001100 */ - 0x3c, 0xc0, /* 001111001100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x1c, 0xe0, /* 000111001110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 21 0x15 '^U' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 22 0x16 '^V' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 23 0x17 '^W' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 24 0x18 '^X' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 25 0x19 '^Y' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 26 0x1a '^Z' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x08, 0x00, /* 000010000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0xff, 0xe0, /* 111111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x38, 0x00, /* 001110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x08, 0x00, /* 000010000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 27 0x1b '^[' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x00, /* 000000010000 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xf0, /* 011111111111 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x01, 0xc0, /* 000000011100 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x00, /* 000000010000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 28 0x1c '^\' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 29 0x1d '^]' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x09, 0x00, /* 000010010000 */ - 0x19, 0x80, /* 000110011000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x7f, 0xe0, /* 011111111110 */ - 0xff, 0xf0, /* 111111111111 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x39, 0xc0, /* 001110011100 */ - 0x19, 0x80, /* 000110011000 */ - 0x09, 0x00, /* 000010010000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 30 0x1e '^^' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 31 0x1f '^_' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 32 0x20 ' ' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 33 0x21 '!' */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 34 0x22 '"' */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 35 0x23 '#' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x30, /* 000000110011 */ - 0x03, 0x30, /* 000000110011 */ - 0x03, 0x30, /* 000000110011 */ - 0x06, 0x60, /* 000001100110 */ - 0x1f, 0xf0, /* 000111111111 */ - 0x1f, 0xf0, /* 000111111111 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x33, 0x00, /* 001100110000 */ - 0x66, 0x00, /* 011001100000 */ - 0x66, 0x00, /* 011001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 36 0x24 '$' */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x66, 0xe0, /* 011001101110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x00, /* 011001100000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x07, 0xc0, /* 000001111100 */ - 0x06, 0x60, /* 000001100110 */ - 0x06, 0x60, /* 000001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 37 0x25 '%' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x38, 0xc0, /* 001110001100 */ - 0x4c, 0xc0, /* 010011001100 */ - 0x45, 0x80, /* 010001011000 */ - 0x65, 0x80, /* 011001011000 */ - 0x3b, 0x00, /* 001110110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0d, 0xc0, /* 000011011100 */ - 0x1a, 0x60, /* 000110100110 */ - 0x1a, 0x20, /* 000110100010 */ - 0x33, 0x20, /* 001100110010 */ - 0x31, 0xc0, /* 001100011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 38 0x26 '&' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x0f, 0x80, /* 000011111000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x77, 0x00, /* 011101110000 */ - 0x63, 0x60, /* 011000110110 */ - 0x61, 0xe0, /* 011000011110 */ - 0x61, 0xc0, /* 011000011100 */ - 0x61, 0x80, /* 011000011000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 39 0x27 ''' */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 40 0x28 '(' */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0x80, /* 000000011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 41 0x29 ')' */ - 0x00, 0x00, /* 000000000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 42 0x2a '*' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x66, 0x60, /* 011001100110 */ - 0x76, 0xe0, /* 011101101110 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x76, 0xe0, /* 011101101110 */ - 0x66, 0x60, /* 011001100110 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 43 0x2b '+' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 44 0x2c ',' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 45 0x2d '-' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 46 0x2e '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 47 0x2f '/' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 48 0x30 '0' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0x80, /* 000100011000 */ - 0x10, 0xc0, /* 000100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0x80, /* 001100001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 49 0x31 '1' */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x36, 0x00, /* 001101100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 50 0x32 '2' */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x61, 0xc0, /* 011000011100 */ - 0x40, 0xc0, /* 010000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 51 0x33 '3' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x40, 0x60, /* 010000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x07, 0xc0, /* 000001111100 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0x60, 0x40, /* 011000000100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 52 0x34 '4' */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x80, /* 000000111000 */ - 0x03, 0x80, /* 000000111000 */ - 0x05, 0x80, /* 000001011000 */ - 0x05, 0x80, /* 000001011000 */ - 0x09, 0x80, /* 000010011000 */ - 0x09, 0x80, /* 000010011000 */ - 0x11, 0x80, /* 000100011000 */ - 0x11, 0x80, /* 000100011000 */ - 0x21, 0x80, /* 001000011000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 53 0x35 '5' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x10, 0x00, /* 000100000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x20, 0x00, /* 001000000000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x31, 0xc0, /* 001100011100 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 54 0x36 '6' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x67, 0x80, /* 011001111000 */ - 0x6f, 0xc0, /* 011011111100 */ - 0x70, 0xe0, /* 011100001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 55 0x37 '7' */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x60, 0x40, /* 011000000100 */ - 0x00, 0x40, /* 000000000100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0x80, /* 000000001000 */ - 0x00, 0x80, /* 000000001000 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x00, /* 000000010000 */ - 0x01, 0x00, /* 000000010000 */ - 0x03, 0x00, /* 000000110000 */ - 0x02, 0x00, /* 000000100000 */ - 0x02, 0x00, /* 000000100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 56 0x38 '8' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x11, 0x80, /* 000100011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x11, 0x80, /* 000100011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x18, 0x80, /* 000110001000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 57 0x39 '9' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0xe0, /* 011100001110 */ - 0x3f, 0x60, /* 001111110110 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x07, 0x00, /* 000001110000 */ - 0x3c, 0x00, /* 001111000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 58 0x3a ':' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 59 0x3b ';' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 60 0x3c '<' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x60, /* 000000000110 */ - 0x01, 0xc0, /* 000000011100 */ - 0x07, 0x00, /* 000001110000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 61 0x3d '=' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 62 0x3e '>' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x03, 0x80, /* 000000111000 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x03, 0x80, /* 000000111000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x38, 0x00, /* 001110000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 63 0x3f '?' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 64 0x40 '@' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x30, 0x60, /* 001100000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x67, 0x20, /* 011001110010 */ - 0x6f, 0xa0, /* 011011111010 */ - 0x6c, 0xa0, /* 011011001010 */ - 0x6c, 0xa0, /* 011011001010 */ - 0x67, 0xe0, /* 011001111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 65 0x41 'A' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x09, 0x00, /* 000010010000 */ - 0x11, 0x80, /* 000100011000 */ - 0x11, 0x80, /* 000100011000 */ - 0x10, 0x80, /* 000100001000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x20, 0x40, /* 001000000100 */ - 0x40, 0x60, /* 010000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0xf0, /* 111000001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 66 0x42 'B' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x00, /* 111111110000 */ - 0x60, 0x80, /* 011000001000 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x61, 0x80, /* 011000011000 */ - 0x7f, 0x80, /* 011111111000 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0xc0, /* 011000001100 */ - 0xff, 0x80, /* 111111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 67 0x43 'C' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x10, 0x60, /* 000100000110 */ - 0x20, 0x20, /* 001000000010 */ - 0x20, 0x00, /* 001000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x20, 0x00, /* 001000000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x18, 0x40, /* 000110000100 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 68 0x44 'D' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x00, /* 111111110000 */ - 0x61, 0xc0, /* 011000011100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x40, /* 011000000100 */ - 0x61, 0x80, /* 011000011000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 69 0x45 'E' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x80, /* 001100001000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x30, 0x80, /* 001100001000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x30, 0x20, /* 001100000010 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 70 0x46 'F' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x80, /* 001100001000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x30, 0x80, /* 001100001000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 71 0x47 'G' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x10, 0x60, /* 000100000110 */ - 0x20, 0x20, /* 001000000010 */ - 0x20, 0x00, /* 001000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x61, 0xf0, /* 011000011111 */ - 0x60, 0x60, /* 011000000110 */ - 0x20, 0x60, /* 001000000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 72 0x48 'H' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0xf0, /* 111100001111 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0xf0, 0xf0, /* 111100001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 73 0x49 'I' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 74 0x4a 'J' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 75 0x4b 'K' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0xe0, /* 111100001110 */ - 0x61, 0x80, /* 011000011000 */ - 0x63, 0x00, /* 011000110000 */ - 0x66, 0x00, /* 011001100000 */ - 0x6c, 0x00, /* 011011000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x6e, 0x00, /* 011011100000 */ - 0x67, 0x00, /* 011001110000 */ - 0x63, 0x80, /* 011000111000 */ - 0x61, 0xc0, /* 011000011100 */ - 0x60, 0xe0, /* 011000001110 */ - 0xf0, 0x70, /* 111100000111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 76 0x4c 'L' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x30, 0x20, /* 001100000010 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 77 0x4d 'M' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xe0, 0x70, /* 111000000111 */ - 0x60, 0xe0, /* 011000001110 */ - 0x70, 0xe0, /* 011100001110 */ - 0x70, 0xe0, /* 011100001110 */ - 0x70, 0xe0, /* 011100001110 */ - 0x59, 0x60, /* 010110010110 */ - 0x59, 0x60, /* 010110010110 */ - 0x59, 0x60, /* 010110010110 */ - 0x4d, 0x60, /* 010011010110 */ - 0x4e, 0x60, /* 010011100110 */ - 0x4e, 0x60, /* 010011100110 */ - 0x44, 0x60, /* 010001000110 */ - 0x44, 0x60, /* 010001000110 */ - 0xe4, 0xf0, /* 111001001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 78 0x4e 'N' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xc0, 0x70, /* 110000000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x70, 0x20, /* 011100000010 */ - 0x78, 0x20, /* 011110000010 */ - 0x58, 0x20, /* 010110000010 */ - 0x4c, 0x20, /* 010011000010 */ - 0x46, 0x20, /* 010001100010 */ - 0x47, 0x20, /* 010001110010 */ - 0x43, 0x20, /* 010000110010 */ - 0x41, 0xa0, /* 010000011010 */ - 0x40, 0xe0, /* 010000001110 */ - 0x40, 0xe0, /* 010000001110 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0x30, /* 111000000011 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 79 0x4f 'O' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x20, 0x60, /* 001000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x20, 0x40, /* 001000000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 80 0x50 'P' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0x80, /* 011111111000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x37, 0x80, /* 001101111000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 81 0x51 'Q' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x20, 0x60, /* 001000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0x40, /* 001100000100 */ - 0x38, 0x40, /* 001110000100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x23, 0x90, /* 001000111001 */ - 0x01, 0xe0, /* 000000011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 82 0x52 'R' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x00, /* 111111110000 */ - 0x61, 0x80, /* 011000011000 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0x80, /* 011000001000 */ - 0x7f, 0x00, /* 011111110000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x6e, 0x00, /* 011011100000 */ - 0x67, 0x00, /* 011001110000 */ - 0x63, 0x80, /* 011000111000 */ - 0x61, 0xc0, /* 011000011100 */ - 0x60, 0xe0, /* 011000001110 */ - 0xf0, 0x70, /* 111100000111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 83 0x53 'S' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x30, 0x60, /* 001100000110 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x70, 0x00, /* 011100000000 */ - 0x3c, 0x00, /* 001111000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x07, 0x80, /* 000001111000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x00, 0xe0, /* 000000001110 */ - 0x40, 0x60, /* 010000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0x60, 0xc0, /* 011000001100 */ - 0x7f, 0x80, /* 011111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 84 0x54 'T' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x46, 0x20, /* 010001100010 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 85 0x55 'U' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0x70, /* 111100000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x70, 0x40, /* 011100000100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 86 0x56 'V' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xe0, 0xe0, /* 111000001110 */ - 0x60, 0x40, /* 011000000100 */ - 0x30, 0x80, /* 001100001000 */ - 0x30, 0x80, /* 001100001000 */ - 0x30, 0x80, /* 001100001000 */ - 0x19, 0x00, /* 000110010000 */ - 0x19, 0x00, /* 000110010000 */ - 0x19, 0x00, /* 000110010000 */ - 0x0a, 0x00, /* 000010100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 87 0x57 'W' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xfe, 0xf0, /* 111111101111 */ - 0x66, 0x20, /* 011001100010 */ - 0x66, 0x20, /* 011001100010 */ - 0x66, 0x20, /* 011001100010 */ - 0x76, 0x20, /* 011101100010 */ - 0x77, 0x40, /* 011101110100 */ - 0x33, 0x40, /* 001100110100 */ - 0x37, 0x40, /* 001101110100 */ - 0x3b, 0xc0, /* 001110111100 */ - 0x3b, 0x80, /* 001110111000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 88 0x58 'X' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0x70, /* 111100000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x30, 0x40, /* 001100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x11, 0x80, /* 000100011000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0xf0, /* 111000001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 89 0x59 'Y' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0x70, /* 111100000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 90 0x5a 'Z' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x20, 0xc0, /* 001000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x20, /* 000110000010 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 91 0x5b '[' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 92 0x5c '\' */ - 0x00, 0x00, /* 000000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 93 0x5d ']' */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 94 0x5e '^' */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1b, 0x00, /* 000110110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x60, 0xc0, /* 011000001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 95 0x5f '_' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 96 0x60 '`' */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x00, /* 000000010000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0x80, /* 000001111000 */ - 0x07, 0x80, /* 000001111000 */ - 0x03, 0x00, /* 000000110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 97 0x61 'a' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 98 0x62 'b' */ - 0x00, 0x00, /* 000000000000 */ - 0x20, 0x00, /* 001000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0xe0, 0x00, /* 111000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x67, 0x80, /* 011001111000 */ - 0x6f, 0xc0, /* 011011111100 */ - 0x70, 0xe0, /* 011100001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x60, /* 011100000110 */ - 0x78, 0xc0, /* 011110001100 */ - 0x4f, 0x80, /* 010011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 99 0x63 'c' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x31, 0xc0, /* 001100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x70, 0x40, /* 011100000100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 100 0x64 'd' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x0f, 0x60, /* 000011110110 */ - 0x31, 0xe0, /* 001100011110 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0xe0, /* 011100001110 */ - 0x39, 0x60, /* 001110010110 */ - 0x1e, 0x70, /* 000111100111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 101 0x65 'e' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 102 0x66 'f' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x80, /* 000000111000 */ - 0x04, 0xc0, /* 000001001100 */ - 0x04, 0xc0, /* 000001001100 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 103 0x67 'g' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x20, /* 000111110010 */ - 0x31, 0xe0, /* 001100011110 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x31, 0x80, /* 001100011000 */ - 0x3f, 0x00, /* 001111110000 */ - 0x60, 0x00, /* 011000000000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x20, 0x60, /* 001000000110 */ - 0x40, 0x20, /* 010000000010 */ - 0x40, 0x20, /* 010000000010 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 104 0x68 'h' */ - 0x00, 0x00, /* 000000000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x37, 0x80, /* 001101111000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x79, 0xe0, /* 011110011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 105 0x69 'i' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 106 0x6a 'j' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0xc0, /* 000000111100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 107 0x6b 'k' */ - 0x00, 0x00, /* 000000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0xe0, 0x00, /* 111000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x61, 0xc0, /* 011000011100 */ - 0x63, 0x00, /* 011000110000 */ - 0x66, 0x00, /* 011001100000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x7c, 0x00, /* 011111000000 */ - 0x6e, 0x00, /* 011011100000 */ - 0x67, 0x00, /* 011001110000 */ - 0x63, 0x80, /* 011000111000 */ - 0xf1, 0xe0, /* 111100011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 108 0x6c 'l' */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 109 0x6d 'm' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xdd, 0xc0, /* 110111011100 */ - 0x6e, 0xe0, /* 011011101110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0xef, 0x70, /* 111011110111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 110 0x6e 'n' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x27, 0x80, /* 001001111000 */ - 0x79, 0xc0, /* 011110011100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x79, 0xe0, /* 011110011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 111 0x6f 'o' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 112 0x70 'p' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xef, 0x80, /* 111011111000 */ - 0x71, 0xc0, /* 011100011100 */ - 0x60, 0xe0, /* 011000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x40, /* 011000000100 */ - 0x70, 0x80, /* 011100001000 */ - 0x7f, 0x00, /* 011111110000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0xf0, 0x00, /* 111100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 113 0x71 'q' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x20, /* 000011110010 */ - 0x11, 0xe0, /* 000100011110 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x60, /* 011100000110 */ - 0x38, 0xe0, /* 001110001110 */ - 0x1f, 0xe0, /* 000111111110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0xf0, /* 000000001111 */ - 0x00, 0x00, /* 000000000000 */ - - /* 114 0x72 'r' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x73, 0x80, /* 011100111000 */ - 0x34, 0xc0, /* 001101001100 */ - 0x38, 0xc0, /* 001110001100 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 115 0x73 's' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0x40, /* 001100000100 */ - 0x38, 0x00, /* 001110000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x07, 0x80, /* 000001111000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x3f, 0x80, /* 001111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 116 0x74 't' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x20, /* 000011000010 */ - 0x0e, 0x40, /* 000011100100 */ - 0x07, 0x80, /* 000001111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 117 0x75 'u' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x79, 0xe0, /* 011110011110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 118 0x76 'v' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0x70, /* 111100000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 119 0x77 'w' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x70, /* 111111110111 */ - 0x66, 0x20, /* 011001100010 */ - 0x66, 0x20, /* 011001100010 */ - 0x66, 0x20, /* 011001100010 */ - 0x37, 0x40, /* 001101110100 */ - 0x3b, 0x40, /* 001110110100 */ - 0x3b, 0x40, /* 001110110100 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 120 0x78 'x' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf8, 0xf0, /* 111110001111 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1d, 0x00, /* 000111010000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0b, 0x80, /* 000010111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0xf1, 0xf0, /* 111100011111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 121 0x79 'y' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0xf0, /* 111100001111 */ - 0x60, 0x20, /* 011000000010 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x08, 0x00, /* 000010000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 122 0x7a 'z' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0xe0, /* 011000001110 */ - 0x41, 0xc0, /* 010000011100 */ - 0x03, 0x80, /* 000000111000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x38, 0x20, /* 001110000010 */ - 0x70, 0x60, /* 011100000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 123 0x7b '{' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x80, /* 000000111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x80, /* 000000111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 124 0x7c '|' */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 125 0x7d '}' */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 126 0x7e '~' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x20, /* 000111000010 */ - 0x3e, 0x60, /* 001111100110 */ - 0x67, 0xc0, /* 011001111100 */ - 0x43, 0x80, /* 010000111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 127 0x7f '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - - /* 128 0x80 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xc0, /* 000011111100 */ - 0x10, 0x60, /* 000100000110 */ - 0x20, 0x20, /* 001000000010 */ - 0x20, 0x00, /* 001000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x20, 0x00, /* 001000000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x18, 0x40, /* 000110000100 */ - 0x0f, 0x80, /* 000011111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0x80, /* 000000011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 129 0x81 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x79, 0xe0, /* 011110011110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 130 0x82 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 131 0x83 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 132 0x84 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 133 0x85 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 134 0x86 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x07, 0x00, /* 000001110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 135 0x87 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x31, 0xc0, /* 001100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x70, 0x40, /* 011100000100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0x80, /* 000000011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 136 0x88 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 137 0x89 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 138 0x8a '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x00, /* 011000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x60, /* 000110000110 */ - 0x0f, 0x80, /* 000011111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 139 0x8b '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 140 0x8c '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x1b, 0x00, /* 000110110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 141 0x8d '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 142 0x8e '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x04, 0x00, /* 000001000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x11, 0x80, /* 000100011000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0xf0, /* 111000001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 143 0x8f '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x04, 0x00, /* 000001000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x11, 0x80, /* 000100011000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0xf0, /* 111000001111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 144 0x90 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x08, 0x00, /* 000010000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x30, 0x20, /* 001100000010 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x80, /* 001100001000 */ - 0x3f, 0x80, /* 001111111000 */ - 0x30, 0x80, /* 001100001000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x20, /* 001100000010 */ - 0x30, 0x20, /* 001100000010 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 145 0x91 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x66, 0x30, /* 011001100011 */ - 0x46, 0x30, /* 010001100011 */ - 0x06, 0x30, /* 000001100011 */ - 0x3f, 0xf0, /* 001111111111 */ - 0x66, 0x00, /* 011001100000 */ - 0xc6, 0x00, /* 110001100000 */ - 0xc6, 0x00, /* 110001100000 */ - 0xe7, 0x30, /* 111001110011 */ - 0x7d, 0xe0, /* 011111011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 146 0x92 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0xf0, /* 000000111111 */ - 0x07, 0x10, /* 000001110001 */ - 0x07, 0x10, /* 000001110001 */ - 0x0b, 0x00, /* 000010110000 */ - 0x0b, 0x00, /* 000010110000 */ - 0x0b, 0x20, /* 000010110010 */ - 0x13, 0xe0, /* 000100111110 */ - 0x13, 0x20, /* 000100110010 */ - 0x3f, 0x00, /* 001111110000 */ - 0x23, 0x00, /* 001000110000 */ - 0x23, 0x00, /* 001000110000 */ - 0x43, 0x10, /* 010000110001 */ - 0x43, 0x10, /* 010000110001 */ - 0xe7, 0xf0, /* 111001111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 147 0x93 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 148 0x94 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 149 0x95 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 150 0x96 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x02, 0x00, /* 000000100000 */ - 0x07, 0x00, /* 000001110000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x79, 0xe0, /* 011110011110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 151 0x97 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x79, 0xe0, /* 011110011110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 152 0x98 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xf0, 0xf0, /* 111100001111 */ - 0x60, 0x20, /* 011000000010 */ - 0x30, 0x40, /* 001100000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x18, 0x80, /* 000110001000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x0d, 0x00, /* 000011010000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x04, 0x00, /* 000001000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x08, 0x00, /* 000010000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 153 0x99 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xc0, /* 001000001100 */ - 0x20, 0x60, /* 001000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x20, 0x40, /* 001000000100 */ - 0x30, 0x40, /* 001100000100 */ - 0x18, 0x80, /* 000110001000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 154 0x9a '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0xe0, 0x30, /* 111000000011 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x60, 0x20, /* 011000000010 */ - 0x70, 0x40, /* 011100000100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 155 0x9b '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x36, 0xc0, /* 001101101100 */ - 0x26, 0xc0, /* 001001101100 */ - 0x66, 0x00, /* 011001100000 */ - 0x66, 0x00, /* 011001100000 */ - 0x66, 0x00, /* 011001100000 */ - 0x66, 0x00, /* 011001100000 */ - 0x76, 0x40, /* 011101100100 */ - 0x36, 0xc0, /* 001101101100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 156 0x9c '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x7e, 0x00, /* 011111100000 */ - 0x7e, 0x00, /* 011111100000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x3e, 0x20, /* 001111100010 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x61, 0xc0, /* 011000011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 157 0x9d '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 158 0x9e '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0x80, /* 011111111000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x37, 0x80, /* 001101111000 */ - 0x30, 0x00, /* 001100000000 */ - 0x33, 0x00, /* 001100110000 */ - 0x37, 0x80, /* 001101111000 */ - 0x33, 0x00, /* 001100110000 */ - 0x33, 0x00, /* 001100110000 */ - 0x33, 0x30, /* 001100110011 */ - 0x31, 0xe0, /* 001100011110 */ - 0x78, 0xc0, /* 011110001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 159 0x9f '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0xe0, /* 000000011110 */ - 0x03, 0x30, /* 000000110011 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x7f, 0xc0, /* 011111111100 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xcc, 0x00, /* 110011000000 */ - 0x78, 0x00, /* 011110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 160 0xa0 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x18, 0xc0, /* 000110001100 */ - 0x10, 0xc0, /* 000100001100 */ - 0x03, 0xc0, /* 000000111100 */ - 0x1c, 0xc0, /* 000111001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0xe0, /* 000111101110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 161 0xa1 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 162 0xa2 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 163 0xa3 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0x80, /* 000000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x79, 0xe0, /* 011110011110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1e, 0x60, /* 000111100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 164 0xa4 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x40, /* 000111000100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x23, 0x80, /* 001000111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x27, 0x80, /* 001001111000 */ - 0x79, 0xc0, /* 011110011100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x79, 0xe0, /* 011110011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 165 0xa5 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x40, /* 000111000100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x23, 0x80, /* 001000111000 */ - 0xc0, 0x70, /* 110000000111 */ - 0x60, 0x20, /* 011000000010 */ - 0x70, 0x20, /* 011100000010 */ - 0x78, 0x20, /* 011110000010 */ - 0x5c, 0x20, /* 010111000010 */ - 0x4e, 0x20, /* 010011100010 */ - 0x47, 0x20, /* 010001110010 */ - 0x43, 0xa0, /* 010000111010 */ - 0x41, 0xe0, /* 010000011110 */ - 0x40, 0xe0, /* 010000001110 */ - 0x40, 0x60, /* 010000000110 */ - 0xe0, 0x30, /* 111000000011 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 166 0xa6 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x07, 0x80, /* 000001111000 */ - 0x19, 0x80, /* 000110011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x31, 0x80, /* 001100011000 */ - 0x33, 0x80, /* 001100111000 */ - 0x1d, 0xc0, /* 000111011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 167 0xa7 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x10, 0xc0, /* 000100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0x80, /* 001100001000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 168 0xa8 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x40, /* 001100000100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 169 0xa9 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 170 0xaa '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 171 0xab '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x10, 0x40, /* 000100000100 */ - 0x10, 0x80, /* 000100001000 */ - 0x11, 0x00, /* 000100010000 */ - 0x3a, 0x00, /* 001110100000 */ - 0x05, 0xc0, /* 000001011100 */ - 0x0a, 0x20, /* 000010100010 */ - 0x10, 0x20, /* 000100000010 */ - 0x20, 0xc0, /* 001000001100 */ - 0x41, 0x00, /* 010000010000 */ - 0x02, 0x00, /* 000000100000 */ - 0x03, 0xe0, /* 000000111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 172 0xac '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x10, 0x00, /* 000100000000 */ - 0x10, 0x40, /* 000100000100 */ - 0x10, 0x80, /* 000100001000 */ - 0x11, 0x00, /* 000100010000 */ - 0x3a, 0x40, /* 001110100100 */ - 0x04, 0xc0, /* 000001001100 */ - 0x09, 0x40, /* 000010010100 */ - 0x12, 0x40, /* 000100100100 */ - 0x24, 0x40, /* 001001000100 */ - 0x47, 0xe0, /* 010001111110 */ - 0x00, 0x40, /* 000000000100 */ - 0x00, 0x40, /* 000000000100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 173 0xad '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 174 0xae '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x60, /* 000001100110 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x33, 0x00, /* 001100110000 */ - 0x66, 0x00, /* 011001100000 */ - 0x33, 0x00, /* 001100110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x06, 0x60, /* 000001100110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 175 0xaf '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x66, 0x00, /* 011001100000 */ - 0x33, 0x00, /* 001100110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x06, 0x60, /* 000001100110 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x33, 0x00, /* 001100110000 */ - 0x66, 0x00, /* 011001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 176 0xb0 '.' */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - 0x61, 0x80, /* 011000011000 */ - 0x20, 0x80, /* 001000001000 */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - 0x61, 0x80, /* 011000011000 */ - 0x20, 0x80, /* 001000001000 */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - 0x61, 0x80, /* 011000011000 */ - 0x20, 0x80, /* 001000001000 */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - 0x61, 0x80, /* 011000011000 */ - 0x20, 0x80, /* 001000001000 */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - 0x61, 0x80, /* 011000011000 */ - 0x20, 0x80, /* 001000001000 */ - 0x0c, 0x30, /* 000011000011 */ - 0x08, 0x20, /* 000010000010 */ - - /* 177 0xb1 '.' */ - 0x77, 0x70, /* 011101110111 */ - 0x22, 0x20, /* 001000100010 */ - 0x88, 0x80, /* 100010001000 */ - 0xdd, 0xd0, /* 110111011101 */ - 0x88, 0x80, /* 100010001000 */ - 0x22, 0x20, /* 001000100010 */ - 0x77, 0x70, /* 011101110111 */ - 0x22, 0x20, /* 001000100010 */ - 0x88, 0x80, /* 100010001000 */ - 0xdd, 0xd0, /* 110111011101 */ - 0x88, 0x80, /* 100010001000 */ - 0x22, 0x20, /* 001000100010 */ - 0x77, 0x70, /* 011101110111 */ - 0x22, 0x20, /* 001000100010 */ - 0x88, 0x80, /* 100010001000 */ - 0xdd, 0xd0, /* 110111011101 */ - 0x88, 0x80, /* 100010001000 */ - 0x22, 0x20, /* 001000100010 */ - 0x77, 0x70, /* 011101110111 */ - 0x22, 0x20, /* 001000100010 */ - 0x88, 0x80, /* 100010001000 */ - 0xdd, 0xd0, /* 110111011101 */ - - /* 178 0xb2 '.' */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - 0x9e, 0x70, /* 100111100111 */ - 0xdf, 0x70, /* 110111110111 */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - 0x9e, 0x70, /* 100111100111 */ - 0xdf, 0x70, /* 110111110111 */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - 0x9e, 0x70, /* 100111100111 */ - 0xdf, 0x70, /* 110111110111 */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - 0x9e, 0x70, /* 100111100111 */ - 0xdf, 0x70, /* 110111110111 */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - 0x9e, 0x70, /* 100111100111 */ - 0xdf, 0x70, /* 110111110111 */ - 0xf3, 0xc0, /* 111100111100 */ - 0xf7, 0xd0, /* 111101111101 */ - - /* 179 0xb3 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 180 0xb4 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 181 0xb5 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 182 0xb6 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 183 0xb7 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x80, /* 111111111000 */ - 0xff, 0x80, /* 111111111000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 184 0xb8 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 185 0xb9 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0x01, 0x80, /* 000000011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 186 0xba '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 187 0xbb '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0x80, /* 111111111000 */ - 0xff, 0x80, /* 111111111000 */ - 0x01, 0x80, /* 000000011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 188 0xbc '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0xfd, 0x80, /* 111111011000 */ - 0x01, 0x80, /* 000000011000 */ - 0xff, 0x80, /* 111111111000 */ - 0xff, 0x80, /* 111111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 189 0xbd '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xff, 0x80, /* 111111111000 */ - 0xff, 0x80, /* 111111111000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 190 0xbe '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 191 0xbf '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 192 0xc0 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 193 0xc1 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 194 0xc2 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 195 0xc3 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 196 0xc4 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 197 0xc5 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 198 0xc6 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 199 0xc7 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 200 0xc8 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 201 0xc9 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 202 0xca '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xfd, 0xf0, /* 111111011111 */ - 0xfd, 0xf0, /* 111111011111 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 203 0xcb '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0xfd, 0xf0, /* 111111011111 */ - 0xfd, 0xf0, /* 111111011111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 204 0xcc '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0xf0, /* 000011011111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 205 0xcd '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 206 0xce '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xfd, 0xf0, /* 111111011111 */ - 0xfd, 0xf0, /* 111111011111 */ - 0x00, 0x00, /* 000000000000 */ - 0xfd, 0xf0, /* 111111011111 */ - 0xfd, 0xf0, /* 111111011111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 207 0xcf '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 208 0xd0 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 209 0xd1 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 210 0xd2 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 211 0xd3 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 212 0xd4 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 213 0xd5 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 214 0xd6 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0f, 0xf0, /* 000011111111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 215 0xd7 '.' */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - 0x0d, 0x80, /* 000011011000 */ - - /* 216 0xd8 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x06, 0x00, /* 000001100000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 217 0xd9 '.' */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0xfe, 0x00, /* 111111100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 218 0xda '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0xf0, /* 000001111111 */ - 0x07, 0xf0, /* 000001111111 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - - /* 219 0xdb '.' */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - - /* 220 0xdc '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - - /* 221 0xdd '.' */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - 0xfc, 0x00, /* 111111000000 */ - - /* 222 0xde '.' */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - 0x03, 0xf0, /* 000000111111 */ - - /* 223 0xdf '.' */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0xff, 0xf0, /* 111111111111 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 224 0xe0 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x60, /* 000011110110 */ - 0x13, 0xe0, /* 000100111110 */ - 0x21, 0xc0, /* 001000011100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x70, 0x80, /* 011100001000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x1f, 0x60, /* 000111110110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 225 0xe1 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x31, 0x80, /* 001100011000 */ - 0x37, 0x80, /* 001101111000 */ - 0x31, 0x80, /* 001100011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x31, 0x80, /* 001100011000 */ - 0x77, 0x00, /* 011101110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 226 0xe2 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x3f, 0xe0, /* 001111111110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 227 0xe3 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 228 0xe4 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0x60, /* 001100000110 */ - 0x30, 0x00, /* 001100000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x60, /* 001100000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 229 0xe5 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0xe0, /* 000001111110 */ - 0x0f, 0xe0, /* 000011111110 */ - 0x13, 0x80, /* 000100111000 */ - 0x21, 0xc0, /* 001000011100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x60, 0xc0, /* 011000001100 */ - 0x70, 0x80, /* 011100001000 */ - 0x39, 0x00, /* 001110010000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 230 0xe6 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x39, 0xc0, /* 001110011100 */ - 0x36, 0xe0, /* 001101101110 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 231 0xe7 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x19, 0x80, /* 000110011000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x66, 0x60, /* 011001100110 */ - 0x66, 0x60, /* 011001100110 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 232 0xe8 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 233 0xe9 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x1f, 0x80, /* 000111111000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 234 0xea '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x31, 0x80, /* 001100011000 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0xd9, 0xb0, /* 110110011011 */ - 0x79, 0xe0, /* 011110011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 235 0xeb '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0x80, /* 000001111000 */ - 0x0c, 0xc0, /* 000011001100 */ - 0x18, 0x60, /* 000110000110 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x0f, 0x80, /* 000011111000 */ - 0x11, 0xc0, /* 000100011100 */ - 0x20, 0xe0, /* 001000001110 */ - 0x60, 0x60, /* 011000000110 */ - 0x60, 0x60, /* 011000000110 */ - 0x70, 0x40, /* 011100000100 */ - 0x38, 0x80, /* 001110001000 */ - 0x1f, 0x00, /* 000111110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 236 0xec '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x6f, 0x60, /* 011011110110 */ - 0x66, 0x60, /* 011001100110 */ - 0xc6, 0x30, /* 110001100011 */ - 0xc6, 0x30, /* 110001100011 */ - 0x66, 0x60, /* 011001100110 */ - 0x6f, 0x60, /* 011011110110 */ - 0x39, 0xc0, /* 001110011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 237 0xed '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0xc0, /* 000000001100 */ - 0x00, 0xc0, /* 000000001100 */ - 0x01, 0x80, /* 000000011000 */ - 0x01, 0x80, /* 000000011000 */ - 0x3b, 0xc0, /* 001110111100 */ - 0x6f, 0x60, /* 011011110110 */ - 0x66, 0x60, /* 011001100110 */ - 0xc6, 0x30, /* 110001100011 */ - 0xc6, 0x30, /* 110001100011 */ - 0x66, 0x60, /* 011001100110 */ - 0x6f, 0x60, /* 011011110110 */ - 0x3d, 0xc0, /* 001111011100 */ - 0x18, 0x00, /* 000110000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x30, 0x00, /* 001100000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 238 0xee '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x1f, 0xc0, /* 000111111100 */ - 0x18, 0x00, /* 000110000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x03, 0x00, /* 000000110000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 239 0xef '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x39, 0xc0, /* 001110011100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x30, 0xc0, /* 001100001100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 240 0xf0 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 241 0xf1 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 242 0xf2 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x03, 0x80, /* 000000111000 */ - 0x00, 0xe0, /* 000000001110 */ - 0x00, 0xe0, /* 000000001110 */ - 0x03, 0x80, /* 000000111000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x38, 0x00, /* 001110000000 */ - 0x60, 0x00, /* 011000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 243 0xf3 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x60, /* 000000000110 */ - 0x01, 0xc0, /* 000000011100 */ - 0x07, 0x00, /* 000001110000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x70, 0x00, /* 011100000000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x07, 0x00, /* 000001110000 */ - 0x01, 0xc0, /* 000000011100 */ - 0x00, 0x60, /* 000000000110 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 244 0xf4 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x03, 0x80, /* 000000111000 */ - 0x07, 0xc0, /* 000001111100 */ - 0x0c, 0x60, /* 000011000110 */ - 0x0c, 0x60, /* 000011000110 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x0c, 0x00, /* 000011000000 */ - - /* 245 0xf5 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x63, 0x00, /* 011000110000 */ - 0x63, 0x00, /* 011000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - 0x03, 0x00, /* 000000110000 */ - - /* 246 0xf6 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x7f, 0xe0, /* 011111111110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 247 0xf7 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x38, 0x00, /* 001110000000 */ - 0x6c, 0x00, /* 011011000000 */ - 0x06, 0x30, /* 000001100011 */ - 0x03, 0x60, /* 000000110110 */ - 0x39, 0xc0, /* 001110011100 */ - 0x6c, 0x00, /* 011011000000 */ - 0x06, 0x30, /* 000001100011 */ - 0x03, 0x60, /* 000000110110 */ - 0x01, 0xc0, /* 000000011100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 248 0xf8 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x19, 0x80, /* 000110011000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 249 0xf9 '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x3e, 0x00, /* 001111100000 */ - 0x1c, 0x00, /* 000111000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 250 0xfa '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x3c, 0x00, /* 001111000000 */ - 0x3c, 0x00, /* 001111000000 */ - 0x18, 0x00, /* 000110000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 251 0xfb '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x07, 0xe0, /* 000001111110 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x06, 0x00, /* 000001100000 */ - 0xc6, 0x00, /* 110001100000 */ - 0x66, 0x00, /* 011001100000 */ - 0x36, 0x00, /* 001101100000 */ - 0x1e, 0x00, /* 000111100000 */ - 0x0e, 0x00, /* 000011100000 */ - 0x06, 0x00, /* 000001100000 */ - 0x02, 0x00, /* 000000100000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 252 0xfc '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x13, 0x80, /* 000100111000 */ - 0x3d, 0xc0, /* 001111011100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x18, 0xc0, /* 000110001100 */ - 0x3d, 0xe0, /* 001111011110 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 253 0xfd '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x1f, 0x80, /* 000111111000 */ - 0x31, 0x80, /* 001100011000 */ - 0x21, 0x80, /* 001000011000 */ - 0x03, 0x00, /* 000000110000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0c, 0x00, /* 000011000000 */ - 0x18, 0x40, /* 000110000100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 254 0xfe '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 255 0xff '.' */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ -}; - -#endif /* _VIDEO_FONT_LARGE_ */ diff --git a/ariane/src/display/video_font_small.h b/ariane/src/display/video_font_small.h deleted file mode 100644 index 2c658fe..0000000 --- a/ariane/src/display/video_font_small.h +++ /dev/null @@ -1,4630 +0,0 @@ -/* - * (C) Copyright 2000 - * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it - * - * SPDX-License-Identifier: GPL-2.0+ - * - * This file contains an 8x16 bitmap font for code page 437. - */ - -#ifndef _VIDEO_FONT_DATA_ -#define _VIDEO_FONT_DATA_ - -#define VIDEO_FONT_CHARS 256 -#define VIDEO_FONT_WIDTH 8 -#define VIDEO_FONT_HEIGHT 16 -#define VIDEO_FONT_SIZE (VIDEO_FONT_CHARS * VIDEO_FONT_HEIGHT) - -static unsigned char video_fontdata[VIDEO_FONT_SIZE] = { - - /* 0 0x00 '^@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 1 0x01 '^A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x81, /* 10000001 */ - 0xa5, /* 10100101 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 2 0x02 '^B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xdb, /* 11011011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 3 0x03 '^C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 4 0x04 '^D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 5 0x05 '^E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 6 0x06 '^F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 7 0x07 '^G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 8 0x08 '^H' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xe7, /* 11100111 */ - 0xc3, /* 11000011 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 9 0x09 '^I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x42, /* 01000010 */ - 0x42, /* 01000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 10 0x0a '^J' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0x99, /* 10011001 */ - 0xbd, /* 10111101 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0xc3, /* 11000011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 11 0x0b '^K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x1a, /* 00011010 */ - 0x32, /* 00110010 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 12 0x0c '^L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 13 0x0d '^M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x33, /* 00110011 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x70, /* 01110000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 14 0x0e '^N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x67, /* 01100111 */ - 0xe7, /* 11100111 */ - 0xe6, /* 11100110 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 15 0x0f '^O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xdb, /* 11011011 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0x3c, /* 00111100 */ - 0xdb, /* 11011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 16 0x10 '^P' */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0xf0, /* 11110000 */ - 0xf8, /* 11111000 */ - 0xfe, /* 11111110 */ - 0xf8, /* 11111000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 17 0x11 '^Q' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0e, /* 00001110 */ - 0x1e, /* 00011110 */ - 0x3e, /* 00111110 */ - 0xfe, /* 11111110 */ - 0x3e, /* 00111110 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 18 0x12 '^R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 19 0x13 '^S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 20 0x14 '^T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7b, /* 01111011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 21 0x15 '^U' */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 22 0x16 '^V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 23 0x17 '^W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 24 0x18 '^X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 25 0x19 '^Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 26 0x1a '^Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 27 0x1b '^[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xfe, /* 11111110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 28 0x1c '^\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 29 0x1d '^]' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x28, /* 00101000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x28, /* 00101000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 30 0x1e '^^' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 31 0x1f '^_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 32 0x20 ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 33 0x21 '!' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 34 0x22 '"' */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x24, /* 00100100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 35 0x23 '#' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 36 0x24 '$' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x86, /* 10000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 37 0x25 '%' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 38 0x26 '&' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 39 0x27 ''' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 40 0x28 '(' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 41 0x29 ')' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 42 0x2a '*' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0xff, /* 11111111 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 43 0x2b '+' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 44 0x2c ',' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 45 0x2d '-' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 46 0x2e '.' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 47 0x2f '/' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 48 0x30 '0' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 49 0x31 '1' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x38, /* 00111000 */ - 0x78, /* 01111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 50 0x32 '2' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 51 0x33 '3' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x3c, /* 00111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 52 0x34 '4' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x1c, /* 00011100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 53 0x35 '5' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 54 0x36 '6' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 55 0x37 '7' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 56 0x38 '8' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 57 0x39 '9' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 58 0x3a ':' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 59 0x3b ';' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 60 0x3c '<' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 61 0x3d '=' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 62 0x3e '>' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 63 0x3f '?' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 64 0x40 '@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xdc, /* 11011100 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 65 0x41 'A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 66 0x42 'B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 67 0x43 'C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 68 0x44 'D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 69 0x45 'E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 70 0x46 'F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 71 0x47 'G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xde, /* 11011110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x66, /* 01100110 */ - 0x3a, /* 00111010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 72 0x48 'H' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 73 0x49 'I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 74 0x4a 'J' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 75 0x4b 'K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe6, /* 11100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 76 0x4c 'L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 77 0x4d 'M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xee, /* 11101110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 78 0x4e 'N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 79 0x4f 'O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 80 0x50 'P' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 81 0x51 'Q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xde, /* 11011110 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 82 0x52 'R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 83 0x53 'S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 84 0x54 'T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x5a, /* 01011010 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 85 0x55 'U' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 86 0x56 'V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 87 0x57 'W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0xee, /* 11101110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 88 0x58 'X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 89 0x59 'Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 90 0x5a 'Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 91 0x5b '[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 92 0x5c '\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0x70, /* 01110000 */ - 0x38, /* 00111000 */ - 0x1c, /* 00011100 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 93 0x5d ']' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 94 0x5e '^' */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 95 0x5f '_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 96 0x60 '`' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 97 0x61 'a' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 98 0x62 'b' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 99 0x63 'c' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 100 0x64 'd' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 101 0x65 'e' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 102 0x66 'f' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x36, /* 00110110 */ - 0x32, /* 00110010 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 103 0x67 'g' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 104 0x68 'h' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x6c, /* 01101100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 105 0x69 'i' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 106 0x6a 'j' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - - /* 107 0x6b 'k' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 108 0x6c 'l' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 109 0x6d 'm' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 110 0x6e 'n' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 111 0x6f 'o' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 112 0x70 'p' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - - /* 113 0x71 'q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - - /* 114 0x72 'r' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 115 0x73 's' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 116 0x74 't' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0xfc, /* 11111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x36, /* 00110110 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 117 0x75 'u' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 118 0x76 'v' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 119 0x77 'w' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 120 0x78 'x' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 121 0x79 'y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - - /* 122 0x7a 'z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 123 0x7b '{' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 124 0x7c '|' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 125 0x7d '}' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 126 0x7e '~' */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 127 0x7f '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 128 0x80 '€' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 129 0x81 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 130 0x82 '‚' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 131 0x83 'ƒ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 132 0x84 '„' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 133 0x85 '…' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 134 0x86 '†' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 135 0x87 '‡' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 136 0x88 'ˆ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 137 0x89 '‰' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 138 0x8a 'Š' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 139 0x8b '‹' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 140 0x8c 'Œ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 141 0x8d '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 142 0x8e 'Ž' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 143 0x8f '' */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 144 0x90 '' */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 145 0x91 '‘' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x6e, /* 01101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 146 0x92 '’' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3e, /* 00111110 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xce, /* 11001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 147 0x93 '“' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 148 0x94 '”' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 149 0x95 '•' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 150 0x96 '–' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 151 0x97 '—' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 152 0x98 '˜' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 153 0x99 '™' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 154 0x9a 'š' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 155 0x9b '›' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 156 0x9c 'œ' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x64, /* 01100100 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xe6, /* 11100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 157 0x9d '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 158 0x9e 'ž' */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xf8, /* 11111000 */ - 0xc4, /* 11000100 */ - 0xcc, /* 11001100 */ - 0xde, /* 11011110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 159 0x9f 'Ÿ' */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 160 0xa0 ' ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 161 0xa1 '¡' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 162 0xa2 '¢' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 163 0xa3 '£' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 164 0xa4 '¤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 165 0xa5 '¥' */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 166 0xa6 '¦' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 167 0xa7 '§' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 168 0xa8 '¨' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 169 0xa9 '©' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 170 0xaa 'ª' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 171 0xab '«' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xdc, /* 11011100 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 172 0xac '¬' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x66, /* 01100110 */ - 0xce, /* 11001110 */ - 0x9a, /* 10011010 */ - 0x3f, /* 00111111 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 173 0xad '­' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 174 0xae '®' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 175 0xaf '¯' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 176 0xb0 '°' */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - - /* 177 0xb1 '±' */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - - /* 178 0xb2 '²' */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - - /* 179 0xb3 '³' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 180 0xb4 '´' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 181 0xb5 'µ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 182 0xb6 '¶' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 183 0xb7 '·' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 184 0xb8 '¸' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 185 0xb9 '¹' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 186 0xba 'º' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 187 0xbb '»' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 188 0xbc '¼' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 189 0xbd '½' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 190 0xbe '¾' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 191 0xbf '¿' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 192 0xc0 'À' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 193 0xc1 'Á' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 194 0xc2 'Â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 195 0xc3 'Ã' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 196 0xc4 'Ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 197 0xc5 'Å' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 198 0xc6 'Æ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 199 0xc7 'Ç' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 200 0xc8 'È' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 201 0xc9 'É' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 202 0xca 'Ê' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 203 0xcb 'Ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 204 0xcc 'Ì' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 205 0xcd 'Í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 206 0xce 'Î' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 207 0xcf 'Ï' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 208 0xd0 'Ð' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 209 0xd1 'Ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 210 0xd2 'Ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 211 0xd3 'Ó' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 212 0xd4 'Ô' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 213 0xd5 'Õ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 214 0xd6 'Ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 215 0xd7 '×' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 216 0xd8 'Ø' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 217 0xd9 'Ù' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 218 0xda 'Ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 219 0xdb 'Û' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 220 0xdc 'Ü' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 221 0xdd 'Ý' */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - - /* 222 0xde 'Þ' */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - - /* 223 0xdf 'ß' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 224 0xe0 'à' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 225 0xe1 'á' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xd8, /* 11011000 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 226 0xe2 'â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 227 0xe3 'ã' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 228 0xe4 'ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 229 0xe5 'å' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 230 0xe6 'æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - - /* 231 0xe7 'ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 232 0xe8 'è' */ - 0x00, /* 00000000 */ - 0x40, /* 01000000*/ - 0xe0, /* 01110000 */ - 0x1c, /* 00011100 */ - 0x06, /* 00000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 233 0xe9 'é' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010*/ - 0x0e, /* 00001110 */ - 0x78, /* 00111000 */ - 0xc0, /* 01100000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 234 0xea 'ê' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xee, /* 11101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 235 0xeb 'ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x3e, /* 00111110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 236 0xec 'ì' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 237 0xed 'í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x03, /* 00000011 */ - 0x06, /* 00000110 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xf3, /* 11110011 */ - 0x7e, /* 01111110 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 238 0xee 'î' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 239 0xef 'ï' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 240 0xf0 'ð' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 241 0xf1 'ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 242 0xf2 'ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 243 0xf3 'ó' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 244 0xf4 'ô' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 245 0xf5 'õ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 246 0xf6 'ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 247 0xf7 '÷' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 248 0xf8 'ø' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 249 0xf9 'ù' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 250 0xfa 'ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 251 0xfb 'û' */ - 0x00, /* 00000000 */ - 0x0f, /* 00001111 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xec, /* 11101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3c, /* 00111100 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 252 0xfc 'ü' */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 253 0xfd 'ý' */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x32, /* 00110010 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 254 0xfe 'þ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 255 0xff 'ÿ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - -}; - -#endif diff --git a/ariane/src/lib/ffconf.h b/ariane/src/ffconf.h similarity index 93% rename from ariane/src/lib/ffconf.h rename to ariane/src/ffconf.h index 4038064..1f79990 100644 --- a/ariane/src/lib/ffconf.h +++ b/ariane/src/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs - Configuration file +/ FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 63463 /* Revision ID */ +#define FFCONF_DEF 86604 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -15,7 +15,7 @@ / and optional writing functions as well. */ -#define FF_FS_MINIMIZE 0 +#define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. @@ -33,29 +33,36 @@ / 2: Enable with LF-CRLF conversion. */ -#define FF_USE_FIND 0 +#define FF_USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -#define FF_USE_MKFS 0 +#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ #define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ +#define FF_FASTFS 1 + +#if FF_FASTFS +#undef FF_USE_FASTSEEK +#define FF_USE_FASTSEEK 1 +#endif + #define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ -#define FF_USE_CHMOD 0 +#define FF_USE_CHMOD 1 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ -#define FF_USE_LABEL 0 +#define FF_USE_LABEL 1 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ @@ -97,7 +104,7 @@ */ -#define FF_USE_LFN 2 +#define FF_USE_LFN 3 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / @@ -150,7 +157,7 @@ */ -#define FF_FS_RPATH 0 +#define FF_FS_RPATH 1 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. @@ -163,12 +170,13 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 2 +#define FF_VOLUMES 4 /* Number of volumes (logical drives) to be used. (1-10) */ -#define FF_STR_VOLUME_ID 0 -#define FF_VOLUME_STRS "sd" +#define FF_STR_VOLUME_ID 1 +// Order is important. Any change to order, must also be reflected to diskio drive enum. +#define FF_VOLUME_STRS "sd","ram","emmc","bis" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each @@ -206,7 +214,7 @@ / disk_ioctl() function. */ -#define FF_FS_NOFSINFO 0 +#define FF_FS_NOFSINFO 1 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. @@ -232,14 +240,14 @@ #define FF_FS_EXFAT 1 /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) -/ To enable exFAT, also LFN needs to be enabled. +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ -#define FF_FS_NORTC 1 +#define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2018 +#define FF_NORTC_YEAR 2020 /* The option FF_FS_NORTC switches timestamp function. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp @@ -262,6 +270,7 @@ / lock control is independent of re-entrancy. */ +/* #include // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 #define FF_SYNC_t HANDLE @@ -282,8 +291,6 @@ / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ -/* #include // O/S definitions */ - /*--- End of configuration options ---*/ diff --git a/ariane/src/fuse.c b/ariane/src/fuse.c deleted file mode 100644 index 7d5870f..0000000 --- a/ariane/src/fuse.c +++ /dev/null @@ -1,236 +0,0 @@ -#include - -#include "hwinit/hwinit.h" -#include "hwinit/clock.h" -#include "hwinit/timer.h" -#include "fuse.h" - -/* Prototypes for internal commands. */ -void fuse_make_regs_visible(void); - -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - -/* Initialize the FUSE driver */ -void fuse_init(void) -{ - /* - Already done by hwinit, except maybe fuse_secondary_private_key_disable (?) - fuse_make_regs_visible(); - fuse_secondary_private_key_disable(); - fuse_disable_programming(); - */ - - /* TODO: Overrides (iROM patches) and various reads happen here */ -} - -/* Make all fuse registers visible */ -void fuse_make_regs_visible(void) -{ - clock_enable_fuse(1); -} - -/* Enable power to the fuse hardware array */ -void fuse_enable_power(void) -{ - FUSE_REGS->FUSE_PWR_GOOD_SW = 1; - usleep(1); -} - -/* Disable power to the fuse hardware array */ -void fuse_disable_power(void) -{ - FUSE_REGS->FUSE_PWR_GOOD_SW = 0; - usleep(1); -} - -/* Wait for the fuse driver to go idle */ -void fuse_wait_idle(void) -{ - uint32_t ctrl_val = 0; - - /* Wait for STATE_IDLE */ - while ((ctrl_val & (0xF0000)) != 0x40000) - { - usleep(1); - ctrl_val = FUSE_REGS->FUSE_CTRL; - } -} - -/* Read a fuse from the hardware array */ -uint32_t fuse_hw_read(uint32_t addr) -{ - fuse_wait_idle(); - - /* Program the target address */ - FUSE_REGS->FUSE_REG_ADDR = addr; - - /* Enable read operation in control register */ - uint32_t ctrl_val = FUSE_REGS->FUSE_CTRL; - ctrl_val &= ~0x3; - ctrl_val |= 0x1; /* Set FUSE_READ command */ - FUSE_REGS->FUSE_CTRL = ctrl_val; - - fuse_wait_idle(); - - return FUSE_REGS->FUSE_REG_READ; -} - -/* Write a fuse in the hardware array */ -void fuse_hw_write(uint32_t value, uint32_t addr) -{ - fuse_wait_idle(); - - /* Program the target address and value */ - FUSE_REGS->FUSE_REG_ADDR = addr; - FUSE_REGS->FUSE_REG_WRITE = value; - - /* Enable write operation in control register */ - uint32_t ctrl_val = FUSE_REGS->FUSE_CTRL; - ctrl_val &= ~0x3; - ctrl_val |= 0x2; /* Set FUSE_WRITE command */ - FUSE_REGS->FUSE_CTRL = ctrl_val; - - fuse_wait_idle(); -} - -/* Sense the fuse hardware array into the shadow cache */ -void fuse_hw_sense(void) -{ - fuse_wait_idle(); - - /* Enable sense operation in control register */ - uint32_t ctrl_val = FUSE_REGS->FUSE_CTRL; - ctrl_val &= ~0x3; - ctrl_val |= 0x3; /* Set FUSE_SENSE command */ - FUSE_REGS->FUSE_CTRL = ctrl_val; - - fuse_wait_idle(); -} - -/* Disables all fuse programming. */ -void fuse_disable_programming(void) { - FUSE_REGS->FUSE_DIS_PGM = 1; -} - -/* Unknown exactly what this does, but it alters the contents read from the fuse cache. */ -void fuse_secondary_private_key_disable(void) { - FUSE_REGS->FUSE_PRIVATEKEYDISABLE = 0x10; -} - - -/* Read the SKU info register from the shadow cache */ -uint32_t fuse_get_sku_info(void) -{ - return FUSE_CHIP_REGS->FUSE_SKU_INFO; -} - -/* Read the bootrom patch version from a register in the shadow cache */ -uint32_t fuse_get_bootrom_patch_version(void) -{ - return FUSE_CHIP_REGS->FUSE_SOC_SPEEDO_1; -} - -/* Read a spare bit register from the shadow cache */ -uint32_t fuse_get_spare_bit(uint32_t idx) -{ - if (idx >= 32) { - return 0; - } - - return FUSE_CHIP_REGS->FUSE_SPARE_BIT[idx]; -} - -/* Read a reserved ODM register from the shadow cache */ -uint32_t fuse_get_reserved_odm(uint32_t idx) -{ - if (idx >= 8) { - return 0; - } - - return FUSE_CHIP_REGS->FUSE_RESERVED_ODM[idx]; -} - -/* Derive the Device ID using values in the shadow cache */ -uint64_t fuse_get_device_id(void) { - uint64_t device_id = 0; - uint64_t y_coord = FUSE_CHIP_REGS->FUSE_Y_COORDINATE & 0x1FF; - uint64_t x_coord = FUSE_CHIP_REGS->FUSE_X_COORDINATE & 0x1FF; - uint64_t wafer_id = FUSE_CHIP_REGS->FUSE_WAFER_ID & 0x3F; - uint32_t lot_code = FUSE_CHIP_REGS->FUSE_LOT_CODE_0; - uint64_t fab_code = FUSE_CHIP_REGS->FUSE_FAB_CODE & 0x3F; - uint64_t derived_lot_code = 0; - for (unsigned int i = 0; i < 5; i++) { - derived_lot_code = (derived_lot_code * 0x24) + ((lot_code >> (24 - 6*i)) & 0x3F); - } - derived_lot_code &= 0x03FFFFFF; - - device_id |= y_coord << 0; - device_id |= x_coord << 9; - device_id |= wafer_id << 18; - device_id |= derived_lot_code << 24; - device_id |= fab_code << 50; - return device_id; -} - -/* Get the DRAM ID using values in the shadow cache */ -uint32_t fuse_get_dram_id(void) { - return (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 3) & 0x7; -} - -/* Derive the Hardware Type using values in the shadow cache */ -uint32_t fuse_get_hardware_type(void) { - /* This function is very different between 4.x and < 4.x */ - uint32_t hardware_type = ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 7) & 2) | ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 2) & 1); - - /* TODO: choose; if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) { - static const uint32_t types[] = {0,1,4,3}; - - hardware_type |= (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 14) & 0x3C; - hardware_type--; - return hardware_type > 3 ? 4 : types[hardware_type]; - } else {*/ - if (hardware_type >= 1) { - return hardware_type > 2 ? 3 : hardware_type - 1; - } else if ((FUSE_CHIP_REGS->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; - } -// } -} - -/* Derive the Retail Type using values in the shadow cache */ -uint32_t fuse_get_retail_type(void) { - /* Retail type = IS_RETAIL | UNIT_TYPE */ - uint32_t retail_type = ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 7) & 4) | (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] & 3); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; - } - return 2; /* IS_RETAIL | DEV_UNIT */ -} - -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ -void fuse_get_hardware_info(void *dst) { - uint32_t hw_info[0x4]; - - uint32_t unk_hw_fuse = FUSE_CHIP_REGS->_0x120 & 0x3F; - uint32_t y_coord = FUSE_CHIP_REGS->FUSE_Y_COORDINATE & 0x1FF; - uint32_t x_coord = FUSE_CHIP_REGS->FUSE_X_COORDINATE & 0x1FF; - uint32_t wafer_id = FUSE_CHIP_REGS->FUSE_WAFER_ID & 0x3F; - uint32_t lot_code_0 = FUSE_CHIP_REGS->FUSE_LOT_CODE_0; - uint32_t lot_code_1 = FUSE_CHIP_REGS->FUSE_LOT_CODE_1 & 0x0FFFFFFF; - uint32_t fab_code = FUSE_CHIP_REGS->FUSE_FAB_CODE & 0x3F; - uint32_t vendor_code = FUSE_CHIP_REGS->FUSE_VENDOR_CODE & 0xF; - - /* Hardware Info = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID */ - hw_info[0] = (uint32_t)((lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | (unk_hw_fuse)); - hw_info[1] = (uint32_t)((lot_code_0 << 26) | (lot_code_1 >> 2)); - hw_info[2] = (uint32_t)((fab_code << 26) | (lot_code_0 >> 6)); - hw_info[3] = (uint32_t)(vendor_code); - - memcpy(dst, hw_info, 0x10); -} diff --git a/ariane/src/fuse.h b/ariane/src/fuse.h deleted file mode 100644 index 1dcbc8d..0000000 --- a/ariane/src/fuse.h +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef FUSEE_FUSE_H -#define FUSEE_FUSE_H - -#include -#include - -typedef struct { - uint32_t FUSE_CTRL; - uint32_t FUSE_REG_ADDR; - uint32_t FUSE_REG_READ; - uint32_t FUSE_REG_WRITE; - uint32_t FUSE_TIME_RD1; - uint32_t FUSE_TIME_RD2; - uint32_t FUSE_TIME_PGM1; - uint32_t FUSE_TIME_PGM2; - uint32_t FUSE_PRIV2INTFC; - uint32_t FUSE_FUSEBYPASS; - uint32_t FUSE_PRIVATEKEYDISABLE; - uint32_t FUSE_DIS_PGM; - uint32_t FUSE_WRITE_ACCESS; - uint32_t FUSE_PWR_GOOD_SW; - uint32_t _0x38[0x32]; -} fuse_registers_t; - -typedef struct { - uint32_t FUSE_PRODUCTION_MODE; - uint32_t _0x4; - uint32_t _0x8; - uint32_t _0xC; - uint32_t FUSE_SKU_INFO; - uint32_t FUSE_CPU_SPEEDO_0; - uint32_t FUSE_CPU_IDDQ; - uint32_t _0x1C; - uint32_t _0x20; - uint32_t _0x24; - uint32_t FUSE_FT_REV; - uint32_t FUSE_CPU_SPEEDO_1; - uint32_t FUSE_CPU_SPEEDO_2; - uint32_t FUSE_SOC_SPEEDO_0; - uint32_t FUSE_SOC_SPEEDO_1; - uint32_t FUSE_SOC_SPEEDO_2; - uint32_t FUSE_SOC_IDDQ; - uint32_t _0x44; - uint32_t FUSE_FA; - uint32_t _0x4C; - uint32_t _0x50; - uint32_t _0x54; - uint32_t _0x58; - uint32_t _0x5C; - uint32_t _0x60; - uint32_t FUSE_PUBLIC_KEY[0x8]; - uint32_t FUSE_TSENSOR_1; - uint32_t FUSE_TSENSOR_2; - uint32_t _0x8C; - uint32_t FUSE_CP_REV; - uint32_t _0x94; - uint32_t FUSE_TSENSOR_0; - uint32_t FUSE_FIRST_BOOTROM_PATCH_SIZE_REG; - uint32_t FUSE_SECURITY_MODE; - uint32_t FUSE_PRIVATE_KEY[0x4]; - uint32_t FUSE_DEVICE_KEY; - uint32_t _0xB8; - uint32_t _0xBC; - uint32_t FUSE_RESERVED_SW; - uint32_t FUSE_VP8_ENABLE; - uint32_t FUSE_RESERVED_ODM[0x8]; - uint32_t _0xE8; - uint32_t _0xEC; - uint32_t FUSE_SKU_USB_CALIB; - uint32_t FUSE_SKU_DIRECT_CONFIG; - uint32_t _0xF8; - uint32_t _0xFC; - uint32_t FUSE_VENDOR_CODE; - uint32_t FUSE_FAB_CODE; - uint32_t FUSE_LOT_CODE_0; - uint32_t FUSE_LOT_CODE_1; - uint32_t FUSE_WAFER_ID; - uint32_t FUSE_X_COORDINATE; - uint32_t FUSE_Y_COORDINATE; - uint32_t _0x11C; - uint32_t _0x120; - uint32_t FUSE_SATA_CALIB; - uint32_t FUSE_GPU_IDDQ; - uint32_t FUSE_TSENSOR_3; - uint32_t _0x130; - uint32_t _0x134; - uint32_t _0x138; - uint32_t _0x13C; - uint32_t _0x140; - uint32_t _0x144; - uint32_t FUSE_OPT_SUBREVISION; - uint32_t _0x14C; - uint32_t _0x150; - uint32_t FUSE_TSENSOR_4; - uint32_t FUSE_TSENSOR_5; - uint32_t FUSE_TSENSOR_6; - uint32_t FUSE_TSENSOR_7; - uint32_t FUSE_OPT_PRIV_SEC_DIS; - uint32_t FUSE_PKC_DISABLE; - uint32_t _0x16C; - uint32_t _0x170; - uint32_t _0x174; - uint32_t _0x178; - uint32_t _0x17C; - uint32_t FUSE_TSENSOR_COMMON; - uint32_t _0x184; - uint32_t _0x188; - uint32_t _0x18C; - uint32_t _0x190; - uint32_t _0x194; - uint32_t _0x198; - uint32_t FUSE_DEBUG_AUTH_OVERRIDE; - uint32_t _0x1A0; - uint32_t _0x1A4; - uint32_t _0x1A8; - uint32_t _0x1AC; - uint32_t _0x1B0; - uint32_t _0x1B4; - uint32_t _0x1B8; - uint32_t _0x1BC; - uint32_t _0x1D0; - uint32_t FUSE_TSENSOR_8; - uint32_t _0x1D8; - uint32_t _0x1DC; - uint32_t _0x1E0; - uint32_t _0x1E4; - uint32_t _0x1E8; - uint32_t _0x1EC; - uint32_t _0x1F0; - uint32_t _0x1F4; - uint32_t _0x1F8; - uint32_t _0x1FC; - uint32_t _0x200; - uint32_t FUSE_RESERVED_CALIB; - uint32_t _0x208; - uint32_t _0x20C; - uint32_t _0x210; - uint32_t _0x214; - uint32_t _0x218; - uint32_t FUSE_TSENSOR_9; - uint32_t _0x220; - uint32_t _0x224; - uint32_t _0x228; - uint32_t _0x22C; - uint32_t _0x230; - uint32_t _0x234; - uint32_t _0x238; - uint32_t _0x23C; - uint32_t _0x240; - uint32_t _0x244; - uint32_t _0x248; - uint32_t _0x24C; - uint32_t FUSE_USB_CALIB_EXT; - uint32_t _0x254; - uint32_t _0x258; - uint32_t _0x25C; - uint32_t _0x260; - uint32_t _0x264; - uint32_t _0x268; - uint32_t _0x26C; - uint32_t _0x270; - uint32_t _0x274; - uint32_t _0x278; - uint32_t _0x27C; - uint32_t FUSE_SPARE_BIT[0x20]; -} fuse_chip_registers_t; - -static inline volatile fuse_registers_t *get_fuse_regs(void) { - return (volatile fuse_registers_t *)(0x7000F000 + 0x800); -} - -static inline volatile fuse_chip_registers_t *get_fuse_chip_regs(void) { - return (volatile fuse_chip_registers_t *)(0x7000F000 + 0x900); -} -#define FUSE_REGS (get_fuse_regs()) -#define FUSE_CHIP_REGS (get_fuse_chip_regs()) - -void fuse_init(void); - -uint32_t fuse_hw_read(uint32_t addr); -void fuse_hw_write(uint32_t value, uint32_t addr); -void fuse_hw_sense(void); -void fuse_disable_programming(void); -void fuse_secondary_private_key_disable(void); - -uint32_t fuse_get_sku_info(void); -uint32_t fuse_get_spare_bit(uint32_t idx); -uint32_t fuse_get_reserved_odm(uint32_t idx); - -uint32_t fuse_get_bootrom_patch_version(void); -uint64_t fuse_get_device_id(void); -uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(void); -uint32_t fuse_get_retail_type(void); -void fuse_get_hardware_info(void *dst); - -#endif diff --git a/ariane/src/gfx/gfx.c b/ariane/src/gfx/gfx.c new file mode 100644 index 0000000..06d62f8 --- /dev/null +++ b/ariane/src/gfx/gfx.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "gfx.h" + +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +static const u8 _gfx_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) + 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (") + 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#) + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($) + 0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%) + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&) + 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (') + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (() + 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ()) + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*) + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,) + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.) + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/) + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0) + 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1) + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2) + 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3) + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4) + 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5) + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6) + 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7) + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8) + 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9) + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:) + 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;) + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<) + 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=) + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>) + 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?) + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@) + 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A) + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B) + 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C) + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D) + 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E) + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F) + 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G) + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H) + 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I) + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J) + 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K) + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L) + 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M) + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O) + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q) + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R) + 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S) + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V) + 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W) + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X) + 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y) + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z) + 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([) + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\) + 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (]) + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_) + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`) + 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b) + 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c) + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d) + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e) + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f) + 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h) + 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i) + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j) + 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k) + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l) + 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n) + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p) + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q) + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r) + 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s) + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v) + 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w) + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x) + 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y) + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z) + 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({) + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|) + 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (}) + 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) +}; + +void gfx_clear_grey(u8 color) +{ + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); +} + +void gfx_clear_color(u32 color) +{ + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) + gfx_ctxt.fb[i] = color; +} + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) +{ + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; + + gfx_clear_grey(0); +} + +void gfx_con_init() +{ + gfx_con.gfx_ctxt = &gfx_ctxt; + gfx_con.fntsz = 16; + gfx_con.x = 0; + gfx_con.y = 0; + gfx_con.savedx = 0; + gfx_con.savedy = 0; + gfx_con.fgcol = 0xFFFFFFFF; + gfx_con.fillbg = 1; + gfx_con.bgcol = 0xFF000000; + gfx_con.mute = 0; +} + +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) +{ + gfx_con.fgcol = fgcol; + gfx_con.fillbg = fillbg; + gfx_con.bgcol = bgcol; +} + +void gfx_con_getpos(u32 *x, u32 *y) +{ + *x = gfx_con.x; + *y = gfx_con.y; +} + +void gfx_con_setpos(u32 x, u32 y) +{ + gfx_con.x = x; + gfx_con.y = y; +} + +static int gfx_column = 0; +void gfx_putc(char c) +{ + // Duplicate code for performance reasons. + switch (gfx_con.fntsz) + { + case 16: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + for (u32 i = 0; i < 16; i += 2) + { + u8 v = *cbuf; + for (u32 k = 0; k < 2; k++) + { + u32 fb_off = gfx_con.y + i + k + (gfx_ctxt.height - gfx_con.x) * gfx_ctxt.stride; + for (u32 j = 0; j < 16; j += 2) + { + for (u32 l = 0; l < 2; l++) + { + if (v & 1) + gfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.fgcol; + else if (gfx_con.fillbg) + gfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.bgcol; + } + v >>= 1; + } + v = *cbuf; + } + cbuf++; + } + gfx_con.x += 16; + } + else if (c == '\n') + { + gfx_con.x = gfx_column; + gfx_con.y +=16; + if (gfx_con.y > gfx_ctxt.height - 33) + { + gfx_con.y = 0; + + if (!gfx_column) + gfx_column = 640; + else + gfx_column = 0; + gfx_con.x = gfx_column; + } + } + break; + case 8: + default: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + for (u32 i = 0; i < 8; i++) + { + u8 v = *cbuf++; + u32 fb_off = gfx_con.y + i + (gfx_ctxt.width - gfx_con.x) * gfx_ctxt.stride; + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + gfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.fgcol; + else if (gfx_con.fillbg) + gfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.bgcol; + v >>= 1; + } + } + gfx_con.x += 8; + } + else if (c == '\n') + { + gfx_con.x = gfx_column; + gfx_con.y += 8; + if (gfx_con.y > gfx_ctxt.height - 33) + { + gfx_con.y = 0; + + if (!gfx_column) + gfx_column = 640; + else + gfx_column = 0; + gfx_con.x = gfx_column; + } + } + break; + } +} + + +void gfx_puts(char *s) +{ + if (!s || gfx_con.mute) + return; + + for (; *s; s++) + gfx_putc(*s); +} + +static void _gfx_putn(u32 v, int base, char fill, int fcnt) +{ + char buf[65]; + static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return; + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) + { + while (c > 0) + { + *--p = fill; + c--; + } + } + + gfx_puts(p); +} + +void gfx_printf(const char *fmt, ...) +{ + if (gfx_con.mute) + return; + + va_list ap; + int fill, fcnt; + + va_start(ap, fmt); + while(*fmt) + { + if(*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') + { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } + else + { + fill = ' '; + fcnt -= '0'; + } + } + switch(*fmt) + { + case 'c': + gfx_putc(va_arg(ap, u32)); + break; + case 's': + gfx_puts(va_arg(ap, char *)); + break; + case 'd': + _gfx_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + case 'x': + case 'X': + _gfx_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + case 'k': + gfx_con.fgcol = va_arg(ap, u32); + break; + case 'K': + gfx_con.bgcol = va_arg(ap, u32); + gfx_con.fillbg = 1; + break; + case '%': + gfx_putc('%'); + break; + case '\0': + goto out; + default: + gfx_putc('%'); + gfx_putc(*fmt); + break; + } + } + else + gfx_putc(*fmt); + fmt++; + } + + out: + va_end(ap); +} + +void gfx_hexdump(u32 base, const u8 *buf, u32 len) +{ + if (gfx_con.mute) + return; + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + for(u32 i = 0; i < len; i++) + { + if(i % 0x10 == 0) + { + if(i != 0) + { + gfx_puts("| "); + for(u32 j = 0; j < 0x10; j++) + { + u8 c = buf[i - 0x10 + j]; + if(c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + gfx_printf("%08x: ", base + i); + } + gfx_printf("%02x ", buf[i]); + if (i == len - 1) + { + int ln = len % 0x10 != 0; + u32 k = 0x10 - 1; + if (ln) + { + k = (len & 0xF) - 1; + for (u32 j = 0; j < 0x10 - k; j++) + gfx_puts(" "); + } + gfx_puts("| "); + for(u32 j = 0; j < (ln ? k : k + 1); j++) + { + u8 c = buf[i - k + j]; + if(c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + } + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +void gfx_set_pixel(u32 x, u32 y, u32 color) +{ + gfx_ctxt.fb[y + (gfx_ctxt.width - x) * gfx_ctxt.stride] = color; +} + +void __attribute__((optimize("unroll-loops"))) gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) +{ + u32 *ptr = (u32 *)buf; + + u32 pixels_w = pos_x2 - pos_x + 1; + + if (!(pixels_w % 8)) + { + for (u32 y = pos_y; y < (pos_y2 + 1); y++) + for (u32 x = pos_x; x < (pos_x2 + 1); x+=8) + { + u32 *fbx = &fb[x * stride + y]; + + fbx[0] = *ptr++; + fbx[stride] = *ptr++; + fbx[stride * 2] = *ptr++; + fbx[stride * 3] = *ptr++; + fbx[stride * 4] = *ptr++; + fbx[stride * 5] = *ptr++; + fbx[stride * 6] = *ptr++; + fbx[stride * 7] = *ptr++; + } + } + else + { + for (u32 y = pos_y; y < (pos_y2 + 1); y++) + for (u32 x = pos_x; x < (pos_x2 + 1); x++) + fb[x * stride + y] = *ptr++; + } +} + +void __attribute__((optimize("unroll-loops"))) gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2) +{ + u32 *ptr = (u32 *)buf; + u32 GOB_address = 0; + u32 addr = 0; + u32 x2 = 0; + + // Optimized + u32 image_width_in_gobs = 655360; //1280 + for (u32 y = pos_y; y < (pos_y2 + 1); y++) + { + for (u32 x = pos_x; x < (pos_x2 + 1); x++) + { + GOB_address = (y >> 7) * image_width_in_gobs + ((x >> 4) << 13) + (((y % 128) >> 3) << 9); + + x2 = x << 2; + addr = GOB_address + + (((x2 % 64) >> 5) << 8) + + (((y % 8) >> 1) << 6) + + (((x2 % 32) >> 4) << 5) + + ((y % 2) << 4) + (x2 % 16); + + *(u32 *)(fb + (addr >> 2)) = *ptr++; + } + } + + // Proper + // u32 block_height = 16; + // u32 image_width_in_gobs = (512 * block_height * 1280 * 4) / 64; + // for (u32 y = pos_y; y <= pos_y2; y++) + // { + // for (int x = pos_x; x <= pos_x2; x++) + // { + // GOB_address = (y / (8 * block_height)) * image_width_in_gobs + ((x * 4 / 64) * 512 * block_height) + ((y % (8 * block_height) / 8) * 512); + + // x2 = x << 2; + // addr = GOB_address + // + (((x2 % 64) >> 5) << 8) + // + (((y % 8) >> 1) << 6) + // + (((x2 % 32) >> 4) << 5) + // + ((y % 2) << 4) + (x2 % 16); + + // *(u32 *)(gfx_ctxt.fb + (addr >> 2)) = *ptr++; + // } + // } +} + +void gfx_rect(u32 size_x, u32 size_y, u32 pos_x, u32 pos_y, u32 color) +{ + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; + } +} + +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 pos = 0; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + { + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); + pos+=3; + } + } +} diff --git a/ariane/src/gfx/gfx.h b/ariane/src/gfx/gfx.h new file mode 100644 index 0000000..a520bed --- /dev/null +++ b/ariane/src/gfx/gfx.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include + +#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) +#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) + +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); +void gfx_clear_grey(u8 color); +void gfx_clear_color(u32 color); +void gfx_con_init(); +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); +void gfx_con_getpos(u32 *x, u32 *y); +void gfx_con_setpos(u32 x, u32 y); +void gfx_putc(char c); +void gfx_puts(char *s); +void gfx_printf(const char *fmt, ...); +void gfx_hexdump(u32 base, const u8 *buf, u32 len); +void gfx_set_pixel(u32 x, u32 y, u32 color); +void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); +void gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2); +void gfx_rect(u32 size_x, u32 size_y, u32 pos_x, u32 pos_y, u32 color); +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); + +#endif diff --git a/ariane/src/gfx/gfx_save.c b/ariane/src/gfx/gfx_save.c new file mode 100644 index 0000000..9433b04 --- /dev/null +++ b/ariane/src/gfx/gfx_save.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "gfx.h" + +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +static const u8 _gfx_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) + 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (") + 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#) + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($) + 0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%) + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&) + 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (') + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (() + 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ()) + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*) + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,) + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.) + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/) + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0) + 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1) + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2) + 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3) + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4) + 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5) + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6) + 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7) + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8) + 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9) + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:) + 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;) + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<) + 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=) + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>) + 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?) + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@) + 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A) + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B) + 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C) + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D) + 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E) + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F) + 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G) + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H) + 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I) + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J) + 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K) + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L) + 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M) + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O) + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q) + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R) + 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S) + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V) + 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W) + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X) + 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y) + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z) + 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([) + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\) + 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (]) + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_) + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`) + 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b) + 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c) + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d) + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e) + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f) + 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h) + 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i) + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j) + 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k) + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l) + 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n) + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p) + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q) + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r) + 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s) + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v) + 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w) + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x) + 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y) + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z) + 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({) + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|) + 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (}) + 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) +}; + +void gfx_clear_grey(u8 color) +{ + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); +} + +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +{ + memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); +} + +void gfx_clear_color(u32 color) +{ + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) + gfx_ctxt.fb[i] = color; +} + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) +{ + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; +} + +void gfx_con_init() +{ + gfx_con.gfx_ctxt = &gfx_ctxt; + gfx_con.fntsz = 16; + gfx_con.x = 0; + gfx_con.y = 0; + gfx_con.savedx = 0; + gfx_con.savedy = 0; + gfx_con.fgcol = 0xFFCCCCCC; + gfx_con.fillbg = 1; + gfx_con.bgcol = 0xFF1B1B1B; + gfx_con.mute = 0; +} + +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) +{ + gfx_con.fgcol = fgcol; + gfx_con.fillbg = fillbg; + gfx_con.bgcol = bgcol; +} + +void gfx_con_getpos(u32 *x, u32 *y) +{ + *x = gfx_con.x; + *y = gfx_con.y; +} + +void gfx_con_setpos(u32 x, u32 y) +{ + gfx_con.x = x; + gfx_con.y = y; +} + +void gfx_putc(char c) +{ + // Duplicate code for performance reasons. + switch (gfx_con.fntsz) + { + case 16: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; + + for (u32 i = 0; i < 16; i += 2) + { + u8 v = *cbuf; + for (u32 k = 0; k < 2; k++) + { + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + { + *fb = gfx_con.fgcol; + fb++; + *fb = gfx_con.fgcol; + } + else if (gfx_con.fillbg) + { + *fb = gfx_con.bgcol; + fb++; + *fb = gfx_con.bgcol; + } + else + fb++; + v >>= 1; + fb++; + } + fb += gfx_ctxt.stride - 16; + v = *cbuf; + } + cbuf++; + } + gfx_con.x += 16; + } + else if (c == '\n') + { + gfx_con.x = 0; + gfx_con.y += 16; + if (gfx_con.y > gfx_ctxt.height - 16) + gfx_con.y = 0; + } + break; + case 8: + default: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; + for (u32 i = 0; i < 8; i++) + { + u8 v = *cbuf++; + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + *fb = gfx_con.fgcol; + else if (gfx_con.fillbg) + *fb = gfx_con.bgcol; + v >>= 1; + fb++; + } + fb += gfx_ctxt.stride - 8; + } + gfx_con.x += 8; + } + else if (c == '\n') + { + gfx_con.x = 0; + gfx_con.y += 8; + if (gfx_con.y > gfx_ctxt.height - 8) + gfx_con.y = 0; + } + break; + } +} + +void gfx_puts(char *s) +{ + if (!s || gfx_con.mute) + return; + + for (; *s; s++) + gfx_putc(*s); +} + +static void _gfx_putn(u32 v, int base, char fill, int fcnt) +{ + char buf[65]; + static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return; + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) + { + while (c > 0) + { + *--p = fill; + c--; + } + } + + gfx_puts(p); +} + +void gfx_put_small_sep() +{ + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +void gfx_put_big_sep() +{ + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 16; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +void gfx_printf(const char *fmt, ...) +{ + if (gfx_con.mute) + return; + + va_list ap; + int fill, fcnt; + + va_start(ap, fmt); + while(*fmt) + { + if(*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') + { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } + else + { + fill = ' '; + fcnt -= '0'; + } + } + switch(*fmt) + { + case 'c': + gfx_putc(va_arg(ap, u32)); + break; + case 's': + gfx_puts(va_arg(ap, char *)); + break; + case 'd': + _gfx_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + case 'x': + case 'X': + _gfx_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + case 'k': + gfx_con.fgcol = va_arg(ap, u32); + break; + case 'K': + gfx_con.bgcol = va_arg(ap, u32); + gfx_con.fillbg = 1; + break; + case '%': + gfx_putc('%'); + break; + case '\0': + goto out; + default: + gfx_putc('%'); + gfx_putc(*fmt); + break; + } + } + else + gfx_putc(*fmt); + fmt++; + } + + out: + va_end(ap); +} + +void gfx_hexdump(u32 base, const u8 *buf, u32 len) +{ + if (gfx_con.mute) + return; + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + for(u32 i = 0; i < len; i++) + { + if(i % 0x10 == 0) + { + if(i != 0) + { + gfx_puts("| "); + for(u32 j = 0; j < 0x10; j++) + { + u8 c = buf[i - 0x10 + j]; + if(c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + gfx_printf("%08x: ", base + i); + } + gfx_printf("%02x ", buf[i]); + if (i == len - 1) + { + int ln = len % 0x10 != 0; + u32 k = 0x10 - 1; + if (ln) + { + k = (len & 0xF) - 1; + for (u32 j = 0; j < 0x10 - k; j++) + gfx_puts(" "); + } + gfx_puts("| "); + for(u32 j = 0; j < (ln ? k : k + 1); j++) + { + u8 c = buf[i - k + j]; + if(c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + } + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +static int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +void gfx_set_pixel(u32 x, u32 y, u32 color) +{ + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; +} + +void gfx_line(int x0, int y0, int x1, int y1, u32 color) +{ + int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; + int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2, e2; + + while (1) + { + gfx_set_pixel(x0, y0, color); + if (x0 == x1 && y0 == y1) + break; + e2 = err; + if (e2 >-dx) + { + err -= dy; + x0 += sx; + } + if (e2 < dy) + { + err += dx; + y0 += sy; + } + } +} + +void gfx_rect(u32 size_x, u32 size_y, u32 pos_x, u32 pos_y, u32 color) +{ + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; + } +} + +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 pos = 0; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + { + memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4); + pos++; + } + } +} + + +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 pos = 0; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + { + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); + pos+=3; + } + } +} + +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 *ptr = (u32 *)buf; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++; +} + +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; + } +} + diff --git a/ariane/src/gfx/gfx_save.h b/ariane/src/gfx/gfx_save.h new file mode 100644 index 0000000..4a5bec3 --- /dev/null +++ b/ariane/src/gfx/gfx_save.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include + +#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) +#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) + +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +typedef struct _image_t_rgb { + const u8 *pixels; + unsigned int w; + unsigned int h; +} image_t_rgb; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); +void gfx_clear_grey(u8 color); +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); +void gfx_clear_color(u32 color); +void gfx_con_init(); +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); +void gfx_con_getpos(u32 *x, u32 *y); +void gfx_con_setpos(u32 x, u32 y); +void gfx_putc(char c); +void gfx_puts(char *s); +void gfx_printf(const char *fmt, ...); +void gfx_hexdump(u32 base, const u8 *buf, u32 len); + +void gfx_set_pixel(u32 x, u32 y, u32 color); +void gfx_line(int x0, int y0, int x1, int y1, u32 color); +void gfx_put_small_sep(); +void gfx_put_big_sep(); +void gfx_rect(u32 size_x, u32 size_y, u32 pos_x, u32 pos_y, u32 color); +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); + +#endif diff --git a/ariane/src/gfx/logos.h b/ariane/src/gfx/logos.h new file mode 100644 index 0000000..7420cc6 --- /dev/null +++ b/ariane/src/gfx/logos.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _HEKATE_LOGOS_H_ +#define _HEKATE_LOGOS_H_ + +// 68 x 192 @8bpp Grayscale RAW. +#define X_BOOTLOGO 68 +#define Y_BOOTLOGO 192 +#define SZ_BOOTLOGO 13056 +#define SZ_BOOTLOGO_BLZ 3988 +static u8 BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = { + 0x0F, 0xF0, 0x80, 0x1B, 0x1B, 0x40, 0xF0, 0x1E, 0x1F, 0x48, 0x5A, 0x0F, 0xF0, 0x0F, 0xF0, 0xE4, + 0x17, 0xF0, 0x91, 0x13, 0x26, 0x28, 0x23, 0x1E, 0x0A, 0xA0, 0x0F, 0xF0, 0xC3, 0x22, 0xF0, 0xC3, + 0xA4, 0x1E, 0x29, 0x33, 0xDB, 0x2C, 0xEA, 0x53, 0x83, 0x0F, 0xF0, 0x38, 0xF0, 0xBC, 0x39, 0x21, + 0x22, 0xB0, 0x87, 0x20, 0x2F, 0x27, 0x3E, 0xDB, 0x35, 0x01, 0xA6, 0x69, 0xF2, 0x3C, 0xFD, 0x25, + 0x2D, 0x38, 0x77, 0x28, 0x15, 0x8A, 0x33, 0x45, 0xDB, 0x09, 0xEF, 0xBB, 0x44, 0xD0, 0xC0, 0x18, + 0xEF, 0x2E, 0x3B, 0xF5, 0x32, 0x25, 0x41, 0xC0, 0x83, 0x52, 0xE1, 0x07, 0xCD, 0x08, 0xF4, 0xF5, + 0x3B, 0x61, 0xB2, 0x95, 0xF1, 0x01, 0x10, 0xE7, 0xA3, 0x02, 0x95, 0x91, 0x3C, 0xFD, 0x41, 0x90, + 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x7F, 0x3D, 0x9B, 0xFA, 0x41, 0xF0, 0x41, 0xF0, 0x0F, + 0xF0, 0x26, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xFE, 0x4C, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x4D, 0xF5, + 0x95, 0x01, 0x9B, 0x02, 0xCD, 0x5D, 0x41, 0xF0, 0xFF, 0x41, 0xF0, 0x4D, 0xF5, 0x77, 0xC5, 0x18, + 0x93, 0xCD, 0x8D, 0x41, 0xF0, 0x41, 0xF0, 0xEB, 0x4D, 0xF5, 0x69, 0xFB, 0x6C, 0xF4, 0x41, 0xF0, + 0x4D, 0xF5, 0x65, 0x3F, 0x28, 0x01, 0x10, 0xBF, 0x03, 0x30, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x30, + 0x45, 0x57, 0x03, 0xE4, 0x03, 0x41, 0xB0, 0xCD, 0xFD, 0x5D, 0x02, 0xCD, 0x1D, 0xC9, 0x1C, 0x2C, + 0x38, 0x3F, 0x3F, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x41, 0x41, 0x41, 0x48, 0x0E, 0x56, 0x61, + 0xF5, 0x41, 0xED, 0xDF, 0xCD, 0xFD, 0x3D, 0xBB, 0x30, 0x2D, 0x6D, 0xB3, 0x6D, 0x4D, 0x15, 0x38, + 0x01, 0x10, 0xE1, 0xF6, 0xD0, 0x3C, 0x27, 0x41, 0xB0, 0xCD, 0xFD, 0xA4, 0xCD, 0x2D, 0xF0, 0x4E, + 0x6F, 0x6C, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x73, 0x73, 0x73, 0x74, 0x75, 0x07, 0x72, 0x68, + 0x31, 0x22, 0x41, 0xD0, 0xA4, 0xF2, 0xCD, 0x3D, 0xE6, 0x1E, 0xF0, 0x36, 0x3D, 0x02, 0x20, 0x03, + 0x30, 0x00, 0x00, 0x40, 0x40, 0x40, 0x1C, 0x3F, 0x3A, 0x31, 0x84, 0x89, 0x21, 0x41, 0xF0, 0xB8, + 0xCB, 0x20, 0x68, 0x23, 0x26, 0x28, 0x2A, 0x2C, 0x2F, 0x2F, 0x2E, 0x00, 0x2B, 0x28, 0x28, 0x01, + 0x10, 0x27, 0x27, 0x27, 0x27, 0x08, 0x26, 0x24, 0x21, 0x08, 0x85, 0x41, 0xF0, 0xCB, 0xF8, 0x21, + 0x28, 0x38, 0x2F, 0x35, 0x38, 0x39, 0x36, 0x31, 0x2B, 0x24, 0x00, 0x1F, 0x1D, 0x01, 0x10, 0x1C, + 0x1C, 0x1C, 0xC3, 0x50, 0x41, 0xF0, 0xC4, 0x39, 0xF8, 0x40, 0x20, 0x2D, 0x3A, 0x56, 0xA8, 0xBE, + 0xBE, 0x03, 0xBE, 0xA7, 0x63, 0x34, 0x42, 0x40, 0x41, 0xF0, 0xB1, 0xF7, 0xA8, 0x02, 0xF0, 0xE5, + 0x06, 0x77, 0xB3, 0x8A, 0x08, 0x25, 0x30, 0x41, 0xAA, 0x11, 0xED, 0xD3, 0xAC, 0xA1, 0xAD, 0xCA, + 0xF5, 0xB2, 0x00, 0x39, 0x37, 0x33, 0x41, 0xF0, 0x41, 0xF0, 0x50, 0x49, 0x6D, 0x71, 0x03, 0x1B, + 0x5E, 0x20, 0x2D, 0x41, 0xAB, 0xE4, 0x80, 0x4E, 0x48, 0x00, 0x46, 0x4A, 0x53, 0x77, 0xE4, 0xBD, + 0x35, 0x24, 0x00, 0x44, 0x94, 0x41, 0xF0, 0x4D, 0xF5, 0x09, 0x15, 0x26, 0x3A, 0x7C, 0xF5, 0x0F, + 0x7F, 0x45, 0x37, 0x30, 0x2F, 0x32, 0x3F, 0x51, 0x00, 0x78, 0xF5, 0x74, 0x2D, 0xAE, 0x32, 0x41, + 0xF0, 0x4D, 0xF5, 0x9D, 0x6A, 0xF0, 0x1F, 0x2D, 0x45, 0xC1, 0xC1, 0x47, 0x30, 0x23, 0x00, 0x1F, + 0x1F, 0x21, 0x2A, 0x3D, 0x54, 0xC1, 0xBE, 0x00, 0x35, 0x22, 0x01, 0x10, 0x41, 0xF0, 0xA5, 0xF2, + 0x3D, 0x44, 0x15, 0x0A, 0x20, 0x7C, 0x33, 0x4C, 0xED, 0x88, 0x39, 0x24, 0x84, 0x10, 0x1F, 0x40, + 0x2F, 0x49, 0x8D, 0xED, 0x3B, 0x44, 0x0D, 0x41, 0xF0, 0x41, 0xF0, 0xE0, 0x64, 0x02, 0x27, 0x0B, + 0xBB, 0xB3, 0xB5, 0x13, 0x21, 0x37, 0x4F, 0x13, 0xF5, 0x49, 0x30, 0xED, 0x21, 0x1D, 0x28, 0x40, + 0x55, 0x08, 0xF5, 0x3F, 0x15, 0x40, 0x41, 0xF0, 0x2D, 0xF3, 0xAF, 0x07, 0x2D, 0x41, 0x50, 0xBC, + 0x42, 0x2C, 0xB8, 0x32, 0x24, 0x3B, 0x52, 0xF5, 0x40, 0x04, 0xB1, 0xF7, 0x1B, 0x41, 0xF0, 0x41, + 0xF0, 0x41, 0x41, 0xD0, 0x41, 0xF0, 0x41, 0xF0, 0xED, 0x79, 0xF7, 0x41, 0xF0, 0x41, 0xF0, 0xD0, + 0xD9, 0x8A, 0x8A, 0x8A, 0x8A, 0x0F, 0x8A, 0x93, 0xAC, 0x09, 0x50, 0x29, 0xB7, 0xF9, 0xF3, 0x41, + 0xF0, 0x8C, 0x0D, 0xF8, 0x81, 0x1F, 0x0F, 0x81, 0xBB, 0x81, 0x41, 0x10, 0x50, 0xF5, 0x22, 0x45, + 0x30, 0x70, 0x33, 0x29, 0x3F, 0x54, 0xF5, 0x46, 0x04, 0x30, 0x72, 0x23, 0x20, 0x71, 0xE3, 0xA5, + 0xF2, 0x3D, 0x20, 0x77, 0x9B, 0x3A, 0xAD, 0x16, 0x52, 0xF5, 0x52, 0x09, 0x00, 0x07, 0x10, 0x3B, + 0x4E, 0x31, 0x61, 0xF5, 0x54, 0x41, 0x35, 0x35, 0x35, 0x35, 0x00, 0x34, 0x30, 0x29, 0x21, 0x0D, + 0xF1, 0x41, 0xF0, 0x11, 0x4E, 0x36, 0x70, 0x50, 0xF5, 0xAF, 0x09, 0x00, 0x07, 0x10, 0xAA, 0xAF, + 0xB4, 0x18, 0xF5, 0xB1, 0xAC, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8, 0x00, 0xA5, 0xA2, 0x99, 0xCE, 0x1D, + 0xF2, 0xA1, 0x22, 0x11, 0x3E, 0x30, 0x46, 0x3C, 0xC1, 0xC2, 0x09, 0x10, 0x06, 0x10, 0xC2, 0xC4, + 0xC5, 0xC3, 0x0C, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0xBD, 0xBA, 0x00, 0x2A, 0x41, 0xB0, 0x6D, + 0xF7, 0x41, 0x00, 0x8A, 0xA4, 0x3D, 0x8A, 0x0E, 0xA4, 0x95, 0x01, 0x27, 0x35, 0x43, 0x49, 0x09, + 0x00, 0x07, 0x10, 0xC2, 0x49, 0x4B, 0x4E, 0x4F, 0x4C, 0x49, 0x48, 0x48, 0x00, 0x48, 0x48, 0x46, + 0x40, 0x34, 0x51, 0x91, 0x41, 0xF0, 0x01, 0x10, 0xE0, 0xC7, 0x00, 0x9B, 0xBB, 0xB3, 0x4A, 0xC9, + 0x10, 0x25, 0x2C, 0x21, 0x01, 0x10, 0x06, 0x30, 0x31, 0x31, 0x31, 0x00, 0x00, 0x30, 0x30, 0x23, + 0x30, 0x2C, 0x27, 0xC9, 0x00, 0x41, 0xF0, 0xA1, 0xF2, 0x42, 0x40, 0x06, 0x60, 0xF8, 0x03, 0x30, + 0x00, 0x00, 0x1F, 0xDD, 0xA6, 0x41, 0xF0, 0xBF, 0xF3, 0x02, 0x20, 0xCD, 0xFD, 0xFB, 0x95, 0xF1, + 0x17, 0xD6, 0x62, 0x6D, 0x62, 0x2D, 0x90, 0x48, 0x29, 0x43, 0x2E, 0x03, 0x30, 0x03, 0x30, 0x00, + 0x00, 0x2F, 0x2F, 0x2F, 0x2B, 0x0E, 0x7D, 0xF8, 0x95, 0xF1, 0xB3, 0x9B, 0xAC, 0x95, 0x21, 0x1D, + 0x23, 0x23, 0x2F, 0x60, 0x66, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x68, 0x68, 0x38, 0x68, 0x67, + 0x63, 0x5B, 0x27, 0x85, 0x10, 0x41, 0xF0, 0x0D, 0xF1, 0xE0, 0x39, 0x03, 0x28, 0x39, 0x07, 0x70, + 0x03, 0x30, 0x00, 0x00, 0xF5, 0xF5, 0x39, 0xF5, 0x2C, 0x20, 0x41, 0x90, 0x41, 0xF0, 0x27, 0x1B, + 0x25, 0x2B, 0xF5, 0x17, 0xF8, 0x34, 0x44, 0x4F, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x52, 0x52, + 0x38, 0x52, 0x51, 0x49, 0x3A, 0x29, 0xE0, 0x12, 0x41, 0xF0, 0x2D, 0xF3, 0xE0, 0x42, 0x00, 0x20, + 0x28, 0x31, 0x38, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE1, 0x39, 0x39, 0x39, 0x34, 0x2C, 0x23, + 0xA9, 0xBF, 0xE9, 0xF2, 0xC0, 0xAC, 0x32, 0x4A, 0xBB, 0x3B, 0x27, 0x20, 0x21, 0xAC, 0xCF, 0x22, + 0x49, 0x22, 0xA9, 0xFF, 0xB5, 0xF3, 0xEA, 0x2F, 0x57, 0xAC, 0xAD, 0x63, 0x38, 0xF0, 0xCE, 0x41, + 0xF0, 0xDD, 0xFE, 0xA4, 0x9B, 0xA4, 0xBB, 0x81, 0x06, 0x60, 0x83, 0x37, 0xF0, 0x41, 0xF0, 0xD6, + 0xF5, 0xC3, 0x00, 0xD4, 0xC5, 0x1D, 0xF0, 0x41, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x19, 0xF0, + 0x41, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x41, 0xF0, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x6D, + 0x6D, 0xD9, 0xC1, 0x33, 0xF0, 0x41, 0xF0, 0x15, 0xFA, 0x03, 0x30, 0xF9, 0x23, 0xF0, 0x41, 0xF0, + 0x41, 0xF0, 0x19, 0xF0, 0xE2, 0x3F, 0x20, 0x91, 0xAD, 0x1B, 0x5F, 0x41, 0xF0, 0x24, 0xF0, 0xA6, + 0xD2, 0x24, 0x2A, 0x56, 0x26, 0x61, 0xD2, 0x87, 0x41, 0xF0, 0xF8, 0xCC, 0xD9, 0xC1, 0x2C, 0x39, + 0xF5, 0x31, 0x24, 0x07, 0x15, 0x90, 0x41, 0xF0, 0xA5, 0xF2, 0x15, 0xD0, 0x46, 0xF5, 0x15, 0x10, + 0x41, 0xF0, 0xCF, 0xE5, 0xF6, 0x57, 0xBB, 0x00, 0x00, 0x57, 0x57, 0x57, 0x77, 0x09, 0x7D, 0xC0, + 0x22, 0x38, 0x4D, 0xF5, 0x3F, 0xC9, 0x50, 0x41, 0xF0, 0xC1, 0xBC, 0xBC, 0xBB, 0x00, 0x00, 0xAC, + 0xAC, 0xAC, 0xA4, 0xA5, 0x92, 0x85, 0x41, 0xF0, 0x41, 0xF0, 0xD9, 0xF1, 0x41, 0xF0, 0x39, 0x4F, + 0xF5, 0x40, 0x0F, 0xCE, 0x14, 0x41, 0xF0, 0x41, 0xF0, 0xD5, 0x3D, 0x85, 0xF5, 0x37, 0x4B, 0xF5, + 0x1F, 0x3E, 0x46, 0x74, 0x41, 0xF0, 0x26, 0xF0, 0x15, 0xF0, 0x32, 0x44, 0xF5, 0x1E, 0x39, 0xEE, + 0x76, 0x1B, 0x41, 0xF0, 0xA5, 0xF2, 0x6D, 0xFC, 0x36, 0x7C, 0x3A, 0x2F, 0x23, 0x15, 0xB0, 0x41, + 0xF0, 0xA5, 0xF2, 0x71, 0xAB, 0x22, 0x28, 0x3C, 0x2A, 0x25, 0x1F, 0x15, 0x90, 0x41, 0xF0, 0xA5, + 0xF2, 0x11, 0xC0, 0x6E, 0x0C, 0xF8, 0xE3, 0xAE, 0x41, 0xF0, 0xA5, 0xF2, 0x41, 0xC0, 0x33, 0xF0, + 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0x33, + 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0A, 0xA0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x09, 0x90, + 0x1E, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x04, 0x40, 0xFF, 0x25, 0xF0, 0xD5, 0xF5, 0x41, 0xF0, 0x53, + 0xF2, 0x85, 0xFE, 0x4D, 0xF5, 0xE3, 0xFA, 0x81, 0x7F, 0x8A, 0x81, 0xA9, 0x3B, 0x1E, 0x21, 0x26, + 0x26, 0x23, 0x04, 0x1F, 0x1C, 0x33, 0xAD, 0x24, 0x28, 0x29, 0x26, 0x05, 0x89, 0x84, 0x41, 0xF0, + 0x47, 0x20, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0xA4, 0x03, 0x2D, 0x81, 0x24, 0x40, 0x41, 0x39, 0x28, + 0x1F, 0xCB, 0x18, 0x82, 0x21, 0x21, 0x20, 0x1E, 0x1B, 0x2A, 0x24, 0x68, 0x6A, 0x20, 0x62, 0x2B, + 0x3D, 0xA4, 0x41, 0xF0, 0x93, 0xA4, 0x58, 0x16, 0x2D, 0x4C, 0xA4, 0x93, 0x10, 0x10, 0x4C, 0x10, + 0x10, 0x23, 0x84, 0x09, 0x2B, 0x54, 0x35, 0x37, 0xBB, 0x07, 0x96, 0x1F, 0x4F, 0x2E, 0x00, 0x39, + 0x24, 0x2C, 0x41, 0xA0, 0x41, 0xF0, 0x55, 0x31, 0x3D, 0x2D, 0x23, 0x63, 0x18, 0x29, 0x34, 0x04, + 0xD7, 0x41, 0xC7, 0xC8, 0xC4, 0x31, 0x21, 0x0E, 0x5F, 0x46, 0x40, 0xA1, 0xB6, 0x55, 0xFE, 0x9A, + 0x52, 0x10, 0x70, 0x34, 0x64, 0xB2, 0x14, 0x6E, 0x2E, 0x00, 0xBF, 0x4D, 0xA5, 0xB2, 0x65, 0xFF, + 0xA5, 0x36, 0x6D, 0xAC, 0x10, 0x70, 0x34, 0x64, 0xCE, 0x2E, 0x40, 0x41, 0xF0, 0xD2, 0xD9, 0xBB, + 0x77, 0x2D, 0x1B, 0x2D, 0x07, 0x77, 0xBB, 0x6D, 0x10, 0x70, 0x34, 0x64, 0x2E, 0x40, 0x41, 0xF0, + 0x08, 0xE9, 0xF8, 0x98, 0x1E, 0xAC, 0x62, 0x41, 0xC0, 0x41, 0xF0, 0x41, 0xF0, 0x77, 0xC8, 0x41, + 0x60, 0xF9, 0x41, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xB5, 0xF3, 0x07, 0x60, 0xA2, 0xF3, 0x41, 0xF0, + 0x71, 0xF3, 0xFF, 0x06, 0x20, 0x07, 0x40, 0x55, 0x32, 0x24, 0x24, 0x2B, 0x47, 0x03, 0x44, 0x09, + 0x41, 0xF0, 0x47, 0xBD, 0x8A, 0x81, 0x4A, 0x1B, 0x77, 0x07, 0xB3, 0xBB, 0xD5, 0x55, 0x06, 0x20, + 0x07, 0x40, 0x6B, 0x44, 0x05, 0x46, 0x5C, 0x5E, 0xBC, 0x08, 0x41, 0xF0, 0xC8, 0xB4, 0x93, 0x73, + 0x07, 0xAC, 0x62, 0x2E, 0x3D, 0x6D, 0xAC, 0x3D, 0x34, 0x06, 0x20, 0x07, 0x40, 0xD1, 0xCF, 0x38, + 0xCD, 0xCD, 0xCF, 0xD1, 0xD2, 0x41, 0xC0, 0x91, 0xF5, 0x77, 0x60, 0x80, 0x14, 0x8D, 0x15, 0x57, + 0xBB, 0xA5, 0x32, 0x40, 0xF0, 0x92, 0x52, 0x41, 0xF0, 0xF3, 0x41, 0xF0, 0x1D, 0x02, 0x3E, 0x6D, + 0x01, 0x10, 0x3D, 0xF0, 0x4C, 0x0A, 0x12, 0xB3, 0x41, 0xF0, 0x41, 0xF0, 0xF1, 0x1B, 0x61, 0x01, + 0x10, 0x29, 0xF3, 0x44, 0x21, 0x8F, 0xB7, 0x41, 0xF0, 0x03, 0x20, 0x61, 0x5B, 0x1F, 0x21, 0xFF, + 0x21, 0xFF, 0xD5, 0xF5, 0x03, 0x20, 0xF7, 0xAE, 0x27, 0xBB, 0x1B, 0xF6, 0x1F, 0x47, 0x51, 0x52, + 0x50, 0x09, 0x21, 0xAF, 0x4E, 0x4E, 0x4B, 0x44, 0x38, 0x65, 0x2F, 0x41, 0xF0, 0xC1, 0xB1, 0xF7, + 0x51, 0x04, 0x25, 0x32, 0x41, 0x45, 0x3F, 0x34, 0x03, 0x21, 0x0F, 0x03, 0x30, 0x00, 0x00, 0x1E, + 0x0F, 0x29, 0x28, 0x24, 0x02, 0x6A, 0x8F, 0x41, 0xF0, 0x45, 0xFD, 0x42, 0x34, 0x0F, 0x34, 0x24, + 0x01, 0x10, 0x03, 0x30, 0xCB, 0x00, 0x00, 0x1D, 0x35, 0x59, 0x41, 0xF0, 0x19, 0xF0, 0x34, 0xBF, + 0x1B, 0xF0, 0x41, 0xF0, 0xFD, 0x19, 0xF0, 0xB5, 0x83, 0x1E, 0xF0, 0x41, 0xF0, 0x1C, 0xF0, 0x21, + 0x9F, 0x2D, 0x83, 0x15, 0xF0, 0xFF, 0x41, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x91, 0xD5, 0x41, 0xF0, + 0x41, 0xF0, 0x57, 0x34, 0x3F, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x26, 0x26, 0x26, 0x24, 0x21, + 0x07, 0x1E, 0x1C, 0x41, 0x80, 0x51, 0xF1, 0x99, 0xFE, 0x6D, 0x51, 0x04, 0x40, 0x9C, 0x45, 0x00, + 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x32, 0x02, 0x26, 0x01, 0xDD, 0x38, 0xAC, 0xAA, 0x83, 0x41, + 0x50, 0xE1, 0xE1, 0x04, 0x40, 0x9E, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0xDE, 0xDA, 0x02, + 0x34, 0x22, 0x41, 0xC0, 0xC4, 0xA8, 0x4A, 0xB2, 0x73, 0x41, 0x50, 0x3E, 0xF0, 0xEC, 0x85, 0xF0, + 0xCD, 0xB0, 0x81, 0xDB, 0x31, 0x8A, 0xBB, 0x77, 0x41, 0x50, 0x8B, 0x3E, 0xF0, 0x69, 0xFB, 0xCA, + 0xD0, 0x57, 0xB2, 0x13, 0x9B, 0x3D, 0x65, 0x7F, 0x97, 0xDD, 0xFA, 0x41, 0xE1, 0xFA, 0xC7, 0xC0, + 0x8A, 0x9B, 0xB3, 0x6D, 0x0D, 0x41, 0x80, 0x7E, 0x76, 0x04, 0x40, 0x70, 0x00, 0x00, 0x70, 0x70, + 0x29, 0x70, 0x6E, 0x63, 0x4C, 0x35, 0xCC, 0x51, 0xF1, 0x81, 0xBB, 0x30, 0xBB, 0x6D, 0x01, 0x9D, + 0x6A, 0x4C, 0x04, 0x40, 0x40, 0x00, 0x00, 0xA4, 0x40, 0xD1, 0xD9, 0x41, 0xF0, 0xF5, 0x0F, 0xA4, + 0xAC, 0x62, 0x77, 0x0E, 0xE7, 0x02, 0xBD, 0x7C, 0x54, 0x30, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, + 0x22, 0x73, 0x22, 0x22, 0x21, 0x1F, 0xA5, 0xD2, 0x2D, 0xF3, 0x5F, 0x32, 0x79, 0x8C, 0xF0, 0x3A, + 0xD1, 0x1C, 0xF7, 0x83, 0x21, 0x2D, 0xF3, 0xAC, 0x57, 0xD7, 0x41, 0x95, 0xB3, 0x9B, 0x35, 0x1C, + 0xF1, 0x1B, 0x4F, 0x70, 0x46, 0x85, 0x61, 0x27, 0x6C, 0x25, 0x20, 0x6D, 0xD7, 0xD8, 0xA5, 0xCA, + 0x79, 0x9B, 0x7C, 0x7B, 0xB8, 0x70, 0xDC, 0xBD, 0x04, 0x34, 0x3E, 0x41, 0x80, 0x2B, 0xE5, 0x56, + 0x41, 0xF0, 0xC1, 0x05, 0xF9, 0x59, 0xF0, 0xF0, 0xEF, 0xDC, 0x60, 0x1D, 0x20, 0x21, 0x09, 0x05, + 0x4A, 0x6B, 0xB9, 0xE6, 0xFF, 0x39, 0xC9, 0x10, 0x81, 0x41, 0xF0, 0x3B, 0xF0, 0x59, 0x2A, 0x54, + 0x58, 0x49, 0x30, 0x21, 0x07, 0xC1, 0x50, 0x81, 0x04, 0xA4, 0x17, 0x26, 0xC5, 0x24, 0x41, 0xF0, + 0xC3, 0xF0, 0xF5, 0x17, 0xFB, 0x29, 0x32, 0x33, 0x2E, 0x24, 0x1E, 0xC1, 0x50, 0x7C, 0x40, 0xBC, + 0x80, 0x30, 0x09, 0xF5, 0xAC, 0xCF, 0xA9, 0x6F, 0x85, 0x20, 0x1F, 0x1F, 0x3E, 0x1F, 0xD3, 0x19, + 0x2F, 0x39, 0x49, 0xC1, 0x00, 0x2C, 0x63, 0x71, 0xE3, 0xE2, 0x5F, 0xBA, 0x00, 0x00, 0x5A, 0x0A, + 0x4A, 0x93, 0xBB, 0x77, 0x76, 0x53, 0x87, 0x24, 0x2B, 0x35, 0x42, 0x52, 0x98, 0xC1, 0x60, 0xF1, + 0x40, 0xC0, 0x90, 0x4D, 0xE9, 0xF2, 0x1B, 0x1B, 0xCE, 0xF9, 0x9B, 0x48, 0x3D, 0xEE, 0x32, 0x22, + 0x28, 0x31, 0x3E, 0x4D, 0x7B, 0x02, 0xBC, 0xF0, 0x1C, 0x62, 0xA6, 0x6C, 0x55, 0x42, 0x61, 0xF2, + 0x84, 0xD2, 0xF9, 0x93, 0xB3, 0x54, 0x1A, 0x45, 0x2D, 0x37, 0x47, 0x69, 0x19, 0xB0, 0xE0, 0x94, + 0x51, 0xDA, 0x36, 0x00, 0x6A, 0x45, 0x30, 0x14, 0x27, 0x21, 0x91, 0xA5, 0x41, 0xF0, 0xBF, 0x1C, + 0x93, 0x3D, 0x51, 0x61, 0x9C, 0x92, 0xCF, 0xF8, 0x3E, 0x60, 0x88, 0x7F, 0x51, 0x11, 0x30, 0x48, + 0x1F, 0x1D, 0x41, 0xF0, 0x4D, 0xC9, 0x9B, 0xAC, 0x62, 0xA1, 0x66, 0x8C, 0x32, 0x56, 0x11, 0x41, + 0xDA, 0xB7, 0x7C, 0x5F, 0x55, 0x04, 0x62, 0xC9, 0x10, 0x50, 0x41, 0x00, 0x41, 0xF0, 0x93, 0xB5, + 0xBB, 0x81, 0x3A, 0xC6, 0x54, 0x41, 0x60, 0xF8, 0xC1, 0x8A, 0x77, 0x5F, 0x4A, 0x03, 0x39, 0x35, + 0x41, 0x60, 0x41, 0xF0, 0x84, 0xA4, 0xBB, 0x9B, 0xD5, 0x65, 0x9C, 0x2D, 0x13, 0x89, 0x4D, 0xDA, + 0xAC, 0x6E, 0x49, 0x39, 0x34, 0x03, 0x49, 0x74, 0x41, 0x40, 0x41, 0xF0, 0xE0, 0xFE, 0x4D, 0x55, + 0x1F, 0x32, 0x3C, 0x57, 0xD1, 0xD1, 0x40, 0xF8, 0xD6, 0x9E, 0x52, 0x61, 0x04, 0x7C, 0xC6, 0xA8, + 0x41, 0xF0, 0x3B, 0xF0, 0x1D, 0x12, 0x3E, 0x5B, 0x80, 0x1E, 0xD1, 0x60, 0xF8, 0xD1, 0xB0, 0x3A, + 0x00, 0x55, 0x2F, 0x14, 0x8E, 0x91, 0x1B, 0x41, 0xF0, 0x95, 0xF1, 0x29, 0x38, 0xD1, 0x00, 0x8F, + 0xC1, 0x26, 0xF1, 0x8A, 0x75, 0x69, 0x43, 0x2F, 0x27, 0x21, 0x42, 0x30, 0x82, 0x41, 0xF0, 0x3A, + 0xF0, 0x68, 0x2B, 0xD1, 0x90, 0x98, 0x22, 0xB9, 0x72, 0x41, 0x1F, 0xF5, 0x23, 0x41, 0xF0, 0x3C, + 0xF0, 0xD1, 0xA0, 0x54, 0x67, 0x82, 0xB8, 0x0F, 0xE1, 0xAF, 0x53, 0xE6, 0xAF, 0xC5, 0x24, 0x41, + 0xF0, 0x3B, 0xF0, 0xD1, 0x90, 0xF2, 0x2F, 0x3B, 0x49, 0x5B, 0x6C, 0x90, 0xC1, 0xF1, 0x00, 0xC5, + 0x54, 0x1D, 0x32, 0x41, 0xF0, 0x39, 0xF0, 0xD1, 0x80, 0x23, 0x29, 0x33, 0x1F, 0x3F, 0x4F, 0x61, + 0x72, 0xA5, 0xD2, 0x95, 0xB1, 0x41, 0xF0, 0xC0, 0x40, 0xF0, 0xE1, 0x0D, 0xC4, 0x5D, 0x1F, 0x25, + 0x2C, 0x36, 0x44, 0x07, 0x55, 0x68, 0x83, 0xC1, 0xE9, 0x51, 0x41, 0x41, 0xF0, 0xAF, 0xF3, 0xE0, + 0xD1, 0x19, 0x25, 0x27, 0x23, 0x1E, 0x25, 0xE0, 0x3F, 0x21, 0x27, 0x31, 0x30, 0x3B, 0x4D, 0x65, + 0x79, 0x9C, 0xDE, 0x99, 0xDE, 0x80, 0x15, 0xFA, 0x00, 0x00, 0x8A, 0x8A, 0x8A, 0x8A, 0x49, 0x19, + 0x35, 0x43, 0xA9, 0x36, 0x2A, 0x2E, 0x52, 0xD9, 0x22, 0x27, 0x35, 0x4F, 0x18, 0x6B, 0x99, 0xEF, + 0x44, 0x41, 0xB0, 0x7D, 0xF8, 0xB3, 0x81, 0x30, 0xE9, 0x52, 0x20, 0x31, 0x4B, 0xFF, 0xB2, 0x43, + 0x2C, 0x01, 0x21, 0xE9, 0x61, 0x1D, 0x21, 0x2B, 0x40, 0x5E, 0xBF, 0x02, 0x9D, 0xEA, 0x41, 0xF0, + 0x69, 0x3F, 0x71, 0x33, 0x60, 0x98, 0x00, 0x49, 0x30, 0x2F, 0x16, 0x59, 0x1E, 0x24, 0x31, 0x48, + 0x80, 0x42, 0x11, 0x4A, 0x41, 0x91, 0xB5, 0x51, 0xF1, 0x31, 0x81, 0x3D, 0x1C, 0x15, 0xE7, 0x6F, + 0x34, 0x17, 0x25, 0x1E, 0x44, 0x41, 0x52, 0xA8, 0xF8, 0xF5, 0x37, 0x41, 0xF0, 0xC4, 0x0E, 0xAE, + 0x70, 0x5B, 0x45, 0x1D, 0x89, 0x2D, 0xF0, 0x81, 0x39, 0x27, 0x0F, 0x1F, 0x1C, 0x1D, 0x22, 0x2E, + 0x42, 0x6E, 0xD8, 0x00, 0x82, 0x20, 0xD5, 0x3F, 0xF5, 0xB7, 0x41, 0xF0, 0xB3, 0x6D, 0x8A, 0x39, + 0x99, 0xBD, 0x1C, 0x54, 0xAE, 0xD2, 0x10, 0xF8, 0x9D, 0x3D, 0x29, 0x09, 0x22, 0x27, 0x35, 0x4D, + 0x90, 0xF0, 0x18, 0x22, 0xA9, 0x40, 0x4F, 0x30, 0xF5, 0x27, 0x41, 0xF0, 0xC4, 0x7C, 0x8D, 0x69, + 0x1D, 0x27, 0x3C, 0x3C, 0x60, 0x9B, 0x57, 0x11, 0xFF, 0xB6, 0x46, 0x39, 0x08, 0x41, 0x5A, 0xC7, + 0x40, 0x20, 0xE1, 0x84, 0x4D, 0x34, 0x08, 0x24, 0xF5, 0xB7, 0x71, 0xF3, 0x8A, 0x2D, 0x42, 0x70, + 0x29, 0x3E, 0x26, 0x5B, 0x85, 0x05, 0x20, 0xCE, 0x65, 0x86, 0xE9, 0x7F, 0x20, 0x84, 0xBF, 0x60, + 0x43, 0x2F, 0x23, 0xC5, 0x10, 0x41, 0xF0, 0xE9, 0xF2, 0xE0, 0x68, 0x3B, 0x28, 0x39, 0x55, 0x75, + 0x56, 0x21, 0xE9, 0x82, 0x20, 0xA1, 0xE9, 0x94, 0x52, 0xEC, 0x02, 0x25, 0xDB, 0x61, 0xF2, 0x42, + 0xA0, 0x1E, 0x78, 0x25, 0x34, 0x4F, 0x70, 0xC1, 0x4B, 0x51, 0xC9, 0x64, 0x20, 0x47, 0x31, 0x25, + 0x1E, 0x41, 0xE0, 0x85, 0xF0, 0x9B, 0x2D, 0x30, 0x1B, 0x90, 0x1D, 0x22, 0x30, 0x49, 0x6A, 0xAF, + 0xF8, 0x01, 0xCB, 0x10, 0xF1, 0xA5, 0x5F, 0x3E, 0x2B, 0x21, 0x1D, 0x01, 0xD1, 0xE9, 0x41, 0xF0, + 0xBC, 0x0C, 0x3B, 0x34, 0x28, 0x17, 0x1F, 0x21, 0x23, 0x1F, 0x25, 0x2A, 0x36, 0x4C, 0x6C, 0x9D, + 0xF1, 0x42, 0x10, 0x80, 0x99, 0x51, 0x34, 0x28, 0x25, 0x24, 0x24, 0x22, 0x00, 0x20, 0x1E, 0x49, + 0xC9, 0x8D, 0xF9, 0x8B, 0x39, 0xA1, 0x16, 0x21, 0x2B, 0x3C, 0x37, 0x3D, 0x41, 0x41, 0x45, 0x4F, + 0x63, 0x7C, 0x00, 0x8A, 0xE9, 0x42, 0x10, 0x8C, 0x4C, 0x42, 0x40, 0x40, 0x04, 0x3F, 0x39, 0x30, + 0x25, 0x1E, 0x0C, 0x30, 0x41, 0xF0, 0xE5, 0xF6, 0xE0, 0x2B, 0x41, 0xC8, 0xCC, 0xCD, 0xCD, 0xCE, + 0xCF, 0x00, 0xD0, 0xD2, 0xD2, 0xD2, 0x37, 0x10, 0xF8, 0xD0, 0xCE, 0x10, 0xCD, 0xCD, 0xCD, 0xCA, + 0xC4, 0x31, 0xD9, 0x11, 0x41, 0xF0, 0xC0, 0x5B, 0xF2, 0xEC, 0x51, 0xFF, 0x3D, 0xF0, 0xD9, 0xF1, + 0xD8, 0xE1, 0x81, 0x8A, 0x3B, 0x81, 0xDA, 0x01, 0x9D, 0x1A, 0x66, 0x00, 0x00, 0x3E, 0xF0, 0x9D, + 0xFA, 0x2F, 0xE7, 0xF6, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0x3B, 0x10, 0x20, 0x38, 0x20, 0x5F, 0x01, + 0x10, 0xF5, 0xF3, 0x43, 0xE5, 0x36, 0x41, 0xF0, 0x25, 0x52, 0xA4, 0x76, 0x09, 0x19, 0x2D, 0x3D, + 0x14, 0x1F, 0x2F, 0x49, 0x99, 0xA1, 0x05, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0xA4, 0xA4, 0xA4, + 0xA3, 0x9D, 0x07, 0x8E, 0x36, 0x23, 0x41, 0x70, 0x41, 0xF0, 0x41, 0x14, 0xE5, 0x76, 0x26, 0x78, + 0x35, 0x45, 0x4F, 0x52, 0x4F, 0x03, 0x30, 0x4E, 0x00, 0x00, 0xA0, 0x4E, 0x4E, 0x4E, 0x4F, 0x52, + 0x52, 0x4B, 0x3C, 0x00, 0x2A, 0x41, 0x00, 0x41, 0xF0, 0xA5, 0xF2, 0xA1, 0x16, 0x24, 0x30, 0x3D, + 0x1E, 0x41, 0x3C, 0x32, 0x2D, 0x2A, 0xC0, 0x44, 0x2A, 0x2A, 0x20, 0x2A, 0x2B, 0x31, 0x3A, 0x44, + 0x42, 0x39, 0x28, 0x00, 0x09, 0xA5, 0x41, 0xF0, 0xAC, 0x30, 0x37, 0x6D, 0x05, 0x09, 0x1F, 0x2A, + 0x2B, 0x3F, 0xB1, 0xB2, 0xAD, 0x31, 0x23, 0x1D, 0x1E, 0x00, 0x20, 0x26, 0x8A, 0x04, 0x22, 0x1F, + 0x1D, 0x1D, 0x20, 0x04, 0x2D, 0x44, 0xC8, 0xC8, 0xC5, 0x32, 0x21, 0x41, 0xC0, 0x80, 0xA8, 0xE6, + 0x77, 0x2D, 0x1B, 0x2D, 0x77, 0xE5, 0x16, 0x20, 0x41, 0x34, 0x57, 0x10, 0x00, 0x3E, 0x25, 0x30, + 0x18, 0x68, 0x6A, 0x24, 0x43, 0x28, 0x20, 0x35, 0x5A, 0x2E, 0x00, 0x40, 0x09, 0x75, 0x41, 0xF0, + 0xD1, 0xB5, 0x27, 0xAC, 0x4A, 0x05, 0xAC, 0x62, 0x1B, 0xE9, 0x22, 0x10, 0x20, 0xC5, 0x30, 0x18, + 0x43, 0x48, 0x21, 0x3C, 0x6B, 0x2E, 0x00, 0xE9, 0xF2, 0x95, 0xF5, 0xE3, 0x3D, 0xA3, 0x16, 0x10, + 0x70, 0x30, 0x08, 0x74, 0x18, 0x46, 0x28, 0x4E, 0x22, 0x9E, 0x61, 0xF2, 0x95, 0xF1, 0x22, 0xF6, + 0x14, 0x02, 0x6E, 0x07, 0x00, 0x4D, 0x29, 0x2F, 0x2E, 0x20, 0x41, 0xF0, 0x2D, 0xF3, 0x22, 0x40, + 0x93, 0x10, 0x30, 0x41, 0xF0, 0x41, 0xF0, 0xEF, 0xC9, 0xF0, 0x80, 0x44, 0xBB, 0x10, 0x50, 0x41, + 0xF0, 0x41, 0xF0, 0x4F, 0xC5, 0xBB, 0x7B, 0x4C, 0x35, 0xB3, 0xA4, 0x10, 0x70, 0x07, 0x60, 0x2E, + 0x40, 0x41, 0xF0, 0xA8, 0xB2, 0xF9, 0x6D, 0xBB, 0x00, 0x00, 0x6D, 0x7A, 0x08, 0x2D, 0x41, 0x20, + 0x06, 0x20, 0xD4, 0xD5, 0x65, 0xCB, 0x25, 0x41, 0xF0, 0x51, 0xF1, 0x41, 0xA0, 0x06, 0x20, 0xD5, + 0x65, 0xCB, 0x25, 0xFF, 0x41, 0xA0, 0x41, 0xF0, 0x41, 0xF0, 0x06, 0x20, 0xD5, 0x65, 0xCB, 0x25, + 0x41, 0xB0, 0x41, 0xF0, 0xFF, 0xCE, 0xF4, 0x40, 0xF0, 0x33, 0x24, 0x41, 0x80, 0x41, 0xF0, 0x9A, + 0x21, 0x2D, 0x8A, 0x3F, 0xAC, 0x98, 0x16, 0x22, 0x3F, 0x6F, 0x01, 0x10, 0x3D, 0xF0, 0x4E, 0x62, + 0x29, 0x41, 0x90, 0x41, 0xF0, 0x8A, 0xAC, 0x4A, 0x1B, 0x9B, 0x06, 0xA4, 0x6D, 0xA4, 0x93, 0x1D, + 0x12, 0x69, 0x01, 0x10, 0xD5, 0xF1, 0xD0, 0x49, 0x1D, 0xC2, 0x85, 0xF0, 0x3D, 0x00, 0x3D, 0x1B, + 0x3D, 0xD5, 0x45, 0x8E, 0xD5, 0xF5, 0xD5, 0xF5, 0x41, 0xF0, 0xC7, 0x00, 0x7D, 0x14, 0xBB, 0xD5, + 0x25, 0xD5, 0xF5, 0xDF, 0xD5, 0xF5, 0x41, 0xF0, 0x44, 0x00, 0x8A, 0x8A, 0xCB, 0x15, 0xD5, 0x85, + 0xD5, 0xF5, 0xE7, 0x41, 0xF0, 0x3A, 0xB4, 0x93, 0xBB, 0x4A, 0x1B, 0x4A, 0xA4, 0x03, 0x77, 0xB5, + 0x13, 0x22, 0x28, 0x2A, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE2, 0x2B, 0x2B, 0x2B, 0x28, 0x24, + 0x1F, 0x1D, 0xD2, 0x23, 0xE2, 0xC0, 0x77, 0x4A, 0x9F, 0x12, 0xDA, 0x11, 0x23, 0x2E, 0x3A, 0x41, + 0x0C, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x07, 0x32, 0x26, 0x95, + 0x11, 0x41, 0xF0, 0x3B, 0xF0, 0x0D, 0x11, 0x45, 0xDC, 0x3C, 0xDF, 0x02, 0x20, 0x03, 0x30, 0x00, + 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0x0E, 0xDE, 0xDA, 0x0D, 0x21, 0x41, 0xF0, 0xC3, 0xF0, 0x85, 0x10, + 0x5D, 0x01, 0x10, 0xBC, 0x3D, 0xF0, 0x41, 0x26, 0x41, 0x90, 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x79, 0x57, 0x24, 0x03, 0x21, 0x3B, 0x67, 0x01, 0x10, 0x3D, 0xF0, 0x48, 0x62, 0x71, 0xA3, + 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xBB, 0x85, 0x00, 0x20, 0x4F, 0x37, 0x5E, 0x01, 0x10, + 0xE5, 0xF2, 0x42, 0x27, 0x01, 0x10, 0x41, 0xF0, 0xCC, 0x16, 0xC2, 0xA4, 0x81, 0xA5, 0x02, 0x2D, + 0x46, 0x7E, 0x8A, 0x09, 0x09, 0x10, 0x8E, 0x92, 0x61, 0x12, 0x94, 0x90, 0x8C, 0x8C, 0x09, 0x8C, + 0x8C, 0x8C, 0x8B, 0x83, 0x71, 0x34, 0x22, 0x00, 0x41, 0xF0, 0x1B, 0x3D, 0xF0, 0x3D, 0x41, 0x00, + 0x1D, 0x23, 0x2F, 0x15, 0x3B, 0x43, 0x09, 0x10, 0x4C, 0x63, 0x7C, 0x41, 0x00, 0x6F, 0x44, 0x52, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x45, 0x3F, 0x00, 0x33, 0x27, 0x1D, 0x62, 0x41, 0xF0, 0x9A, 0xD2, + 0x1D, 0x20, 0x23, 0x1C, 0x25, 0x09, 0x10, 0x2D, 0x49, 0x74, 0x41, 0x00, 0x57, 0x34, 0x22, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x26, 0x24, 0x21, 0x00, 0x1E, 0x1C, 0x41, 0xF0, 0x1B, 0x68, 0xF0, 0x6D, + 0x56, 0x32, 0x0B, 0x30, 0xD4, 0x23, 0x0D, 0x21, 0x50, 0x2B, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x12, + 0x1C, 0x41, 0xC0, 0x41, 0xF0, 0x00, 0x00, 0x9B, 0x9B, 0x9B, 0xA4, 0x0E, 0xBB, 0xCF, 0x31, 0x41, + 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x00, 0x00, 0x77, 0x77, 0x3E, 0x77, 0x6D, 0x3D, 0x11, 0x50, 0x41, + 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x17, 0xF0, 0xF8, 0x22, 0x40, 0x70, 0x41, 0x00, 0x4F, 0x2A, 0x16, + 0xF0, 0x41, 0xF0, 0xC8, 0x4F, 0xF3, 0x0B, 0x30, 0x24, 0x41, 0x71, 0x41, 0x00, 0x51, 0x2B, 0x23, + 0x00, 0x00, 0x1D, 0x1D, 0x81, 0x93, 0x41, 0xF0, 0xDF, 0x21, 0x62, 0x03, 0x10, 0xB9, 0x62, 0x2D, + 0x1E, 0x22, 0x1F, 0x24, 0x29, 0x2E, 0x09, 0x10, 0x84, 0x35, 0x50, 0x78, 0x41, 0x00, 0x5D, 0x3C, + 0x00, 0x00, 0x2F, 0x48, 0x2F, 0x2F, 0x2B, 0x26, 0x20, 0xD9, 0xE1, 0x40, 0xA0, 0xBB, 0x60, 0xB3, + 0x7D, 0x20, 0xB3, 0x77, 0x85, 0x22, 0x35, 0x6A, 0x72, 0x12, 0x09, 0x10, 0x78, 0x88, 0x94, 0x38, + 0x00, 0x8E, 0x7D, 0x75, 0x11, 0x75, 0x75, 0x75, 0x75, 0x74, 0x6D, 0x62, 0x2B, 0x00, 0x1F, 0x0C, + 0x60, 0x41, 0xF0, 0x77, 0xAC, 0x57, 0x42, 0x50, 0x77, 0x46, 0xC9, 0x00, 0x30, 0x4F, 0x01, 0x10, + 0x3D, 0xF0, 0x39, 0xE8, 0x71, 0x41, 0xF0, 0xD9, 0xB3, 0x6D, 0x24, 0x50, 0x57, 0xAC, 0x21, 0x00, + 0x39, 0x63, 0x24, 0x01, 0x10, 0x3D, 0xF0, 0x45, 0x0C, 0x10, 0x41, 0xF0, 0x41, 0xF0, 0x21, 0x00, + 0x3A, 0x7B, 0x65, 0x07, 0x70, 0x03, 0x30, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x47, 0x0E, 0x28, 0x41, + 0xE0, 0x08, 0x80, 0x34, 0x70, 0xBB, 0x1B, 0x1B, 0x1F, 0x0E, 0x33, 0x55, 0xE0, 0x05, 0x50, 0x03, + 0x30, 0x00, 0x00, 0xE1, 0xE1, 0x38, 0xE1, 0xDD, 0x3D, 0x25, 0x0C, 0x60, 0x41, 0xF0, 0xA4, 0x8A, + 0x30, 0x24, 0x50, 0x81, 0xA4, 0x31, 0x01, 0x28, 0x3C, 0x52, 0x60, 0x09, 0x02, 0x20, 0x03, 0x30, + 0x00, 0x00, 0x65, 0x65, 0x65, 0x63, 0x58, 0x07, 0x45, 0x2F, 0x20, 0x41, 0xC0, 0x42, 0xA0, 0xBB, + 0x81, 0x3D, 0x18, 0x22, 0x10, 0x2D, 0x81, 0xBB, 0x57, 0x31, 0x11, 0x28, 0x30, 0x21, 0x36, 0x02, + 0x20, 0x03, 0x30, 0x00, 0x00, 0x39, 0x39, 0x39, 0x37, 0x0E, 0x32, 0x2B, 0x22, 0x40, 0x70, 0x21, + 0x34, 0x47, 0xDB, 0x08, 0x3A, 0x28, 0x43, 0xB0, 0x9B, 0xBB, 0xB3, 0xAC, 0xAC, 0x04, 0xB3, 0xBB, + 0xA4, 0x3F, 0x20, 0x1C, 0x1E, 0x1F, 0x04, 0x40, 0x88, 0x03, 0x30, 0x00, 0x00, 0x20, 0x20, 0x20, + 0x1F, 0x1F, 0xD9, 0x80, 0x83, 0x20, 0x32, 0x44, 0xDB, 0x38, 0x26, 0x12, 0xC0, 0x4A, 0x40, 0x62, + 0x6D, 0x6D, 0x62, 0x4A, 0x02, 0x20, 0x0F, 0xF0, 0x15, 0xF0, 0xE0, 0x20, 0x2E, 0x3B, 0xDB, 0x32, + 0x24, 0x05, 0x50, 0x0F, 0xF0, 0xC0, 0x0F, 0xF0, 0x15, 0xF0, 0x1E, 0x26, 0x2E, 0x31, 0x29, 0x20, + 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x26, 0xF0, 0x42, 0xF0, 0x20, 0x23, 0x24, 0x20, 0x0F, 0x1D, 0x06, + 0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x13, 0xF0, 0x1C, 0x1D, 0x1D, 0x1E, 0x1C, 0x00, 0x00, 0x09, 0x90, + 0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1E, 0x94, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x6C, 0x23, 0x00, 0x00 +}; + +// 21 x 50 @8bpp RGB. +#define X_BATTERY_EMPTY 21 +#define Y_BATTERY_EMPTY_BATT 38 +#define Y_BATTERY_EMPTY_CHRG 12 +#define SZ_BATTERY_EMPTY 3150 +#define SZ_BATTERY_EMPTY_BLZ 740 +static u8 BATTERY_EMPTY_BLZ[SZ_BATTERY_EMPTY_BLZ] = +{ + 0x17, 0xC0, 0x5D, 0x51, 0x79, 0x12, 0x79, 0x48, 0x69, 0x00, 0x0D, 0x46, 0xE3, 0x0F, 0xF0, 0x20, + 0xF0, 0x35, 0x2E, 0x38, 0x3F, 0x40, 0xEF, 0xCF, 0x00, 0x89, 0x77, 0x00, 0x17, 0x01, 0x14, 0x09, + 0x90, 0x36, 0xF0, 0xA4, 0xF1, 0x62, 0x01, 0x38, 0xA1, 0x99, 0x84, 0x3E, 0x00, 0x23, 0x1F, 0x04, + 0x40, 0x3B, 0xF0, 0x5B, 0x4F, 0x00, 0x18, 0x25, 0x20, 0x24, 0x90, 0x57, 0x00, 0x3C, 0xC0, 0x7B, + 0x00, 0x63, 0x10, 0x31, 0x7C, 0x2B, 0x03, 0x30, 0x3C, 0xF0, 0xA2, 0x00, 0xCE, 0x11, 0x0F, 0x0D, + 0x21, 0x00, 0x9E, 0xDE, 0x00, 0x06, 0x40, 0x60, 0xF0, 0xB9, 0xA0, 0xEA, 0x70, 0x3C, 0xF0, 0xF5, + 0x67, 0xD4, 0x3E, 0x01, 0x54, 0x00, 0x00, 0x00, 0x57, 0x70, 0xCD, 0xB1, 0x00, 0x1E, 0xFB, 0xD9, + 0x15, 0xA0, 0xC9, 0xAE, 0x69, 0x30, 0x3C, 0xD0, 0x30, 0xF0, 0xE4, 0xC1, 0xA7, 0x18, 0x10, 0x0D, + 0x0C, 0x00, 0x49, 0x3F, 0x04, 0x00, 0x87, 0x75, 0x00, 0xC5, 0xAA, 0x2A, 0x00, 0x09, 0x40, 0xC0, + 0xD7, 0xBA, 0x24, 0x00, 0x0C, 0xA0, 0x33, 0xF0, 0xF7, 0xD6, 0x0C, 0x00, 0x9C, 0x3C, 0xA0, 0x07, + 0x06, 0x2A, 0x10, 0x7D, 0x6C, 0x00, 0xBB, 0x09, 0xA2, 0x00, 0xF3, 0xD2, 0x00, 0xE3, 0xC4, 0x0C, + 0xA0, 0x80, 0x3C, 0xF0, 0x41, 0x38, 0x05, 0x50, 0x3E, 0xF1, 0x03, 0x00, 0x01, 0x19, 0x01, 0x00, + 0x33, 0x2C, 0x00, 0x71, 0x62, 0x00, 0x00, 0xAF, 0x97, 0x00, 0xEB, 0xCB, 0x03, 0x30, 0x03, 0x30, + 0x3C, 0x40, 0xE0, 0x81, 0x70, 0x04, 0x40, 0x0F, 0xF0, 0x23, 0xF0, 0x2D, 0x27, 0x00, 0x1C, 0x6B, + 0x5D, 0x00, 0xA9, 0x92, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC, 0x00, 0xBF, 0xA5, + 0x0E, 0xE0, 0x81, 0x0F, 0xF0, 0x19, 0xF0, 0xA5, 0x00, 0x22, 0x00, 0x65, 0x58, 0x00, 0x07, 0x67, + 0x59, 0x07, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x06, 0x09, 0x45, 0x10, 0x3C, 0x0A, 0x00, 0x00, 0x03, + 0x30, 0x00, 0x00, 0x49, 0x11, 0x0B, 0x47, 0x0E, 0x10, 0x0B, 0x1B, 0x06, 0x04, 0x3F, 0xF0, 0xD2, + 0xF0, 0xCD, 0x38, 0xE0, 0x85, 0xF8, 0xF7, 0x3A, 0x26, 0x75, 0x00, 0xD2, 0xF0, 0x33, 0x00, 0x27, + 0x71, 0x09, 0x06, 0x24, 0x30, 0xBD, 0x2C, 0x1D, 0x15, 0x00, 0xDB, 0x44, 0x33, 0x22, 0x00, 0x00, + 0x03, 0x30, 0x00, 0x00, 0x57, 0x00, 0x5D, 0x00, 0x18, 0x00, 0xFC, 0xC7, 0x2E, 0x1F, 0x00, 0x00, + 0x45, 0x00, 0x29, 0x09, 0x06, 0x18, 0x89, 0x30, 0x2F, 0x0B, 0x07, 0xDF, 0x34, 0x23, 0x21, 0xC0, + 0x81, 0x59, 0x15, 0x0E, 0x3C, 0xC0, 0x2A, 0x00, 0xF5, 0xC7, 0xE1, 0x34, 0x38, 0x23, 0x31, 0x0B, + 0x07, 0xC9, 0x2F, 0x1F, 0x33, 0x00, 0x80, 0x2D, 0x00, 0x1E, 0x90, 0x4D, 0x12, 0x0C, 0x2D, 0xC0, + 0x41, 0x0F, 0x23, 0x0A, 0x03, 0x30, 0x00, 0x00, 0xD9, 0x33, 0x22, 0xE7, 0x36, 0x06, 0x24, 0x06, + 0x00, 0xCB, 0x2F, 0x1F, 0x39, 0x30, 0x15, 0x05, 0x22, 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x21, 0xF0, + 0x0F, 0x03, 0x02, 0x03, 0x00, 0x8E, 0xF9, 0x3A, 0x3C, 0xA0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x30, 0xF0, 0xFC, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, + 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, + 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, + 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, + 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, + 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, + 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, + 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x84, 0x90, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0xF0, + 0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x07, 0x01, 0xB1, 0x40, + 0x81, 0x20, 0x33, 0x0C, 0x08, 0x00, 0x00, 0x0F, 0xF0, 0xC6, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, + 0x0D, 0x03, 0x02, 0x2D, 0x0A, 0x07, 0x07, 0x75, 0x30, 0x39, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, + 0xF0, 0x1B, 0xF0, 0x03, 0x00, 0xFE, 0x39, 0x00, 0xB1, 0x29, 0x1B, 0xF3, 0x39, 0x26, 0x00, 0x00, + 0x81, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFE, 0x3B, 0x27, 0xF5, 0x0F, 0x39, 0x26, + 0xB3, 0x2A, 0x1C, 0x17, 0x05, 0x03, 0x00, 0xFF, 0xE4, 0x02, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x6A, 0x09, 0x00, 0x00 +}; + +#endif diff --git a/ariane/src/hwinit/btn.c b/ariane/src/hwinit/btn.c deleted file mode 100644 index 109fae9..0000000 --- a/ariane/src/hwinit/btn.c +++ /dev/null @@ -1,75 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "btn.h" -#include "gpio.h" -#include "pinmux.h" -#include "max7762x.h" -#include "max77620.h" -#include "timer.h" - -u32 btn_read() -{ - u32 res = 0; - if (!gpio_read(GPIO_BY_NAME(BUTTON_VOL_DOWN))) - res |= BTN_VOL_DOWN; - if (!gpio_read(GPIO_BY_NAME(BUTTON_VOL_UP))) - res |= BTN_VOL_UP; - if (max77620_recv_byte(MAX77620_REG_ONOFFSTAT) & 0x4) - res |= BTN_POWER; - return res; -} - -u32 btn_wait() -{ - u32 res = 0, btn = btn_read(); - int pwr = 0; - - //Power button down, raise a filter. - if (btn & BTN_POWER) - { - pwr = 1; - btn &= ~BTN_POWER; - } - - do - { - res = btn_read(); - //Power button up, remove filter. - if (!(res & BTN_POWER) && pwr) - pwr = 0; - else if (pwr) //Power button still down. - res &= ~BTN_POWER; - } while (btn == res); - - return res; -} - -u32 btn_wait_timeout(u32 time_ms) -{ - u32 timeout = get_tmr_ms() + time_ms; - u32 res = btn_read(); - u32 btn = res; - - do - { - //Keep the new value until timeout is reached - if (btn == res) - res = btn_read(); - } while (get_tmr_ms() < timeout); - - return res; -} \ No newline at end of file diff --git a/ariane/src/hwinit/btn.h b/ariane/src/hwinit/btn.h deleted file mode 100644 index 09ff329..0000000 --- a/ariane/src/hwinit/btn.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _BTN_H_ -#define _BTN_H_ - -#include "types.h" - -#define BTN_POWER 0x1 -#define BTN_VOL_DOWN 0x2 -#define BTN_VOL_UP 0x4 - -u32 btn_read(); -u32 btn_wait(); -u32 btn_wait_timeout(u32 time_ms); - -#endif diff --git a/ariane/src/hwinit/carveout.c b/ariane/src/hwinit/carveout.c deleted file mode 100644 index 97daaa1..0000000 --- a/ariane/src/hwinit/carveout.c +++ /dev/null @@ -1,381 +0,0 @@ -#include "carveout.h" -#include "t210.h" -#include "mc_t210.h" -#include "util.h" -#include "lib/printk.h" - -static uintptr_t tz_base_mib = 0; -static const size_t tz_size_mib = TRUSTZONE_CARVEOUT_SIZE_MB; - -/* returns total amount of DRAM (in MB) from memory controller registers */ -int sdram_size_mb(void) -{ - struct tegra_mc_regs *mc = (struct tegra_mc_regs *)MC_BASE; - static int total_size = 0; - - if (total_size) - return total_size; - - /* - * This obtains memory size from the External Memory Aperture - * Configuration register. Nvidia confirmed that it is safe to assume - * this value represents the total physical DRAM size. - */ - total_size = (mc->emem_cfg >> MC_EMEM_CFG_SIZE_MB_SHIFT) & MC_EMEM_CFG_SIZE_MB_MASK; - return total_size; -} - -static void carveout_from_regs(uintptr_t *base_mib, size_t *size_mib, - uint32_t bom, uint32_t bom_hi, uint32_t size) -{ - - /* All size regs of carveouts are in MiB. */ - if (size == 0) - return; - - *size_mib = size; - bom >>= 20; - bom |= bom_hi << (32 - 20); - - *base_mib = bom; -} - -void carveout_range(int id, uintptr_t *base_mib, size_t *size_mib) -{ - *base_mib = 0; - *size_mib = 0; - struct tegra_mc_regs * const mc = (struct tegra_mc_regs *)MC_BASE; - size_t region_size_mb; - - switch (id) { - case CARVEOUT_TZ: - *base_mib = tz_base_mib; - *size_mib = tz_size_mib; - break; - case CARVEOUT_SEC: - carveout_from_regs(base_mib, size_mib, - mc->sec_carveout_bom, - mc->sec_carveout_adr_hi, - mc->sec_carveout_size_mb); - break; - case CARVEOUT_MTS: - carveout_from_regs(base_mib, size_mib, - mc->mts_carveout_bom, - mc->mts_carveout_adr_hi, - mc->mts_carveout_size_mb); - break; - case CARVEOUT_VPR: - /* - * A 128MB VPR carveout is felt to be sufficient as per syseng. - * Set it up in vpr_region_init, below. - */ - carveout_from_regs(base_mib, size_mib, - mc->video_protect_bom, - mc->video_protect_bom_adr_hi, - mc->video_protect_size_mb); - break; - case CARVEOUT_GPU: - /* These carveout regs use 128KB granularity - convert to MB */ - region_size_mb = DIV_ROUND_UP(mc->security_carveout2_size_128kb, 8); - - /* BOM address set in gpu_region_init, below */ - carveout_from_regs(base_mib, size_mib, - mc->security_carveout2_bom, - mc->security_carveout2_bom_hi, - region_size_mb); - break; - case CARVEOUT_NVDEC: - /* These carveout regs use 128KB granularity - convert to MB */ - region_size_mb = DIV_ROUND_UP(mc->security_carveout1_size_128kb, 8); - - /* BOM address set in nvdec_region_init, below */ - carveout_from_regs(base_mib, size_mib, - mc->security_carveout1_bom, - mc->security_carveout1_bom_hi, - region_size_mb); - break; - case CARVEOUT_TSEC: - /* These carveout regs use 128KB granularity - convert to MB */ - region_size_mb = DIV_ROUND_UP(mc->security_carveout4_size_128kb, 8); - - /* BOM address set in tsec_region_init, below. - * Since the TSEC region consumes 2 carveouts, and is - * expected to be split evenly between the two, size_mib - * is doubled here. - */ - region_size_mb *= 2; - carveout_from_regs(base_mib, size_mib, - mc->security_carveout4_bom, - mc->security_carveout4_bom_hi, - region_size_mb); - break; - default: - break; - } -} - -void print_carveouts(void) -{ - #ifdef CARVEOUT_DEBUGGING - int i; - dbg_print("Carveout ranges:\n"); - for (i = 0; i < CARVEOUT_NUM; i++) { - uintptr_t base, end; - size_t size; - carveout_range(i, &base, &size); - end = base + size; - if (end && base) - dbg_print("ID:%d [%lx - %lx)\n", i, - (unsigned long)base * 1024*1024, - (unsigned long)end * 1024*1024); - } - #endif -} - -/* - * Memory Map is as follows - * - * ------------------------------ <-- Start of DRAM - * | | - * | Available DRAM | - * |____________________________| - * | | - * | CBMEM | - * |____________________________| - * | | - * | Other carveouts | - * | (with dynamic allocation) | - * |____________________________| - * | | - * | TZ carveout of size | - * | TRUSTZONE_CARVEOUT_SIZE_MB | - * |____________________________| <-- 0x100000000 - * | | - * | Available DRAM | - * | | - * ------------------------------ <-- End of DRAM - * - */ -static void memory_in_range(uintptr_t *base_mib, uintptr_t *end_mib, - int ignore_carveout_id) -{ - uintptr_t base; - uintptr_t end; - int i; - - base = (uintptr_t)TEGRA_DRAM_START / (1024*1024); - end = base + sdram_size_mb(); - -#ifdef CARVEOUT_DEBUGGING - dbg_print("BASE: 0x%08x END: 0x%08x\n", base, end); -#endif - - /* Requested limits out of range. */ - if (*end_mib <= base || *base_mib >= end) { - *end_mib = *base_mib = 0; - return; - } - - /* Clip region to passed in limits. */ - if (*end_mib < end) - end = *end_mib; - if (*base_mib > base) - base = *base_mib; - - for (i = 0; i < CARVEOUT_NUM; i++) { - uintptr_t carveout_base; - uintptr_t carveout_end; - size_t carveout_size; - - if (i == ignore_carveout_id) - continue; - - carveout_range(i, &carveout_base, &carveout_size); - if (carveout_size == 0) - continue; - - carveout_end = carveout_base + carveout_size; - - /* Bypass carveouts out of requested range. */ - if (carveout_base >= end || carveout_end <= base) - continue; - - /* - * This is crude, but the assumption is that carveouts live - * at the upper range of physical memory. Therefore, update - * the end address to be equal to the base of the carveout. - */ - end = carveout_base; - } - - *base_mib = base; - *end_mib = end; -} - -void memory_in_range_below_4gb(uintptr_t *base_mib, uintptr_t *end_mib) -{ - *base_mib = 0; - *end_mib = 4096; - memory_in_range(base_mib, end_mib, CARVEOUT_NUM); -} - -void memory_in_range_above_4gb(uintptr_t *base_mib, uintptr_t *end_mib) -{ - *base_mib = 4096; - *end_mib = ~0UL; - memory_in_range(base_mib, end_mib, CARVEOUT_NUM); -} - -void trustzone_region_init(void) -{ - struct tegra_mc_regs * const mc = (void *)(uintptr_t)MC_BASE; - uintptr_t end = 4096; - - /* Already has been initialized. */ - if (tz_size_mib != 0 && tz_base_mib != 0) - return; - - /* - * Get memory layout below 4GiB ignoring the TZ carveout because - * that's the one to initialize. - */ - tz_base_mib = end - tz_size_mib; - memory_in_range(&tz_base_mib, &end, CARVEOUT_TZ); - - /* - * IMPORTANT!!!!! - * We need to ensure that trustzone region is located at the end of - * 32-bit address space. If any carveout is allocated space before - * trustzone_region_init is called, then this assert will ensure that - * the boot flow fails. If you are here because of this assert, please - * move your call to initialize carveout after trustzone_region_init in - * romstage and ramstage. - */ - if (end != 4096) - { - dbg_print("MC_CARVEOUT ERROR: end is %u instead of 4096!\n", end); - while (1) {} - } - - /* AVP cannot set the TZ registers proper as it is always non-secure. */ - if (running_on_bpmp()) - { -#ifdef CARVEOUT_DEBUGGING - dbg_print("IN AVP CONTEXT, SKIPPIN, 0x%08x 0x%08x\n", (uint32_t)(tz_base_mib << 20), (uint32_t)(tz_size_mib)); -#endif - return; - } -#ifdef CARVEOUT_DEBUGGING - else - dbg_print("NOT IN AVP CONTEXT, TZ: 0x%08x 0x%08x\n", (uint32_t)(tz_base_mib) << 20, (uint32_t)(tz_size_mib)); -#endif - - /* Set the carveout region. */ - mc->security_cfg0 = tz_base_mib << 20; - mc->security_cfg1 = tz_size_mib; - - /* Enable SMMU translations */ - mc->smmu_config = MC_SMMU_CONFIG_ENABLE; -} - -void gpu_region_init(void) -{ - struct tegra_mc_regs * const mc = (void *)(uintptr_t)MC_BASE; - uintptr_t gpu_base_mib = 0, end = 4096; - size_t gpu_size_mib = GPU_CARVEOUT_SIZE_MB; - - /* Get memory layout below 4GiB */ - memory_in_range(&gpu_base_mib, &end, CARVEOUT_GPU); - gpu_base_mib = end - gpu_size_mib; - - /* Set the carveout2 base address. Everything else has been set in the BCT cfg/inc */ - mc->security_carveout2_bom = gpu_base_mib << 20; - mc->security_carveout2_bom_hi = 0; - - /* Set the locked bit. This will lock out any other writes! */ - mc->security_carveout2_cfg0 |= MC_SECURITY_CARVEOUT_LOCKED; - - /* Set the carveout3 base to 0, unused */ - mc->security_carveout3_bom = 0; - mc->security_carveout3_bom_hi = 0; - -#ifdef CARVEOUT_DEBUGGING - dbg_print("GPU_REGION INIT: 0x%08x 0x%08x\n", (uint32_t)(gpu_base_mib << 20), (uint32_t)(gpu_size_mib)); -#endif - - /* Set the locked bit. This will lock out any other writes! */ - //mc->security_carveout3_cfg0 = MC_SECURITY_CARVEOUT_LOCKED; -} - -void nvdec_region_init(void) -{ - struct tegra_mc_regs * const mc = (void *)(uintptr_t)MC_BASE; - uintptr_t nvdec_base_mib = 0, end = 4096; - size_t nvdec_size_mib = NVDEC_CARVEOUT_SIZE_MB; - - /* Get memory layout below 4GiB */ - memory_in_range(&nvdec_base_mib, &end, CARVEOUT_NVDEC); - nvdec_base_mib = end - nvdec_size_mib; - - /* Set the carveout1 base address. Everything else has been set in the BCT cfg/inc */ - mc->security_carveout1_bom = nvdec_base_mib << 20; - mc->security_carveout1_bom_hi = 0; - -#ifdef CARVEOUT_DEBUGGING - dbg_print("NVDEC_REGION INIT: 0x%08x 0x%08x\n", (uint32_t)(nvdec_base_mib << 20), (uint32_t)(nvdec_size_mib)); -#endif - - /* Set the locked bit. This will lock out any other writes! */ - //mc->security_carveout1_cfg0 |= MC_SECURITY_CARVEOUT_LOCKED; -} - -void tsec_region_init(void) -{ - struct tegra_mc_regs * const mc = (void *)(uintptr_t)MC_BASE; - uintptr_t tsec_base_mib = 0, end = 4096; - size_t tsec_size_mib = TSEC_CARVEOUT_SIZE_MB; - - /* Get memory layout below 4GiB */ - memory_in_range(&tsec_base_mib, &end, CARVEOUT_TSEC); - tsec_base_mib = end - tsec_size_mib; - - /* - * Set the carveout4/5 base address. Everything else has been set in the BCT cfg/inc - * Note that the TSEC range is split evenly between the 2 carveouts (i.e. 1MB each) - */ - mc->security_carveout4_bom = tsec_base_mib << 20; - mc->security_carveout4_bom_hi = 0; - mc->security_carveout5_bom = (tsec_base_mib + (TSEC_CARVEOUT_SIZE_MB / 2)) << 20; - mc->security_carveout5_bom_hi = 0; - -#ifdef CARVEOUT_DEBUGGING - dbg_print("TSEC_REGION INIT: 0x%08x 0x%08x\n", (uint32_t)(tsec_base_mib << 20), (uint32_t)(tsec_size_mib)); -#endif - - /* Set the locked bit. This will lock out any other writes! */ - mc->security_carveout4_cfg0 |= MC_SECURITY_CARVEOUT_LOCKED; - mc->security_carveout5_cfg0 |= MC_SECURITY_CARVEOUT_LOCKED; -} - -void vpr_region_init(void) -{ - struct tegra_mc_regs * const mc = (void *)(uintptr_t)MC_BASE; - uintptr_t vpr_base_mib = 0, end = 4096; - size_t vpr_size_mib = VPR_CARVEOUT_SIZE_MB; - - /* Get memory layout below 4GiB */ - memory_in_range(&vpr_base_mib, &end, CARVEOUT_VPR); - vpr_base_mib = end - vpr_size_mib; - - /* Set the carveout base address and size */ - mc->video_protect_bom = vpr_base_mib << 20; - mc->video_protect_bom_adr_hi = 0; - mc->video_protect_size_mb = vpr_size_mib; - -#ifdef CARVEOUT_DEBUGGING - dbg_print("VPR_REGION INIT: 0x%08x 0x%08x\n", (uint32_t)(vpr_base_mib << 20), (uint32_t)(vpr_size_mib)); -#endif - - /* Set the locked bit. This will lock out any other writes! */ - //mc->video_protect_reg_ctrl = MC_VPR_WR_ACCESS_DISABLE; -} \ No newline at end of file diff --git a/ariane/src/hwinit/carveout.h b/ariane/src/hwinit/carveout.h deleted file mode 100644 index 68b2e57..0000000 --- a/ariane/src/hwinit/carveout.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _CARVEOUT_H_ -#define _CARVEOUT_H_ - -#include -#include - -#define GPU_CARVEOUT_SIZE_MB 1 -#define NVDEC_CARVEOUT_SIZE_MB 1 -#define TSEC_CARVEOUT_SIZE_MB 2 -#define VPR_CARVEOUT_SIZE_MB 128 -#define TRUSTZONE_CARVEOUT_SIZE_MB 0x14 - -#define TEGRA_DRAM_START 0x80000000 - -/* Return total size of DRAM memory configured on the platform. */ -int sdram_size_mb(void); - -/* Find memory below and above 4GiB boundary repsectively. All units 1MiB. */ -void memory_in_range_below_4gb(uintptr_t *base_mib, uintptr_t *end_mib); -void memory_in_range_above_4gb(uintptr_t *base_mib, uintptr_t *end_mib); - -enum { - CARVEOUT_TZ, - CARVEOUT_SEC, - CARVEOUT_MTS, - CARVEOUT_VPR, - CARVEOUT_GPU, - CARVEOUT_NVDEC, - CARVEOUT_TSEC, - CARVEOUT_NUM, -}; - -/* Provided the careout id, obtain the base and size in 1MiB units. */ -void carveout_range(int id, uintptr_t *base_mib, size_t *size_mib); -void print_carveouts(void); - -/* - * There are complications accessing the Trust Zone carveout region. The - * AVP cannot access these registers and the CPU can't access this register - * as a non-secure access. When the page tables live in non-secure memory - * these registers cannot be accessed either. Thus, this function handles - * both the AVP case and non-secured access case by keeping global state. - */ -void trustzone_region_init(void); -void gpu_region_init(void); -void nvdec_region_init(void); -void tsec_region_init(void); -void vpr_region_init(void); - -#endif \ No newline at end of file diff --git a/ariane/src/hwinit/clock.c b/ariane/src/hwinit/clock.c deleted file mode 100644 index e95e0b3..0000000 --- a/ariane/src/hwinit/clock.c +++ /dev/null @@ -1,435 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "clock.h" -#include "t210.h" -#include "timer.h" -#include "sdmmc.h" -#include "flow.h" - -static const clock_t _clock_uart[] = { - /* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6 , 0, 0 }, - /* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7 , 0, 0 }, - /* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 0 }, - /* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1 , 0, 0 }, - /* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, 0, 2, 0, 0 } -}; - -static const clock_t _clock_i2c[] = { - /* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 6, 0 }, - /* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 6, 0 }, - /* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 6, 0 }, - /* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 6, 0 }, - /* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 6, 0 }, - /* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6 , 6, 0 }, -}; - -static clock_t _clock_se = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 }; - -static clock_t _clock_host1x = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 }; -static clock_t _clock_tsec = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 }; -static clock_t _clock_sor_safe = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, 0, 30, 0, 0 }; -static clock_t _clock_sor0 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, 0, 22, 0, 0 }; //no CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 on this one ? -static clock_t _clock_sor1 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 }; -static clock_t _clock_kfuse = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, 0, 8, 0, 0 }; - -static clock_t _clock_cl_dvfs = { CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, 0, 27, 0, 0 }; -static clock_t _clock_coresight = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4}; - -void clock_enable(const clock_t *clk) -{ - //Put clock into reset. - CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); - //Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); - //Configure clock source if required. - if (clk->source) - CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); - //Enable. - CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); - //Take clock off reset. - CLOCK(clk->reset) &= ~(1 << clk->index); -} - -void clock_disable(const clock_t *clk) -{ - //Put clock into reset. - CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); - //Disable. - CLOCK(clk->enable) &= ~(1 << clk->index); -} - -void clock_enable_fuse(u32 enable) -{ - static const u32 FUSE_ENABLE_BIT = 1u << 28; - - if (enable) - CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) |= FUSE_ENABLE_BIT; - else - CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) &= ~FUSE_ENABLE_BIT; -} - -void clock_enable_uart(u32 idx) -{ - clock_enable(&_clock_uart[idx]); -} - -void clock_enable_i2c(u32 idx) -{ - clock_enable(&_clock_i2c[idx]); -} - -void clock_enable_se() -{ - clock_enable(&_clock_se); -} - -void clock_enable_host1x() -{ - clock_enable(&_clock_host1x); -} - -void clock_disable_host1x() -{ - clock_disable(&_clock_host1x); -} - -void clock_enable_tsec() -{ - clock_enable(&_clock_tsec); -} - -void clock_disable_tsec() -{ - clock_disable(&_clock_tsec); -} - -void clock_enable_sor_safe() -{ - clock_enable(&_clock_sor_safe); -} - -void clock_disable_sor_safe() -{ - clock_disable(&_clock_sor_safe); -} - -void clock_enable_sor0() -{ - clock_enable(&_clock_sor0); -} - -void clock_disable_sor0() -{ - clock_disable(&_clock_sor0); -} - -void clock_enable_sor1() -{ - clock_enable(&_clock_sor1); -} - -void clock_disable_sor1() -{ - clock_disable(&_clock_sor1); -} - -void clock_enable_kfuse() -{ - //clock_enable(&_clock_kfuse); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) |= CLK_H_KFUSE; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= ~CLK_H_KFUSE; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) |= CLK_H_KFUSE; - usleep(10); - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= ~CLK_H_KFUSE; - usleep(20); -} - -void clock_disable_kfuse() -{ - clock_disable(&_clock_kfuse); -} - -void clock_enable_cl_dvfs() -{ - clock_enable(&_clock_cl_dvfs); -} - -void clock_enable_coresight() -{ - clock_enable(&_clock_coresight); -} - -static int _clock_sdmmc_is_reset(u32 id) -{ - switch (id) - { - case SDMMC_1: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & CLK_L_SDMMC1; - case SDMMC_2: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & CLK_L_SDMMC2; - case SDMMC_3: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & CLK_U_SDMMC3; - case SDMMC_4: - return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & CLK_L_SDMMC4; - } - return 0; -} - -static void _clock_sdmmc_set_reset(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = CLK_L_SDMMC1; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = CLK_L_SDMMC2; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = CLK_U_SDMMC3; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = CLK_L_SDMMC4; - } -} - -static void _clock_sdmmc_clear_reset(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = CLK_L_SDMMC1; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = CLK_L_SDMMC2; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = CLK_U_SDMMC3; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = CLK_L_SDMMC4; - } -} - -static int _clock_sdmmc_is_enabled(u32 id) -{ - switch (id) - { - case SDMMC_1: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & CLK_L_SDMMC1; - case SDMMC_2: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & CLK_L_SDMMC2; - case SDMMC_3: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & CLK_U_SDMMC3; - case SDMMC_4: - return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & CLK_L_SDMMC4; - } - return 0; -} - -static void _clock_sdmmc_set_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = CLK_L_SDMMC1; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = CLK_L_SDMMC2; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = CLK_U_SDMMC3; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = CLK_L_SDMMC4; - } -} - -static void _clock_sdmmc_clear_enable(u32 id) -{ - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = CLK_L_SDMMC1; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = CLK_L_SDMMC2; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = CLK_U_SDMMC3; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = CLK_L_SDMMC4; - } -} - -static u32 _clock_sdmmc_table[8] = { 0 }; - -static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) -{ - u32 divisor = 0; - u32 source = 0; - - switch (val) - { - case 25000: - *pout = 24728; - divisor = 31; - break; - case 26000: - *pout = 25500; - divisor = 30; - break; - case 40800: - *pout = 40800; - divisor = 18; - break; - case 50000: - *pout = 48000; - divisor = 15; - break; - case 52000: - *pout = 51000; - divisor = 14; - break; - case 100000: - *pout = 90667; - divisor = 7; - break; - case 200000: - *pout = 163200; - divisor = 3; - break; - case 208000: - *pout = 204000; - divisor = 2; - break; - default: - return 0; - } - - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; - - switch (id) - { - case SDMMC_1: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor; - break; - case SDMMC_2: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor; - break; - case SDMMC_3: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor; - break; - case SDMMC_4: - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor; - break; - } - - return 1; -} - -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) -{ - if (_clock_sdmmc_table[2 * id] == val) - { - *pout = _clock_sdmmc_table[2 * id + 1]; - } - else - { - int is_enabled = _clock_sdmmc_is_enabled(id); - if (is_enabled) - _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_source_inner(pout, id, val); - if (is_enabled) - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - } -} - -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type) -{ - switch (type) - { - case 0: - *pout = 26000; - *pdivisor = 66; - break; - case 1: - *pout = 26000; - *pdivisor = 1; - break; - case 2: - *pout = 52000; - *pdivisor = 1; - break; - case 3: - case 4: - case 11: - *pout = 200000; - *pdivisor = 1; - break; - case 5: - *pout = 25000; - *pdivisor = 64; - case 6: - case 8: - *pout = 25000; - *pdivisor = 1; - break; - case 7: - *pout = 50000; - *pdivisor = 1; - case 10: - *pout = 100000; - *pdivisor = 1; - case 13: - *pout = 40800; - *pdivisor = 1; - break; - case 14: - *pout = 200000; - *pdivisor = 2; - break; - } -} - -int clock_sdmmc_is_not_reset_and_enabled(u32 id) -{ - return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id); -} - -void clock_sdmmc_enable(u32 id, u32 val) -{ - u32 div = 0; - - if (_clock_sdmmc_is_enabled(id)) - _clock_sdmmc_clear_enable(id); - _clock_sdmmc_set_reset(id); - _clock_sdmmc_config_clock_source_inner(&div, id, val); - _clock_sdmmc_set_enable(id); - _clock_sdmmc_is_reset(id); - usleep((100000 + div - 1) / div); - _clock_sdmmc_clear_reset(id); - _clock_sdmmc_is_reset(id); -} - -void clock_sdmmc_disable(u32 id) -{ - _clock_sdmmc_set_reset(id); - _clock_sdmmc_clear_enable(id); - _clock_sdmmc_is_reset(id); -} - -void clock_halt_bpmp(void) -{ - static struct flow_ctlr *flow = (void *)FLOW_CTLR_BASE; - - for (;;) - { - flow->halt_cop_events = FLOW_EVENT_JTAG | FLOW_EVENT_LIC_IRQ | FLOW_EVENT_GIC_IRQ | FLOW_MODE_WAITEVENT; - } -} diff --git a/ariane/src/hwinit/clock.h b/ariane/src/hwinit/clock.h deleted file mode 100644 index 2501da6..0000000 --- a/ariane/src/hwinit/clock.h +++ /dev/null @@ -1,490 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _CLOCK_H_ -#define _CLOCK_H_ - -#include "types.h" - -/*! Clock registers. */ -#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 -#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 -#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18 -#define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20 -#define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24 -#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28 -#define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C -#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 -#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 -#define CLK_RST_CONTROLLER_OSC_CTRL 0x50 -#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 -#define CLK_RST_CONTROLLER_PLLM_OUT 0x94 -#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 -#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9c -#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 -#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 -#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC -#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 -#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 -#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 -#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC -#define CLK_RST_CONTROLLER_PLLE_SS_CNTL1 0xF0 -#define CLK_RST_CONTROLLER_PLLE_SS_CNTL2 0xF4 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 -#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S3 0x104 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPDIF_OUT 0x108 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPDIF_IN 0x10C -#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPI2 0x118 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPI3 0x11C -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPI1 0x134 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP2 0x13C -#define CLK_RST_CONTROLLER_CLK_SOURCE_ISP 0x144 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C -#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI_SENSOR 0x1A8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SPI4 0x1B4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_OWR 0x1CC -#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DTV 0x1DC -#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 -#define CLK_RST_CONTROLLER_CLK_SPARE2 0x1FC -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 -#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 -#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 -#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C -#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 -#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 -#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C -#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 -#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 -#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 -#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC -#define CLK_RST_CONTROLLER_DFLL_BASE 0x2F4 -#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300 -#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304 -#define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308 -#define CLK_RST_CONTROLLER_RST_DEV_H_CLR 0x30C -#define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310 -#define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314 -#define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320 -#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324 -#define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328 -#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR 0x32C -#define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330 -#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334 -#define CLK_RST_CONTROLLER_CCPLEX_PG_SM_OVRD 0x33C -#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 -#define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358 -#define CLK_RST_CONTROLLER_RST_DEVICES_W 0x35C -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364 -#define CLK_RST_CONTROLLER_CCLKG_BURST_POLICY 0x368 -#define CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER 0x36C -#define CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY 0x370 -#define CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER 0x374 -#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL 0x380 -#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL1 0x384 -#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388 -#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_TSENSOR 0x3B8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S4 0x3BC -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S5 0x3C0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_AHUB 0x3D0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_HDA2CODEC_2X 0x3E4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON 0x3E8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC -#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 0x3F0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH3 0x3F4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C_SLOW 0x3FC -#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 -#define CLK_RST_CONTROLLER_CLK_SOURCE_ISPB 0x404 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 0x414 -#define CLK_RST_CONTROLLER_CLK_SOURCE_HDA 0x428 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C -#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 -#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438 -#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C -#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 -#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 -#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 -#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C -#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 -#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 -#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C -#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_HOST 0x600 -#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FALCON 0x604 -#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608 -#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C -#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610 -#define CLK_RST_CONTROLLER_CLK_SOURCE_CILAB 0x614 -#define CLK_RST_CONTROLLER_CLK_SOURCE_CILCD 0x618 -#define CLK_RST_CONTROLLER_CLK_SOURCE_CILEF 0x61C -#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIB_LP 0x624 -#define CLK_RST_CONTROLLER_CLK_SOURCE_ENTROPY 0x628 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF 0x62C -#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC 0x630 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_LATENCY 0x640 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SOC_THERM 0x644 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DMIC1 0x64C -#define CLK_RST_CONTROLLER_CLK_SOURCE_DMIC2 0x650 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI_SENSOR2 0x658 -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C -#define CLK_RST_CONTROLLER_CLK_SOURCE_MIPIBIF 0x660 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C -#define CLK_RST_CONTROLLER_CLK_SOURCE_VIC 0x678 -#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 -#define CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC 0x698 -#define CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG 0x69C -#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 -#define CLK_RST_CONTROLLER_PLLA1_BASE 0x6A4 -#define CLK_RST_CONTROLLER_PLLA1_MISC_0 0x6A8 -#define CLK_RST_CONTROLLER_PLLA1_MISC_1 0x6AC -#define CLK_RST_CONTROLLER_PLLA1_MISC_2 0x6B0 -#define CLK_RST_CONTROLLER_PLLA1_MISC_3 0x6B4 -#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC3 0x6B8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_DMIC3 0x6BC -#define CLK_RST_CONTROLLER_CLK_SOURCE_APE 0x6C0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_QSPI 0x6C4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_VI_I2C 0x6C8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC -#define CLK_RST_CONTROLLER_CLK_SOURCE_PEX_SATA_USB_RX_BYP 0x6D0 -#define CLK_RST_CONTROLLER_CLK_SOURCE_MAUD 0x6D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_TSECB 0x6D8 -#define CLK_RST_CONTROLLER_CLK_CPUG_MISC1 0x6DC - -enum { - CLK_L_CPU = 0x1 << 0, - CLK_L_COP = 0x1 << 1, - CLK_L_TRIG_SYS = 0x1 << 2, - CLK_L_RTC = 0x1 << 4, - CLK_L_TMR = 0x1 << 5, - CLK_L_UARTA = 0x1 << 6, - CLK_L_UARTB = 0x1 << 7, - CLK_L_GPIO = 0x1 << 8, - CLK_L_SDMMC2 = 0x1 << 9, - CLK_L_SPDIF = 0x1 << 10, - CLK_L_I2S2 = 0x1 << 11, - CLK_L_I2C1 = 0x1 << 12, - CLK_L_NDFLASH = 0x1 << 13, - CLK_L_SDMMC1 = 0x1 << 14, - CLK_L_SDMMC4 = 0x1 << 15, - CLK_L_PWM = 0x1 << 17, - CLK_L_I2S3 = 0x1 << 18, - CLK_L_EPP = 0x1 << 19, - CLK_L_VI = 0x1 << 20, - CLK_L_2D = 0x1 << 21, - CLK_L_USBD = 0x1 << 22, - CLK_L_ISP = 0x1 << 23, - CLK_L_3D = 0x1 << 24, - CLK_L_DISP2 = 0x1 << 26, - CLK_L_DISP1 = 0x1 << 27, - CLK_L_HOST1X = 0x1 << 28, - CLK_L_VCP = 0x1 << 29, - CLK_L_I2S1 = 0x1 << 30, - CLK_L_CACHE2 = 0x1 << 31, - - CLK_H_MEM = 0x1 << 0, - CLK_H_AHBDMA = 0x1 << 1, - CLK_H_APBDMA = 0x1 << 2, - CLK_H_KBC = 0x1 << 4, - CLK_H_STAT_MON = 0x1 << 5, - CLK_H_PMC = 0x1 << 6, - CLK_H_FUSE = 0x1 << 7, - CLK_H_KFUSE = 0x1 << 8, - CLK_H_SBC1 = 0x1 << 9, - CLK_H_SNOR = 0x1 << 10, - CLK_H_JTAG2TBC = 0x1 << 11, - CLK_H_SBC2 = 0x1 << 12, - CLK_H_SBC3 = 0x1 << 14, - CLK_H_I2C5 = 0x1 << 15, - CLK_H_DSI = 0x1 << 16, - CLK_H_HSI = 0x1 << 18, - CLK_H_HDMI = 0x1 << 19, - CLK_H_CSI = 0x1 << 20, - CLK_H_I2C2 = 0x1 << 22, - CLK_H_UARTC = 0x1 << 23, - CLK_H_MIPI_CAL = 0x1 << 24, - CLK_H_EMC = 0x1 << 25, - CLK_H_USB2 = 0x1 << 26, - CLK_H_USB3 = 0x1 << 27, - CLK_H_MPE = 0x1 << 28, - CLK_H_VDE = 0x1 << 29, - CLK_H_BSEA = 0x1 << 30, - CLK_H_BSEV = 0x1 << 31, - - CLK_U_UARTD = 0x1 << 1, - CLK_U_UARTE = 0x1 << 2, - CLK_U_I2C3 = 0x1 << 3, - CLK_U_SBC4 = 0x1 << 4, - CLK_U_SDMMC3 = 0x1 << 5, - CLK_U_PCIE = 0x1 << 6, - CLK_U_OWR = 0x1 << 7, - CLK_U_AFI = 0x1 << 8, - CLK_U_CSITE = 0x1 << 9, - CLK_U_PCIEXCLK = 0x1 << 10, - CLK_U_AVPUCQ = 0x1 << 11, - CLK_U_TRACECLKIN = 0x1 << 13, - CLK_U_SOC_THERM = 0x1 << 14, - CLK_U_DTV = 0x1 << 15, - CLK_U_NAND_SPEED = 0x1 << 16, - CLK_U_I2C_SLOW = 0x1 << 17, - CLK_U_DSIB = 0x1 << 18, - CLK_U_TSEC = 0x1 << 19, - CLK_U_IRAMA = 0x1 << 20, - CLK_U_IRAMB = 0x1 << 21, - CLK_U_IRAMC = 0x1 << 22, - - // Clock reset. - CLK_U_EMUCIF = 0x1 << 23, - // Clock enable. - CLK_U_IRAMD = 0x1 << 23, - - CLK_U_CRAM2 = 0x2 << 24, - CLK_U_XUSB_HOST = 0x1 << 25, - CLK_U_MSENC = 0x1 << 27, - CLK_U_SUS_OUT = 0x1 << 28, - CLK_U_DEV2_OUT = 0x1 << 29, - CLK_U_DEV1_OUT = 0x1 << 30, - CLK_U_XUSB_DEV = 0x1 << 31, - - CLK_V_CPUG = 0x1 << 0, - CLK_V_CPULP = 0x1 << 1, - CLK_V_3D2 = 0x1 << 2, - CLK_V_MSELECT = 0x1 << 3, - CLK_V_I2S4 = 0x1 << 5, - CLK_V_I2S5 = 0x1 << 6, - CLK_V_I2C4 = 0x1 << 7, - CLK_V_SBC5 = 0x1 << 8, - CLK_V_SBC6 = 0x1 << 9, - CLK_V_AHUB = 0x1 << 10, - CLK_V_APB2APE = 0x1 << 11, - CLK_V_HDA2CODEC_2X = 0x1 << 15, - CLK_V_ATOMICS = 0x1 << 16, - CLK_V_SPDIF_DOUBLER = 0x1 << 22, - CLK_V_ACTMON = 0x1 << 23, - CLK_V_EXTPERIPH1 = 0x1 << 24, - CLK_V_SATA = 0x1 << 28, - CLK_V_HDA = 0x1 << 29, - - CLK_W_HDA2HDMICODEC = 0x1 << 0, - CLK_W_SATACOLD = 0x1 << 1, - CLK_W_PCIERX0 = 0x1 << 2, - CLK_W_PCIERX1 = 0x1 << 3, - CLK_W_PCIERX2 = 0x1 << 4, - CLK_W_PCIERX3 = 0x1 << 5, - CLK_W_PCIERX4 = 0x1 << 6, - CLK_W_PCIERX5 = 0x1 << 7, - CLK_W_CEC = 0x1 << 8, - CLK_W_PCIE2_IOBIST = 0x1 << 9, - CLK_W_EMC_IOBIST = 0x1 << 10, - CLK_W_SATA_IOBIST = 0x1 << 12, - CLK_W_MIPI_IOBIST = 0x1 << 13, - CLK_W_XUSB_PADCTL = 0x1 << 14, - CLK_W_XUSB = 0x1 << 15, - CLK_W_CILAB = 0x1 << 16, - CLK_W_CILCD = 0x1 << 17, - CLK_W_CILEF = 0x1 << 18, - CLK_W_DSIA_LP = 0x1 << 19, - CLK_W_DSIB_LP = 0x1 << 20, - CLK_W_ENTROPY = 0x1 << 21, - CLK_W_DVFS = 0x1 << 27, - CLK_W_XUSB_SS = 0x1 << 28, - CLK_W_EMC_LATENCY = 0x1 << 29, - CLK_W_MC1 = 0x1 << 30, - - CLK_X_SPARE = 0x1 << 0, - CLK_X_DMIC1 = 0x1 << 1, - CLK_X_DMIC2 = 0x1 << 2, - CLK_X_ETR = 0x1 << 3, - CLK_X_CAM_MCLK = 0x1 << 4, - CLK_X_CAM_MCLK2 = 0x1 << 5, - CLK_X_I2C6 = 0x1 << 6, - CLK_X_MC_CAPA = 0x1 << 7, - CLK_X_MC_CBPA = 0x1 << 8, - CLK_X_MC_CPU = 0x1 << 9, - CLK_X_MC_BBC = 0x1 << 10, - CLK_X_VIM2_CLK = 0x1 << 11, - CLK_X_MIPIBIF = 0x1 << 13, - CLK_X_EMC_DLL = 0x1 << 14, - CLK_X_UART_FST_MIPI_CAL = 0x1 << 17, - CLK_X_VIC = 0x1 << 18, - CLK_X_DPAUX = 0x1 << 21, - CLK_X_SOR0 = 0x1 << 22, - CLK_X_SOR1 = 0x1 << 23, - CLK_X_GPU = 0x1 << 24, - CLK_X_DPGAPB = 0x1 << 25, - CLK_X_HPLL_ADSP = 0x1 << 26, - CLK_X_PLLP_ADSP = 0x1 << 27, - CLK_X_PLLA_ADSP = 0x1 << 28, - CLK_X_PLLG_REF = 0x1 << 29, - - CLK_Y_SPARE1 = 0x1 << 0, - CLK_Y_SDMMC_LEGACY_TM = 0x1 << 1, - CLK_Y_NVDEC = 0x1 << 2, - CLK_Y_NVJPG = 0x1 << 3, - CLK_Y_AXIAP = 0x1 << 4, - CLK_Y_DMIC3 = 0x1 << 5, - CLK_Y_APE = 0x1 << 6, - CLK_Y_ADSP = 0x1 << 7, - CLK_Y_MC_CDPA = 0x1 << 8, - CLK_Y_MC_CCPA = 0x1 << 9, - CLK_Y_MAUD = 0x1 << 10, - CLK_Y_TSECB = 0x1 << 14, - CLK_Y_DPAUX1 = 0x1 << 15, - CLK_Y_VI_I2C = 0x1 << 16, - CLK_Y_HSIC_TRK = 0x1 << 17, - CLK_Y_USB2_TRK = 0x1 << 18, - CLK_Y_QSPI = 0x1 << 19, - CLK_Y_UARTAPE = 0x1 << 20, - CLK_Y_ADSPNEON = 0x1 << 26, - CLK_Y_NVENC = 0x1 << 27, - CLK_Y_IQC2 = 0x1 << 28, - CLK_Y_IQC1 = 0x1 << 29, - CLK_Y_SOR_SAFE = 0x1 << 30, - CLK_Y_PLLP_OUT_CPU = 0x1 << 31 -}; - -/* PLLM specific registers */ -#define PLLM_MISC1_SETUP_SHIFT 0 -#define PLLM_MISC1_PD_LSHIFT_PH45_SHIFT 28 -#define PLLM_MISC1_PD_LSHIFT_PH90_SHIFT 29 -#define PLLM_MISC1_PD_LSHIFT_PH135_SHIFT 30 -#define PLLM_MISC2_KCP_SHIFT 1 -#define PLLM_MISC2_KVCO_SHIFT 0 -#define PLLM_OUT1_RSTN_RESET_DISABLE (1 << 0) -#define PLLM_EN_LCKDET (1 << 4) - -/* CLK_RST_CONTROLLER_PLL*_BASE_0 */ -#define PLL_BASE_BYPASS (1U << 31) -#define PLL_BASE_ENABLE (1U << 30) -#define PLL_BASE_REF_DIS (1U << 29) -#define PLL_BASE_OVRRIDE (1U << 28) -#define PLL_BASE_LOCK (1U << 27) -#define PLLC_BASE_LOCK (1U << 26) - -#define PLL_BASE_DIVP_SHIFT 20 -#define PLL_BASE_DIVP_MASK (7U << PLL_BASE_DIVP_SHIFT) - -#define PLL_BASE_DIVN_SHIFT 8 -#define PLL_BASE_DIVN_MASK (0x3ffU << PLL_BASE_DIVN_SHIFT) - -#define PLL_BASE_DIVM_SHIFT 0 -#define PLL_BASE_DIVM_MASK (0x1f << PLL_BASE_DIVM_SHIFT) - -/* SPECIAL CASE: PLLM, PLLC and PLLX use different-sized fields here */ -#define PLLCX_BASE_DIVP_MASK (0xfU << PLL_BASE_DIVP_SHIFT) -#define PLLM_BASE_DIVP_MASK (0x1fU << PLL_BASE_DIVP_SHIFT) -#define PLLCMX_BASE_DIVN_MASK (0xffU << PLL_BASE_DIVN_SHIFT) -#define PLLCMX_BASE_DIVM_MASK (0xffU << PLL_BASE_DIVM_SHIFT) - -#define PLLX_IDDQ_SHIFT 3 -#define PLLX_IDDQ_MASK (1U << PLLX_IDDQ_SHIFT) - -#define CLK_DIVISOR_MASK (0xffff) - -#define CLK_SOURCE_SHIFT 29 -#define CLK_SOURCE_MASK (0x7 << CLK_SOURCE_SHIFT) - -#define CLK_SOURCE_EMC_MC_EMC_SAME_FREQ (1 << 16) -#define EMC_2X_CLK_SRC_SHIFT 29 -#define PLLM_UD 4 - -/* PLL stabilization delay in usec */ -#define CLOCK_PLL_STABLE_DELAY_US 300 - -#define IO_STABILIZATION_DELAY (2) -#define LOGIC_STABILIZATION_DELAY (2) - -/* Bits to enable/reset modules */ -#define CLK_ENB_CPU (1 << 0) -#define SWR_TRIG_SYS_RST (1 << 2) -#define SWR_CSITE_RST (1 << 9) -#define CLK_ENB_CSITE (1 << 9) -#define CLK_ENB_EMC_DLL (1 << 14) - -/*! Generic clock descriptor. */ -typedef struct _clock_t -{ - u32 reset; - u32 enable; - u32 source; - u8 index; - u8 clk_src; - u8 clk_div; -} clock_t; - -/*! Generic clock enable/disable. */ -void clock_enable(const clock_t *clk); -void clock_disable(const clock_t *clk); - -/*! Clock control for specific hardware portions. */ -void clock_enable_fuse(u32 enable); -void clock_enable_uart(u32 idx); -void clock_enable_i2c(u32 idx); -void clock_enable_se(); -void clock_enable_host1x(); -void clock_disable_host1x(); -void clock_enable_tsec(); -void clock_disable_tsec(); -void clock_enable_sor_safe(); -void clock_disable_sor_safe(); -void clock_enable_sor0(); -void clock_disable_sor0(); -void clock_enable_sor1(); -void clock_disable_sor1(); -void clock_enable_kfuse(); -void clock_disable_kfuse(); -void clock_enable_cl_dvfs(); -void clock_enable_coresight(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type); -int clock_sdmmc_is_not_reset_and_enabled(u32 id); -void clock_sdmmc_enable(u32 id, u32 val); -void clock_sdmmc_disable(u32 id); - -void clock_halt_bpmp(void); - -#endif diff --git a/ariane/src/hwinit/cluster.c b/ariane/src/hwinit/cluster.c deleted file mode 100644 index 4ff4cc1..0000000 --- a/ariane/src/hwinit/cluster.c +++ /dev/null @@ -1,143 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "cluster.h" -#include "clock.h" -#include "timer.h" -#include "pmc.h" -#include "flow.h" -#include "t210.h" -#include "i2c.h" -#include "max7762x.h" -#include "max77620.h" - -void _cluster_enable_power() -{ - u8 tmp = max77620_recv_byte(MAX77620_REG_AME_GPIO); - max77620_send_byte(MAX77620_REG_AME_GPIO, tmp & 0xDF); - max77620_send_byte(MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); - - // Enable cores power. - max7762x_send_byte(MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE); // 1-3.x: MAX77621_NFSR_ENABLE - max7762x_send_byte(MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - // 1-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL - max7762x_send_byte(MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37); - max7762x_send_byte(MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37); -} - -int _cluster_pmc_enable_partition(u32 part, u32 toggle, u32 enable) -{ - //Check if the partition has already been turned on. - if (enable && (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)) - return 1; - - u32 startTime = get_tmr_ms(); - while (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & 0x100) - { - if (get_tmr_ms() - startTime >= 5) //only wait for 5ms - return 0; - } - - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0); - - startTime = get_tmr_ms(); - while ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part) == 0) - { - if (get_tmr_ms() - startTime >= 5) //only wait for 5ms - return 0; - } - - return 1; -} - -#define PLLX_VALUE_FROM_DIVS(DIVM, DIVN, DIVP) (((DIVP & 0x1F) << 20) | ((DIVN & 0xFF) << 8) | (DIVM & 0xFF)) - -void cluster_boot_cpu0(u32 entry) -{ - struct flow_ctlr* const flow = (void *)FLOW_CTLR_BASE; - flow->bpmp_cluster_control &= ~(1u << 0); //Set ACTIVE_CLUSER to FAST. - - _cluster_enable_power(); - - //final_freq = ((38.4MHz / DIVM) * DIVN) / (2^DIVP) - typedef struct freqEntry_s { u32 clkFreqHz; u32 pllxDividers; } freqEntry_t; - static const freqEntry_t frequencies[] = - { - { 93600000, PLLX_VALUE_FROM_DIVS(2, 78, 4) }, //93.6MHz (bench: 6677351 us) - { 187200000, PLLX_VALUE_FROM_DIVS(2, 78, 3) }, //187.2MHz (bench: 5341881 us) - { 249600000, PLLX_VALUE_FROM_DIVS(3, 156, 3) }, //249.6MHz (bench: 4006410 us) - { 499200000, PLLX_VALUE_FROM_DIVS(3, 156, 2) }, //499.2MHz (bench: 3004808 us) - { 748800000, PLLX_VALUE_FROM_DIVS(2, 78, 1) }, //748.8MHz (bench: 2670940 us) - { 998400000, PLLX_VALUE_FROM_DIVS(3, 156, 1) } //998.4MHz (bench: 2003206 us) - }; - - static const u32 pllxDividers = frequencies[0].pllxDividers; - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & (1u << 30))) - { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~(1u << 3); - usleep(2); - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = (1u << 31) | pllxDividers; - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x00000000 | pllxDividers; - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= (1u << 18); - CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = (1u << 30) | pllxDividers; - } - while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x8000000)) {} - - //Configure MSELECT source and enable clock. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= CLK_V_MSELECT; - - //Configure initial CPU clock frequency and enable clock. - CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; - CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = CLK_V_CPUG; - - clock_enable_coresight(); - - //CAR2PMC_CPU_ACK_WIDTH should be set to 0. - CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; - - //Enable CPU rail. - _cluster_pmc_enable_partition(1, 0, 1); - //Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(0x8000, 15, 1); - //Enable CE0. - _cluster_pmc_enable_partition(0x4000, 14, 1); - - //Request and wait for RAM repair. - flow->ram_repair = 1; - while (!(flow->ram_repair & 2)) {} - - EXCP_VEC(0x100) = 0; - - //Keep bootrom accessible after cluster boot - SB(SB_PIROM_START) = 96*1024; - //Set reset vector. - SB(SB_AA64_RESET_LOW) = entry | 1; - SB(SB_AA64_RESET_HIGH) = 0; - //Non-secure reset vector write disable. - SB(SB_CSR) = 2; - (void)SB(SB_CSR); - - //Clear MSELECT reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= ~CLK_V_MSELECT; - //Clear NONCPU reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; - //Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. - CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x411F000F; -} diff --git a/ariane/src/hwinit/cluster.h b/ariane/src/hwinit/cluster.h deleted file mode 100644 index 94a4725..0000000 --- a/ariane/src/hwinit/cluster.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _CLUSTER_H_ -#define _CLUSTER_H_ - -#include "types.h" - -void cluster_boot_cpu0(u32 entry); - -#endif diff --git a/ariane/src/hwinit/di.c b/ariane/src/hwinit/di.c deleted file mode 100644 index cd54ac7..0000000 --- a/ariane/src/hwinit/di.c +++ /dev/null @@ -1,209 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "di.h" -#include "clock.h" -#include "gpio.h" -#include "pinmux.h" -#include "t210.h" -#include "timer.h" -#include "util.h" -#include "pmc.h" -#include "max7762x.h" -#include "max77620.h" - -#include "di.inl" - -static u32 _display_ver = 0; - -static void _display_dsi_wait(u32 milliseconds, u32 off, u32 mask) -{ - u32 end = get_tmr_ms() + milliseconds; - while (DSI(off) & mask) { if (get_tmr_ms() >= end) return; } - usleep(5); -} - -void display_init() -{ - //Power on. - max77620_regulator_set_voltage(REGULATOR_LDO0, 1200000); //1.2V - max77620_regulator_enable(REGULATOR_LDO0, 1); - max77620_send_byte(MAX77620_REG_GPIO7, 0x09); - - //Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = CLK_H_DSI | CLK_H_MIPI_CAL; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLK_H_DSI | CLK_H_MIPI_CAL; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = CLK_L_DISP1 | CLK_L_HOST1X; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = CLK_L_DISP1 | CLK_L_HOST1X; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = CLK_X_UART_FST_MIPI_CAL; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 0xA; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = CLK_W_DSIA_LP; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA; - - //DPD idle. - PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; - PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; - - //Config pins. - pinmux_set_config(PINMUX_GPIO_I0, pinmux_get_config(PINMUX_GPIO_I0) & (~PINMUX_TRISTATE)); - pinmux_set_config(PINMUX_GPIO_I1, pinmux_get_config(PINMUX_GPIO_I1) & (~PINMUX_TRISTATE)); - pinmux_set_config(PINMUX_LCD_BL_PWM_INDEX, pinmux_get_config(PINMUX_LCD_BL_PWM_INDEX) & (~PINMUX_TRISTATE)); - pinmux_set_config(PINMUX_LCD_BL_EN_INDEX, pinmux_get_config(PINMUX_LCD_BL_EN_INDEX) & (~PINMUX_TRISTATE)); - pinmux_set_config(PINMUX_LCD_RST_INDEX, pinmux_get_config(PINMUX_LCD_RST_INDEX) & (~PINMUX_TRISTATE)); - - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); //Backlight +-5V. - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); //Backlight +-5V. - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); //Backlight +5V enable. - - msleep(10); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); //Backlight -5V enable. - msleep(10); - - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); //Backlight PWM, Enable, Reset. - gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_BY_NAME(LCD_BL_EN), GPIO_HIGH); //Backlight Enable enable. - - //Config display interface and display. - MIPI_CAL(0x60) = 0; - - exec_cfg((u32 *)CLOCK_BASE, _display_config_1, ARRAY_SIZE(_display_config_1)); - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, ARRAY_SIZE(_display_config_2)); - exec_cfg((u32 *)DSI_BASE, _display_config_3, ARRAY_SIZE(_display_config_3)); - - msleep(10); - gpio_write(GPIO_BY_NAME(LCD_RST), GPIO_HIGH); //Backlight Reset enable. - msleep(60); - - DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; - DSI(_DSIREG(DSI_WR_DATA)) = 0x337; - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x406; - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - _display_dsi_wait(250, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); - - DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; - _display_dsi_wait(150, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); - - msleep(5); - - _display_ver = DSI(_DSIREG(DSI_RD_DATA)); - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_4, ARRAY_SIZE(_display_config_4)); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - msleep(180); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - msleep(20); - - exec_cfg((u32 *)DSI_BASE, _display_config_5, ARRAY_SIZE(_display_config_5)); - exec_cfg((u32 *)CLOCK_BASE, _display_config_6, ARRAY_SIZE(_display_config_6)); - DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; - exec_cfg((u32 *)DSI_BASE, _display_config_7, ARRAY_SIZE(_display_config_7)); - - msleep(10); - - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, ARRAY_SIZE(_display_config_8)); - exec_cfg((u32 *)DSI_BASE, _display_config_9, ARRAY_SIZE(_display_config_9)); - exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, ARRAY_SIZE(_display_config_10)); - - msleep(10); - - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, ARRAY_SIZE(_display_config_11)); -} - -void display_enable_backlight(u32 on) -{ - gpio_write(GPIO_BY_NAME(LCD_BL_PWM), on ? GPIO_HIGH : GPIO_LOW); //Backlight PWM. -} - -void display_end() -{ - display_enable_backlight(0); - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1; - DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; - - u32 end = HOST1X(0x30A4) + 5; - while (HOST1X(0x30A4) < end) {} - - DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; - - exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, ARRAY_SIZE(_display_config_12)); - exec_cfg((u32 *)DSI_BASE, _display_config_13, ARRAY_SIZE(_display_config_13)); - - msleep(10); - - if (_display_ver == 0x10) - exec_cfg((u32 *)DSI_BASE, _display_config_14, ARRAY_SIZE(_display_config_14)); - - DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; - DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; - - msleep(50); - gpio_write(GPIO_BY_NAME(LCD_RST), GPIO_LOW); //Backlight Reset disable. - msleep(10); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. - msleep(10); - gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. - msleep(10); - - //Disable clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = CLK_H_DSI | CLK_H_MIPI_CAL; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = CLK_H_DSI | CLK_H_MIPI_CAL; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = CLK_L_DISP1 | CLK_L_HOST1X; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = CLK_L_DISP1 | CLK_L_HOST1X; - - DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); - DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; - - gpio_config(GPIO_BY_NAME(LCD_BL_PWM), GPIO_MODE_SPIO); //Backlight PWM. - - pinmux_set_config(PINMUX_LCD_BL_PWM_INDEX, pinmux_get_config(PINMUX_LCD_BL_PWM_INDEX) | PINMUX_TRISTATE); - pinmux_set_config(PINMUX_LCD_BL_PWM_INDEX, (pinmux_get_config(PINMUX_LCD_BL_PWM_INDEX) & (~PINMUX_FUNC_MASK)) | PINMUX_LCD_BL_PWM_FUNC_PWM0); -} - -void display_color_screen(u32 color) -{ - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8); - - //Configure display to show single color. - DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; - DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; - DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - - msleep(35); - - display_enable_backlight(1); -} - -u32 *display_init_framebuffer(u32 *fb) -{ - //This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, ARRAY_SIZE(cfg_display_framebuffer)); - - msleep(35); - - return (u32 *)0xC0000000; -} \ No newline at end of file diff --git a/ariane/src/hwinit/emc.h b/ariane/src/hwinit/emc.h deleted file mode 100644 index 8c7b020..0000000 --- a/ariane/src/hwinit/emc.h +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. - * Copyright (C) 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __SOC_NVIDIA_TEGRA210_EMC_H__ -#define __SOC_NVIDIA_TEGRA210_EMC_H__ - -#include -#include -#include "types.h" - -enum { - EMC_PIN_RESET_MASK = 1 << 8, - EMC_PIN_RESET_ACTIVE = 0 << 8, - EMC_PIN_RESET_INACTIVE = 1 << 8, - EMC_PIN_DQM_MASK = 1 << 4, - EMC_PIN_DQM_NORMAL = 0 << 4, - EMC_PIN_DQM_INACTIVE = 1 << 4, - EMC_PIN_CKE_MASK = 1 << 0, - EMC_PIN_CKE_POWERDOWN = 0 << 0, - EMC_PIN_CKE_NORMAL = 1 << 0, - - EMC_REF_CMD_MASK = 1 << 0, - EMC_REF_CMD_REFRESH = 1 << 0, - EMC_REF_NORMAL_MASK = 1 << 1, - EMC_REF_NORMAL_INIT = 0 << 1, - EMC_REF_NORMAL_ENABLED = 1 << 1, - EMC_REF_NUM_SHIFT = 8, - EMC_REF_NUM_MASK = 0xFF << EMC_REF_NUM_SHIFT, - EMC_REF_DEV_SELECTN_SHIFT = 30, - EMC_REF_DEV_SELECTN_MASK = 3 << EMC_REF_DEV_SELECTN_SHIFT, - - EMC_REFCTRL_REF_VALID_MASK = 1 << 31, - EMC_REFCTRL_REF_VALID_DISABLED = 0 << 31, - EMC_REFCTRL_REF_VALID_ENABLED = 1 << 31, - - EMC_CFG_EMC2PMACRO_CFG_BYPASS_ADDRPIPE_MASK = 1 << 1, - EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE1_MASK = 1 << 2, - EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE2_MASK = 1 << 3, - - EMC_NOP_CMD_SHIFT = 0, - EMC_NOP_CMD_MASK = 1 << EMC_NOP_CMD_SHIFT, - EMC_NOP_DEV_SELECTN_SHIFT = 30, - EMC_NOP_DEV_SELECTN_MASK = 3 << EMC_NOP_DEV_SELECTN_SHIFT, - - EMC_TIMING_CONTROL_TIMING_UPDATE = 1, - - EMC_PIN_GPIOEN_SHIFT = 16, - EMC_PIN_GPIO_SHIFT = 12, - EMC_PMACRO_BRICK_CTRL_RFU1_RESET_VAL = 0x1FFF1FFF, - - AUTOCAL_MEASURE_STALL_ENABLE = 1 << 9, - WRITE_MUX_ACTIVE = 1 << 1, - CFG_ADR_EN_LOCKED = 1 << 1, -}; - -struct tegra_emc_regs { - vu32 intstatus; /* 0x0 */ - vu32 intmask; /* 0x4 */ - vu32 dbg; /* 0x8 */ - vu32 cfg; /* 0xc */ - vu32 adr_cfg; /* 0x10 */ - vu32 rsvd_0x14[3]; /* 0x14-0x1C */ - - vu32 refctrl; /* 0x20 */ - vu32 pin; /* 0x24 */ - vu32 timing_control; /* 0x28 */ - vu32 rc; /* 0x2c */ - vu32 rfc; /* 0x30 */ - vu32 ras; /* 0x34 */ - vu32 rp; /* 0x38 */ - vu32 r2w; /* 0x3c */ - vu32 w2r; /* 0x40 */ - vu32 r2p; /* 0x44 */ - vu32 w2p; /* 0x48 */ - vu32 rd_rcd; /* 0x4c */ - vu32 wr_rcd; /* 0x50 */ - vu32 rrd; /* 0x54 */ - vu32 rext; /* 0x58 */ - vu32 wdv; /* 0x5c */ - vu32 quse; /* 0x60 */ - vu32 qrst; /* 0x64 */ - vu32 qsafe; /* 0x68 */ - vu32 rdv; /* 0x6c */ - vu32 refresh; /* 0x70 */ - vu32 burst_refresh_num; /* 0x74 */ - vu32 pdex2wr; /* 0x78 */ - vu32 pdex2rd; /* 0x7c */ - vu32 pchg2pden; /* 0x80 */ - vu32 act2pden; /* 0x84 */ - vu32 ar2pden; /* 0x88 */ - vu32 rw2pden; /* 0x8c */ - vu32 txsr; /* 0x90 */ - vu32 tcke; /* 0x94 */ - vu32 tfaw; /* 0x98 */ - vu32 trpab; /* 0x9c */ - vu32 tclkstable; /* 0xa0 */ - vu32 tclkstop; /* 0xa4 */ - vu32 trefbw; /* 0xa8 */ - vu32 tppd; /* 0xac */ - vu32 odt_write; /* 0xb0 */ - vu32 pdex2mrr; /* 0xb4 */ - vu32 wext; /* 0xb8 */ - vu32 ctt; /* 0xbc */ - vu32 rfc_slr; /* 0xc0 */ - vu32 mrs_wait_cnt2; /* 0xc4 */ - vu32 mrs_wait_cnt; /* 0xc8 */ - vu32 mrs; /* 0xcc */ - vu32 emrs; /* 0xd0 */ - vu32 ref; /* 0xd4 */ - vu32 pre; /* 0xd8 */ - vu32 nop; /* 0xdc */ - vu32 self_ref; /* 0xe0 */ - vu32 dpd; /* 0xe4 */ - vu32 mrw; /* 0xe8 */ - vu32 mrr; /* 0xec */ - vu32 cmdq; /* 0xf0 */ - vu32 mc2emcq; /* 0xf4 */ - vu32 xm2dqspadctrl3; /* 0xf8 */ - vu32 rsvd_0xfc[1]; /* 0xfc */ - vu32 fbio_spare; /* 0x100 */ - vu32 fbio_cfg5; /* 0x104 */ - vu32 fbio_wrptr_eq_2; /* 0x108 */ - vu32 rsvd_0x10c[2]; /* 0x10c-0x110 */ - - vu32 fbio_cfg6; /* 0x114 */ - vu32 pdex2cke; /* 0x118 */ - vu32 cke2pden; /* 0x11C */ - vu32 cfg_rsv; /* 0x120 */ - vu32 acpd_control; /* 0x124 */ - vu32 rsvd_0x128[1]; /* 0x128 */ - vu32 emrs2; /* 0x12c */ - vu32 emrs3; /* 0x130 */ - vu32 mrw2; /* 0x134 */ - vu32 mrw3; /* 0x138 */ - vu32 mrw4; /* 0x13c */ - vu32 clken_override; /* 0x140 */ - vu32 r2r; /* 0x144 */ - vu32 w2w; /* 0x148 */ - vu32 einput; /* 0x14c */ - vu32 einput_duration; /* 0x150 */ - vu32 puterm_extra; /* 0x154 */ - vu32 tckesr; /* 0x158 */ - vu32 tpd; /* 0x15c */ - vu32 rsvd_0x160[81]; /* 0x160-0x2A0 */ - - vu32 auto_cal_config; /* 0x2a4 */ - vu32 auto_cal_interval; /* 0x2a8 */ - vu32 auto_cal_status; /* 0x2ac */ - vu32 req_ctrl; /* 0x2b0 */ - vu32 status; /* 0x2b4 */ - vu32 cfg_2; /* 0x2b8 */ - vu32 cfg_dig_dll; /* 0x2bc */ - vu32 cfg_dig_dll_period; /* 0x2c0 */ - vu32 dig_dll_status; /* 0x2C4 */ - vu32 cfg_dig_dll_1; /* 0x2C8 */ - vu32 rdv_mask; /* 0x2cc */ - vu32 wdv_mask; /* 0x2d0 */ - vu32 rdv_early_mask; /* 0x2d4 */ - vu32 rdv_early; /* 0x2d8 */ - vu32 auto_cal_config8; /* 0x2DC */ - vu32 zcal_interval; /* 0x2e0 */ - vu32 zcal_wait_cnt; /* 0x2e4 */ - vu32 zcal_mrw_cmd; /* 0x2e8 */ - vu32 zq_cal; /* 0x2ec */ - vu32 xm2cmdpadctrl; /* 0x2f0 */ - vu32 xm2comppadctrl3; /* 0x2f4 */ - vu32 auto_cal_vref_sel0; /* 0x2f8 */ - vu32 xm2dqspadctrl2; /* 0x2fc */ - vu32 auto_cal_vref_sel1; /* 0x300 */ - vu32 xm2dqpadctrl2; /* 0x304 */ - vu32 xm2clkpadctrl; /* 0x308 */ - vu32 xm2comppadctrl; /* 0x30c */ - vu32 fdpd_ctrl_dq; /* 0x310 */ - vu32 fdpd_ctrl_cmd; /* 0x314 */ - vu32 pmacro_cmd_brick_ctrl_fdpd; /* 0x318 */ - vu32 pmacro_data_brick_ctrl_fdpd; /* 0x31c */ - vu32 xm2dqspadctrl4; /* 0x320 */ - vu32 scratch0; /* 0x324 */ - vu32 rsvd_0x328[2]; /* 0x328-0x32C */ - - vu32 pmacro_brick_ctrl_rfu1; /* 0x330 */ - vu32 pmacro_brick_ctrl_rfu2; /* 0x334 */ - vu32 rsvd_0x338[18]; /* 0x338-0x37C */ - - vu32 cmd_mapping_cmd0_0; /* 0x380 */ - vu32 cmd_mapping_cmd0_1; /* 0x384 */ - vu32 cmd_mapping_cmd0_2; /* 0x388 */ - vu32 cmd_mapping_cmd1_0; /* 0x38c */ - vu32 cmd_mapping_cmd1_1; /* 0x390 */ - vu32 cmd_mapping_cmd1_2; /* 0x394 */ - vu32 cmd_mapping_cmd2_0; /* 0x398 */ - vu32 cmd_mapping_cmd2_1; /* 0x39C */ - vu32 cmd_mapping_cmd2_2; /* 0x3A0 */ - vu32 cmd_mapping_cmd3_0; /* 0x3A4 */ - vu32 cmd_mapping_cmd3_1; /* 0x3A8 */ - vu32 cmd_mapping_cmd3_2; /* 0x3AC */ - vu32 cmd_mapping_byte; /* 0x3B0 */ - vu32 tr_timing_0; /* 0x3B4 */ - vu32 tr_ctrl_0; /* 0x3B8 */ - vu32 tr_ctrl_1; /* 0x3BC */ - vu32 switch_back_ctrl; /* 0x3C0 */ - vu32 tr_rdv; /* 0x3C4 */ - vu32 stall_then_exe_before_clkchange; /* 0x3c8 */ - vu32 stall_then_exe_after_clkchange; /* 0x3cc */ - vu32 unstall_rw_after_clkchange; /* 0x3d0 */ - vu32 auto_cal_clk_status; /* 0x3d4 */ - vu32 sel_dpd_ctrl; /* 0x3d8 */ - vu32 pre_refresh_req_cnt; /* 0x3dc */ - vu32 dyn_self_ref_control; /* 0x3e0 */ - vu32 txsrdll; /* 0x3e4 */ - vu32 ccfifo_addr; /* 0x3e8 */ - vu32 ccfifo_data; /* 0x3ec */ - vu32 ccfifo_status; /* 0x3f0 */ - vu32 cdb_cntl_1; /* 0x3f4 */ - vu32 cdb_cntl_2; /* 0x3f8 */ - vu32 xm2clkpadctrl2; /* 0x3fc */ - vu32 swizzle_rank0_byte_cfg; /* 0x400 */ - vu32 swizzle_rank0_byte0; /* 0x404 */ - vu32 swizzle_rank0_byte1; /* 0x408 */ - vu32 swizzle_rank0_byte2; /* 0x40c */ - vu32 swizzle_rank0_byte3; /* 0x410 */ - vu32 swizzle_rank1_byte_cfg; /* 0x414 */ - vu32 swizzle_rank1_byte0; /* 0x418 */ - vu32 swizzle_rank1_byte1; /* 0x41c */ - vu32 swizzle_rank1_byte2; /* 0x420 */ - vu32 swizzle_rank1_byte3; /* 0x424 */ - vu32 issue_qrst; /* 0x428 */ - vu32 rsvd_0x42C[5]; /* 0x42C-0x43C */ - vu32 pmc_scratch1; /* 0x440 */ - vu32 pmc_scratch2; /* 0x444 */ - vu32 pmc_scratch3; /* 0x448 */ - vu32 rsvd_0x44C[3]; /* 0x44C-0x454 */ - vu32 auto_cal_config2; /* 0x458 */ - vu32 auto_cal_config3; /* 0x45c */ - vu32 auto_cal_status2; /* 0x460 */ - vu32 auto_cal_channel; /* 0x464 */ - vu32 ibdly; /* 0x468 */ - vu32 obdly; /* 0x46c */ - vu32 rsvd_0x470[3]; /* 0x470-0x478 */ - - vu32 dsr_vttgen_drv; /* 0x47c */ - vu32 txdsrvttgen; /* 0x480 */ - vu32 xm2cmdpadctrl4; /* 0x484 */ - vu32 xm2cmdpadctrl5; /* 0x488 */ - vu32 we_duration; /* 0x48C */ - vu32 ws_duration; /* 0x490 */ - vu32 wev; /* 0x494 */ - vu32 wsv; /* 0x498 */ - vu32 cfg_3; /* 0x49C */ - vu32 mrw5; /* 0x4A0 */ - vu32 mrw6; /* 0x4A4 */ - vu32 mrw7; /* 0x4A8 */ - vu32 mrw8; /* 0x4AC */ - vu32 mrw9; /* 0x4B0 */ - vu32 mrw10; /* 0x4B4 */ - vu32 mrw11; /* 0x4B8 */ - vu32 mrw12; /* 0x4BC */ - vu32 mrw13; /* 0x4C0 */ - vu32 mrw14; /* 0x4C4 */ - vu32 rsvd_0x4c8[2]; /* 0x4C8-0x4CC */ - - vu32 mrw15; /* 0x4D0 */ - vu32 cfg_sync; /* 0x4D4 */ - vu32 fdpd_ctrl_cmd_no_ramp; /* 0x4D8 */ - vu32 rsvd_0x4dc[1]; /* 0x4DC */ - vu32 wdv_chk; /* 0x4E0 */ - vu32 rsvd_0x4e4[28]; /* 0x4E4-0x550 */ - - vu32 cfg_pipe2; /* 0x554 */ - vu32 cfg_pipe_clk; /* 0x558 */ - vu32 cfg_pipe1; /* 0x55C */ - vu32 cfg_pipe; /* 0x560 */ - vu32 qpop; /* 0x564 */ - vu32 quse_width; /* 0x568 */ - vu32 puterm_width; /* 0x56c */ - vu32 bgbias_ctl0; /* 0x570 */ - vu32 auto_cal_config7; /* 0x574 */ - vu32 xm2comppadctrl2; /* 0x578 */ - vu32 comppadswctrl; /* 0x57C */ - vu32 refctrl2; /* 0x580 */ - vu32 fbio_cfg7; /* 0x584 */ - vu32 data_brlshft_0; /* 0x588 */ - vu32 data_brlshft_1; /* 0x58C */ - vu32 rfcpb; /* 0x590 */ - vu32 dqs_brlshft_0; /* 0x594 */ - vu32 dqs_brlshft_1; /* 0x598 */ - vu32 cmd_brlshft_0; /* 0x59C */ - vu32 cmd_brlshft_1; /* 0x5A0 */ - vu32 cmd_brlshft_2; /* 0x5A4 */ - vu32 cmd_brlshft_3; /* 0x5A8 */ - vu32 quse_brlshft_0; /* 0x5AC */ - vu32 auto_cal_config4; /* 0x5B0 */ - vu32 auto_cal_config5; /* 0x5B4 */ - vu32 quse_brlshft_1; /* 0x5B8 */ - vu32 quse_brlshft_2; /* 0x5BC */ - vu32 ccdmw; /* 0x5C0 */ - vu32 quse_brlshft_3; /* 0x5C4 */ - vu32 fbio_cfg8; /* 0x5C8 */ - vu32 auto_cal_config6; /* 0x5CC */ - vu32 protobist_config_addr_1; /* 0x5D0 */ - vu32 protobist_config_addr_2; /* 0x5D4 */ - vu32 protobist_misc; /* 0x5D8 */ - vu32 protobist_wdata_lower; /* 0x5DC */ - vu32 protobist_wdata_upper; /* 0x5E0 */ - vu32 dll_cfg0; /* 0x5E4 */ - vu32 dll_cfg1; /* 0x5E8 */ - vu32 protobist_rdata; /* 0x5EC */ - vu32 config_sample_delay; /* 0x5F0 */ - vu32 cfg_update; /* 0x5F4 */ - vu32 rsvd_0x5f8[2]; /* 0x5F8-0x5FC */ - - vu32 pmacro_quse_ddll_rank0_0; /* 0x600 */ - vu32 pmacro_quse_ddll_rank0_1; /* 0x604 */ - vu32 pmacro_quse_ddll_rank0_2; /* 0x608 */ - vu32 pmacro_quse_ddll_rank0_3; /* 0x60C */ - vu32 pmacro_quse_ddll_rank0_4; /* 0x610 */ - vu32 pmacro_quse_ddll_rank0_5; /* 0x614 */ - vu32 rsvd_0x618[2]; /* 0x618-0x61C */ - - vu32 pmacro_quse_ddll_rank1_0; /* 0x620 */ - vu32 pmacro_quse_ddll_rank1_1; /* 0x624 */ - vu32 pmacro_quse_ddll_rank1_2; /* 0x628 */ - vu32 pmacro_quse_ddll_rank1_3; /* 0x62C */ - vu32 pmacro_quse_ddll_rank1_4; /* 0x630 */ - vu32 pmacro_quse_ddll_rank1_5; /* 0x634 */ - vu32 rsvd_0x638[2]; /* 0x638-0x63C */ - - vu32 pmacro_ob_ddll_long_dq_rank0_0; /* 0x640 */ - vu32 pmacro_ob_ddll_long_dq_rank0_1; /* 0x644 */ - vu32 pmacro_ob_ddll_long_dq_rank0_2; /* 0x648 */ - vu32 pmacro_ob_ddll_long_dq_rank0_3; /* 0x64C */ - vu32 pmacro_ob_ddll_long_dq_rank0_4; /* 0x650 */ - vu32 pmacro_ob_ddll_long_dq_rank0_5; /* 0x654 */ - vu32 rsvd_0x658[2]; /* 0x658-0x65C */ - - vu32 pmacro_ob_ddll_long_dq_rank1_0; /* 0x660 */ - vu32 pmacro_ob_ddll_long_dq_rank1_1; /* 0x664 */ - vu32 pmacro_ob_ddll_long_dq_rank1_2; /* 0x668 */ - vu32 pmacro_ob_ddll_long_dq_rank1_3; /* 0x66C */ - vu32 pmacro_ob_ddll_long_dq_rank1_4; /* 0x670 */ - vu32 pmacro_ob_ddll_long_dq_rank1_5; /* 0x674 */ - vu32 rsvd_0x678[2]; /* 0x678-0x67C */ - - vu32 pmacro_ob_ddll_long_dqs_rank0_0; /* 0x680 */ - vu32 pmacro_ob_ddll_long_dqs_rank0_1; /* 0x684 */ - vu32 pmacro_ob_ddll_long_dqs_rank0_2; /* 0x688 */ - vu32 pmacro_ob_ddll_long_dqs_rank0_3; /* 0x68C */ - vu32 pmacro_ob_ddll_long_dqs_rank0_4; /* 0x690 */ - vu32 pmacro_ob_ddll_long_dqs_rank0_5; /* 0x694 */ - vu32 rsvd_0x698[2]; /* 0x698-0x69C */ - - vu32 pmacro_ob_ddll_long_dqs_rank1_0; /* 0x6A0 */ - vu32 pmacro_ob_ddll_long_dqs_rank1_1; /* 0x6A4 */ - vu32 pmacro_ob_ddll_long_dqs_rank1_2; /* 0x6A8 */ - vu32 pmacro_ob_ddll_long_dqs_rank1_3; /* 0x6AC */ - vu32 pmacro_ob_ddll_long_dqs_rank1_4; /* 0x6B0 */ - vu32 pmacro_ob_ddll_long_dqs_rank1_5; /* 0x6B4 */ - vu32 rsvd_0x6B8[2]; /* 0x6B8-0x6BC */ - - vu32 pmacro_ib_ddll_long_dqs_rank0_0; /* 0x6C0 */ - vu32 pmacro_ib_ddll_long_dqs_rank0_1; /* 0x6C4 */ - vu32 pmacro_ib_ddll_long_dqs_rank0_2; /* 0x6C8 */ - vu32 pmacro_ib_ddll_long_dqs_rank0_3; /* 0x6CC */ - vu32 pmacro_ib_ddll_long_dqs_rank0_4; /* 0x6D0 */ - vu32 pmacro_ib_ddll_long_dqs_rank0_5; /* 0x6D4 */ - vu32 rsvd_0x6D8[2]; /* 0x6D8-0x6DC */ - - vu32 pmacro_ib_ddll_long_dqs_rank1_0; /* 0x6E0 */ - vu32 pmacro_ib_ddll_long_dqs_rank1_1; /* 0x6E4 */ - vu32 pmacro_ib_ddll_long_dqs_rank1_2; /* 0x6E8 */ - vu32 pmacro_ib_ddll_long_dqs_rank1_3; /* 0x6EC */ - vu32 pmacro_ib_ddll_long_dqs_rank1_4; /* 0x6F0 */ - vu32 pmacro_ib_ddll_long_dqs_rank1_5; /* 0x6F4 */ - vu32 rsvd_0x6F8[2]; /* 0x6F8-0x6FC */ - - vu32 pmacro_autocal_cfg0; /* 0x700 */ - vu32 pmacro_autocal_cfg1; /* 0x704 */ - vu32 pmacro_autocal_cfg2; /* 0x708 */ - vu32 rsvd_0x70C[5]; /* 0x70C-0x71C */ - - vu32 pmacro_tx_pwrd_0; /* 0x720 */ - vu32 pmacro_tx_pwrd_1; /* 0x724 */ - vu32 pmacro_tx_pwrd_2; /* 0x728 */ - vu32 pmacro_tx_pwrd_3; /* 0x72C */ - vu32 pmacro_tx_pwrd_4; /* 0x730 */ - vu32 pmacro_tx_pwrd_5; /* 0x734 */ - vu32 rsvd_0x738[2]; /* 0x738-0x73C */ - - vu32 pmacro_tx_sel_clk_src_0; /* 0x740 */ - vu32 pmacro_tx_sel_clk_src_1; /* 0x744 */ - vu32 pmacro_tx_sel_clk_src_2; /* 0x748 */ - vu32 pmacro_tx_sel_clk_src_3; /* 0x74C */ - vu32 pmacro_tx_sel_clk_src_4; /* 0x750 */ - vu32 pmacro_tx_sel_clk_src_5; /* 0x754 */ - vu32 rsvd_0x758[2]; /* 0x758-0x75C */ - - vu32 pmacro_ddll_bypass; /* 0x760 */ - vu32 rsvd_0x764[3]; /* 0x764-0x76C */ - - vu32 pmacro_ddll_pwrd_0; /* 0x770 */ - vu32 pmacro_ddll_pwrd_1; /* 0x774 */ - vu32 pmacro_ddll_pwrd_2; /* 0x778 */ - vu32 rsvd_0x77C[1]; /* 0x77C */ - vu32 pmacro_cmd_ctrl_0; /* 0x780 */ - vu32 pmacro_cmd_ctrl_1; /* 0x784 */ - vu32 pmacro_cmd_ctrl_2; /* 0x788 */ - vu32 rsvd_0x78C[277]; /* 0x78C-0xBDC */ - - vu32 pmacro_ib_vref_dq_0; /* 0xBE0 */ - vu32 pmacro_ib_vref_dq_1; /* 0xBE4 */ - vu32 pmacro_ib_vref_dq_2; /* 0xBE8 */ - vu32 rsvd_0xBEC[1]; /* 0xBEC */ - vu32 pmacro_ib_vref_dqs_0; /* 0xBF0 */ - vu32 pmacro_ib_vref_dqs_1; /* 0xBF4 */ - vu32 pmacro_ib_vref_dqs_2; /* 0xBF8 */ - vu32 rsvd_0xBFC[1]; /* 0xBFC */ - vu32 pmacro_ddll_long_cmd_0; /* 0xC00 */ - vu32 pmacro_ddll_long_cmd_1; /* 0xC04 */ - vu32 pmacro_ddll_long_cmd_2; /* 0xC08 */ - vu32 pmacro_ddll_long_cmd_3; /* 0xC0C */ - vu32 pmacro_ddll_long_cmd_4; /* 0xC10 */ - vu32 pmacro_ddll_long_cmd_5; /* 0xC14 */ - vu32 rsvd_0xC18[2]; /* 0xC18-0xC1C */ - - vu32 pmacro_ddll_short_cmd_0; /* 0xC20 */ - vu32 pmacro_ddll_short_cmd_1; /* 0xC24 */ - vu32 pmacro_ddll_short_cmd_2; /* 0xC28 */ - vu32 rsvd_0xC2C[2]; /* 0xC2C-0xC30 */ - - vu32 pmacro_vttgen_ctrl0; /* 0xC34 */ - vu32 pmacro_vttgen_ctrl1; /* 0xC38 */ - vu32 pmacro_bg_bias_ctrl_0; /* 0xC3C */ - vu32 pmacro_pad_cfg_ctrl; /* 0xC40 */ - vu32 pmacro_zctrl; /* 0xC44 */ - vu32 pmacro_rx_term; /* 0xC48 */ - vu32 pmacro_cmd_tx_drv; /* 0xC4C */ - vu32 pmacro_cmd_pad_rx_ctrl; /* 0xC50 */ - vu32 pmacro_data_pad_rx_ctrl; /* 0xC54 */ - vu32 pmacro_cmd_rx_term_mode; /* 0xC58 */ - vu32 pmacro_data_rx_term_mode; /* 0xC5C */ - vu32 pmacro_cmd_pad_tx_ctrl; /* 0xC60 */ - vu32 pmacro_data_pad_tx_ctrl; /* 0xC64 */ - vu32 pmacro_common_pad_tx_ctrl; /* 0xC68 */ - vu32 rsvd_0xC6C[1]; /* 0xC6C */ - vu32 pmacro_dq_tx_drv; /* 0xC70 */ - vu32 pmacro_ca_tx_drv; /* 0xC74 */ - vu32 pmacro_autocal_cfg_common; /* 0xC78 */ - vu32 rsvd_0xC7C[1]; /* 0xC7C */ - vu32 pmacro_brick_mapping0; /* 0xC80 */ - vu32 pmacro_brick_mapping1; /* 0xC84 */ - vu32 pmacro_brick_mapping2; /* 0xC88 */ - vu32 rsvd_0xC8C[25]; /* 0xC8C-0xCEC */ - - vu32 pmacro_vttgen_ctrl2; /* 0xCF0 */ - vu32 pmacro_ib_rxrt; /* 0xCF4 */ - vu32 pmacro_training_ctrl0; /* 0xCF8 */ - vu32 pmacro_training_ctrl1; /* 0xCFC */ -}; - -#endif /* __SOC_NVIDIA_TEGRA210_EMC_H__ */ diff --git a/ariane/src/hwinit/flow.h b/ariane/src/hwinit/flow.h deleted file mode 100644 index bae8903..0000000 --- a/ariane/src/hwinit/flow.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _TEGRA210_FLOW_H_ -#define _TEGRA210_FLOW_H_ - -#include "types.h" - -struct flow_ctlr { - vu32 halt_cpu_events; /* offset 0x00 */ - vu32 halt_cop_events; /* offset 0x04 */ - vu32 cpu_csr; /* offset 0x08 */ - vu32 cop_csr; /* offset 0x0c */ - vu32 xrq_events; /* offset 0x10 */ - vu32 halt_cpu1_events; /* offset 0x14 */ - vu32 cpu1_csr; /* offset 0x18 */ - vu32 halt_cpu2_events; /* offset 0x1c */ - vu32 cpu2_csr; /* offset 0x20 */ - vu32 halt_cpu3_events; /* offset 0x24 */ - vu32 cpu3_csr; /* offset 0x28 */ - vu32 cluster_control; /* offset 0x2c */ - vu32 halt_cop1_events; /* offset 0x30 */ - vu32 halt_cop1_csr; /* offset 0x34 */ - vu32 cpu_pwr_csr; /* offset 0x38 */ - vu32 mpid; /* offset 0x3c */ - vu32 ram_repair; /* offset 0x40 */ - vu32 flow_dbg_sel; /* offset 0x44 */ - vu32 flow_dbg_cnt0; /* offset 0x48 */ - vu32 flow_dbg_cnt1; /* offset 0x4c */ - vu32 flow_dbg_qual; /* offset 0x50 */ - vu32 flow_ctlr_spare; /* offset 0x54 */ - vu32 reserved; /* offset 0x58 */ - vu32 fc_seq_intercept; /* offset 0x5c */ - vu32 cc4_retention_control; /* offset 0x64 */ - vu32 cc4_fc_status; /* offset 0x68 */ - vu32 cc4_core0_ctrl; /* offset 0x6c */ - vu32 cc4_core1_ctrl; /* offset 0x70 */ - vu32 cc4_core2_ctrl; /* offset 0x74 */ - vu32 cc4_core3_ctrl; /* offset 0x78 */ - vu32 core0_idle_counter; /* offset 0x7c */ - vu32 core1_idle_counter; /* offset 0x80 */ - vu32 core2_idle_counter; /* offset 0x84 */ - vu32 core3_idle_counter; /* offset 0x88 */ - vu32 cc4_hvc_retry; /* offset 0x8c */ - vu32 l2flush_timeout_cntr; /* offset 0x90 */ - vu32 l2flush_control; /* offset 0x94 */ - vu32 bpmp_cluster_control; /* offset 0x98 */ -}; - -enum { - FLOW_MODE_SHIFT = 29, - FLOW_MODE_MASK = 0x7 << FLOW_MODE_SHIFT, - - FLOW_MODE_NONE = 0 << FLOW_MODE_SHIFT, - FLOW_MODE_RUN_AND_INT = 1 << FLOW_MODE_SHIFT, - FLOW_MODE_WAITEVENT = 2 << FLOW_MODE_SHIFT, - FLOW_MODE_WAITEVENT_AND_INT = 3 << FLOW_MODE_SHIFT, - FLOW_MODE_STOP_UNTIL_IRQ = 4 << FLOW_MODE_SHIFT, - FLOW_MODE_STOP_UNTIL_IRQ_AND_INT = 5 << FLOW_MODE_SHIFT, - FLOW_MODE_STOP_UNTIL_EVENT_AND_IRQ = 6 << FLOW_MODE_SHIFT, -}; - -/* HALT_COP_EVENTS_0, 0x04 */ -enum { - FLOW_EVENT_GIC_FIQ = 1 << 8, - FLOW_EVENT_GIC_IRQ = 1 << 9, - FLOW_EVENT_LIC_FIQ = 1 << 10, - FLOW_EVENT_LIC_IRQ = 1 << 11, - FLOW_EVENT_IBF = 1 << 12, - FLOW_EVENT_IBE = 1 << 13, - FLOW_EVENT_OBF = 1 << 14, - FLOW_EVENT_OBE = 1 << 15, - FLOW_EVENT_XRQ_A = 1 << 16, - FLOW_EVENT_XRQ_B = 1 << 17, - FLOW_EVENT_XRQ_C = 1 << 18, - FLOW_EVENT_XRQ_D = 1 << 19, - FLOW_EVENT_SMP30 = 1 << 20, - FLOW_EVENT_SMP31 = 1 << 21, - FLOW_EVENT_X_RDY = 1 << 22, - FLOW_EVENT_SEC = 1 << 23, - FLOW_EVENT_MSEC = 1 << 24, - FLOW_EVENT_USEC = 1 << 25, - FLOW_EVENT_X32K = 1 << 26, - FLOW_EVENT_SCLK = 1 << 27, - FLOW_EVENT_JTAG = 1 << 28 -}; - -#endif /* _TEGRA210_FLOW_H_ */ diff --git a/ariane/src/hwinit/fuse.c b/ariane/src/hwinit/fuse.c deleted file mode 100644 index 356eb89..0000000 --- a/ariane/src/hwinit/fuse.c +++ /dev/null @@ -1,28 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "fuse.h" -#include "t210.h" - -void fuse_disable_program() -{ - FUSE(FUSE_DISABLEREGPROGRAM) = 1; -} - -u32 fuse_read_odm(u32 idx) -{ - return FUSE(FUSE_RESERVED_ODMX(idx)); -} diff --git a/ariane/src/hwinit/fuse.h b/ariane/src/hwinit/fuse.h deleted file mode 100644 index 2732eb4..0000000 --- a/ariane/src/hwinit/fuse.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _FUSE_H_ -#define _FUSE_H_ - -#include "types.h" - -/*! Fuse registers. */ -#define FUSE_CTRL 0x0 -#define FUSE_ADDR 0x4 -#define FUSE_RDATA 0x8 -#define FUSE_WDATA 0xC -#define FUSE_TIME_RD1 0x10 -#define FUSE_TIME_RD2 0x14 -#define FUSE_TIME_PGM1 0x18 -#define FUSE_TIME_PGM2 0x1C -#define FUSE_PRIV2INTFC 0x20 -#define FUSE_FUSEBYPASS 0x24 -#define FUSE_PRIVATEKEYDISABLE 0x28 -#define FUSE_DISABLEREGPROGRAM 0x2C -#define FUSE_WRITE_ACCESS_SW 0x30 -#define FUSE_PWR_GOOD_SW 0x34 - -/*! Fuse cache registers. */ -#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) - -void fuse_disable_program(); -u32 fuse_read_odm(u32 idx); - -#endif diff --git a/ariane/src/hwinit/gpio.c b/ariane/src/hwinit/gpio.c deleted file mode 100644 index 596af03..0000000 --- a/ariane/src/hwinit/gpio.c +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "gpio.h" -#include "t210.h" - -static const u16 _gpio_cnf[31] = { - 0x000, 0x004, 0x008, 0x00C, - 0x100, 0x104, 0x108, 0x10C, - 0x200, 0x204, 0x208, 0x20C, - 0x300, 0x304, 0x308, 0x30C, - 0x400, 0x404, 0x408, 0x40C, - 0x500, 0x504, 0x508, 0x50C, - 0x600, 0x604, 0x608, 0x60C, - 0x700, 0x704, 0x708 -}; - -static const u16 _gpio_oe[31] = { - 0x010, 0x014, 0x018, 0x01C, - 0x110, 0x114, 0x118, 0x11C, - 0x210, 0x214, 0x218, 0x21C, - 0x310, 0x314, 0x318, 0x31C, - 0x410, 0x414, 0x418, 0x41C, - 0x510, 0x514, 0x518, 0x51C, - 0x610, 0x614, 0x618, 0x61C, - 0x710, 0x714, 0x718 -}; - -static const u16 _gpio_out[31] = { - 0x020, 0x024, 0x028, 0x02C, - 0x120, 0x124, 0x128, 0x12C, - 0x220, 0x224, 0x228, 0x22C, - 0x320, 0x324, 0x328, 0x32C, - 0x420, 0x424, 0x428, 0x42C, - 0x520, 0x524, 0x528, 0x52C, - 0x620, 0x624, 0x628, 0x62C, - 0x720, 0x724, 0x728 -}; - -static const u16 _gpio_in[31] = { - 0x030, 0x034, 0x038, 0x03C, - 0x130, 0x134, 0x138, 0x13C, - 0x230, 0x234, 0x238, 0x23C, - 0x330, 0x334, 0x338, 0x33C, - 0x430, 0x434, 0x438, 0x43C, - 0x530, 0x534, 0x538, 0x53C, - 0x630, 0x634, 0x638, 0x63C, - 0x730, 0x734, 0x738 -}; - -void gpio_config(u32 port, u32 pins, int mode) -{ - if (mode) - GPIO(_gpio_cnf[port]) |= pins; - else - GPIO(_gpio_cnf[port]) &= ~pins; - (void)GPIO(_gpio_cnf[port]); -} - -void gpio_output_enable(u32 port, u32 pins, int enable) -{ - if (enable) - GPIO(_gpio_oe[port]) |= pins; - else - GPIO(_gpio_oe[port]) &= ~pins; - (void)GPIO(_gpio_oe[port]); -} - -void gpio_write(u32 port, u32 pins, int high) -{ - if (high) - GPIO(_gpio_out[port]) |= pins; - else - GPIO(_gpio_out[port]) &= ~pins; - (void)GPIO(_gpio_out[port]); -} - -int gpio_read(u32 port, u32 pins) -{ - return GPIO(_gpio_in[port]) & pins ? 1 : 0; -} diff --git a/ariane/src/hwinit/hwinit.c b/ariane/src/hwinit/hwinit.c deleted file mode 100644 index 0ed01bf..0000000 --- a/ariane/src/hwinit/hwinit.c +++ /dev/null @@ -1,278 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "clock.h" -#include "uart.h" -#include "i2c.h" -#include "sdram.h" -#include "di.h" -#include "mc.h" -#include "t210.h" -#include "pmc.h" -#include "gpio.h" -#include "pinmux.h" -#include "max77620.h" -#include "max7762x.h" -#include "fuse.h" -#include "timer.h" -#include "carveout.h" -#include - -void config_oscillators() -{ - CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; - SYSCTR0(SYSCTR0_CNTFID0) = 19200000; - TMR(TMR_US_CFG_OFFS) = 0x45F; - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; - PMC(APBDEV_PMC_OSC_EDPD_OVER) |= 0x400000; - PMC(APBDEV_PMC_CNTRL2) |= 0x1000; - PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; - PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; - CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; -} - -void config_gpios() -{ - pinmux_set_config(PINMUX_UART2_TX_INDEX, 0); - pinmux_set_config(PINMUX_UART3_TX_INDEX, 0); - pinmux_set_config(PINMUX_GPIO_PE6_INDEX, PINMUX_INPUT_ENABLE); - pinmux_set_config(PINMUX_GPIO_PH6_INDEX, PINMUX_INPUT_ENABLE); - - gpio_config(GPIO_BY_NAME(UART2_TX), GPIO_MODE_GPIO); - gpio_config(GPIO_BY_NAME(UART3_TX), GPIO_MODE_GPIO); - gpio_config(GPIO_DECOMPOSE(GPIO_E6_INDEX), GPIO_MODE_GPIO); - gpio_config(GPIO_DECOMPOSE(GPIO_H6_INDEX), GPIO_MODE_GPIO); - gpio_output_enable(GPIO_BY_NAME(UART2_TX), GPIO_OUTPUT_DISABLE); - gpio_output_enable(GPIO_BY_NAME(UART3_TX), GPIO_OUTPUT_DISABLE); - gpio_output_enable(GPIO_DECOMPOSE(GPIO_E6_INDEX), GPIO_OUTPUT_DISABLE); - gpio_output_enable(GPIO_DECOMPOSE(GPIO_H6_INDEX), GPIO_OUTPUT_DISABLE); - - pinmux_config_i2c(I2C_1); - pinmux_config_i2c(I2C_5); - - //unused UART_A - PINMUX_SET_UNUSED_BY_NAME(UART1_RX); - PINMUX_SET_UNUSED_BY_NAME(UART1_TX); - PINMUX_SET_UNUSED_BY_NAME(UART1_CTS); - PINMUX_SET_UNUSED_BY_NAME(UART1_RTS); - - //Configure volume up/down as inputs. - gpio_config(GPIO_BY_NAME(BUTTON_VOL_UP), GPIO_MODE_GPIO); - gpio_config(GPIO_BY_NAME(BUTTON_VOL_DOWN), GPIO_MODE_GPIO); - gpio_output_enable(GPIO_BY_NAME(BUTTON_VOL_UP), GPIO_OUTPUT_DISABLE); - gpio_output_enable(GPIO_BY_NAME(BUTTON_VOL_DOWN), GPIO_OUTPUT_DISABLE); - - //Configure SD card detect pin - pinmux_set_config(PINMUX_GPIO_Z1, PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | PINMUX_GPIO_PZ1_FUNC_SDMMC1); - gpio_config(GPIO_DECOMPOSE(GPIO_Z1_INDEX), GPIO_MODE_GPIO); - gpio_output_enable(GPIO_DECOMPOSE(GPIO_Z1_INDEX), GPIO_OUTPUT_DISABLE); - APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; //use GPIO for all SDMMC - - //Configure SD power enable pin (powered off by default) - pinmux_set_config(PINMUX_DMIC3_CLK_INDEX, PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | PINMUX_DMIC3_CLK_FUNC_I2S5A); //not sure about the altfunc here - gpio_config(GPIO_BY_NAME(DMIC3_CLK), GPIO_MODE_GPIO); - gpio_write(GPIO_BY_NAME(DMIC3_CLK), GPIO_LOW); - gpio_output_enable(GPIO_BY_NAME(DMIC3_CLK), GPIO_OUTPUT_ENABLE); -} - -void config_pmc_scratch() -{ - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; - PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; - PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10; -} - -void mbist_workaround() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = CLK_Y_APE; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = CLK_X_VIC; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = CLK_L_DISP1 | CLK_L_HOST1X; - usleep(2); - - I2S(0x0A0) |= 0x400; - I2S(0x088) &= 0xFFFFFFFE; - I2S(0x1A0) |= 0x400; - I2S(0x188) &= 0xFFFFFFFE; - I2S(0x2A0) |= 0x400; - I2S(0x288) &= 0xFFFFFFFE; - I2S(0x3A0) |= 0x400; - I2S(0x388) &= 0xFFFFFFFE; - I2S(0x4A0) |= 0x400; - I2S(0x488) &= 0xFFFFFFFE; - DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; - VIC(0x8C) = 0xFFFFFFFF; - usleep(2); - - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = CLK_Y_APE; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = CLK_L_DISP1 | CLK_L_HOST1X; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = CLK_X_VIC; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = CLK_H_PMC | CLK_H_FUSE; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = CLK_L_RTC | CLK_L_TMR | CLK_L_GPIO | CLK_L_USBD | CLK_L_CACHE2; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = CLK_U_CSITE | CLK_U_IRAMA | CLK_U_IRAMB | CLK_U_IRAMC | CLK_U_IRAMD | CLK_U_CRAM2; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = CLK_V_MSELECT | CLK_V_APB2APE | CLK_V_SPDIF_DOUBLER | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = CLK_W_PCIERX0 | CLK_W_PCIERX1 | CLK_W_PCIERX2 | CLK_W_PCIERX3 | CLK_W_PCIERX4 | CLK_W_PCIERX5 | CLK_W_ENTROPY | CLK_W_MC1; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = CLK_X_MC_CAPA | CLK_X_MC_CBPA | CLK_X_MC_CPU | CLK_X_MC_BBC | CLK_X_GPU | CLK_X_DPGAPB | CLK_X_PLLG_REF; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = CLK_Y_MC_CDPA | CLK_Y_MC_CCPA; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; -} - -void config_hw() -{ - clock_enable_fuse(1); - - - // This memset needs to happen here, else TZRAM will behave weirdly later on. - memset((void *)TZRAM_BASE, 0, 0x10000); - PMC(APBDEV_PMC_CRYPTO_OP) = 0; - SE(0x010) = 0x1F; - - // Clear the boot reason to avoid problems later - PMC(APBDEV_PMC_SCRATCH200) = 0x0; - PMC(0x1B4) = 0x0; - APB_MISC(0x08) = (APB_MISC(0x08) & 0xF0) | (7 << 10); - - SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. - PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; - - - mbist_workaround(); - clock_enable_se(); - - //Enable fuse clock. - clock_enable_fuse(1); - //Disable fuse programming. - fuse_disable_program(); - - mc_enable(); - - config_oscillators(); - APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; - config_gpios(); - - -#ifdef DEBUG_UART_PORT - clock_enable_uart(DEBUG_UART_PORT); - uart_init(DEBUG_UART_PORT, 115200); - pinmux_config_uart(DEBUG_UART_PORT); -#endif - - clock_enable_cl_dvfs(); - - clock_enable_i2c(I2C_1); - clock_enable_i2c(I2C_5); - - // Clock TZRAM - clock_enable_se(); - static const clock_t clock_unk = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, 0, 30, 0, 0 }; - clock_enable(&clock_unk); - - i2c_init(I2C_1); - i2c_init(I2C_5); - - max77620_send_byte(MAX77620_REG_CNFGBBC, 0x40); - max77620_send_byte(MAX77620_REG_ONOFFCNFG1, 0x78); - - max77620_send_byte(MAX77620_REG_FPS_CFG0, 0x38); - max77620_send_byte(MAX77620_REG_FPS_CFG1, 0x3A); - max77620_send_byte(MAX77620_REG_FPS_CFG2, 0x38); - max77620_regulator_config_fps(REGULATOR_LDO4); - max77620_regulator_config_fps(REGULATOR_LDO8); - max77620_regulator_config_fps(REGULATOR_SD0); - max77620_regulator_config_fps(REGULATOR_SD1); - max77620_regulator_config_fps(REGULATOR_SD3); - max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); //1.125V - - //Set SDMMC1 IO clamps to default value before changing voltage - PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); - - //Start up the SDMMC1 IO voltage regulator - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - max77620_regulator_enable(REGULATOR_LDO2, 1); - - //Remove isolation from SDMMC1 and core domain - PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12); - - - - // Fix CPU/GPU after a L4T warmboot. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); - - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); - i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, - MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | - MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - - - config_pmc_scratch(); - - //CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). - - - //mc_config_carveout(); - { - const struct sdram_params* sdram_params = sdram_get_params(); - sdram_init(sdram_params); - //TODO: test this with LP0 wakeup. - //sdram_lp0_save_params(sdram_params); - } - - /* - * IMPORTANT: - * DO NOT INITIALIZE ANY CARVEOUT BEFORE TZ. - * - * Trust Zone needs to be initialized after the DRAM initialization - * because carveout registers are programmed during DRAM init. - * cbmem_initialize() is dependent on the Trust Zone region - * initialization because CBMEM lives right below the Trust Zone which - * needs to be properly identified. - */ - trustzone_region_init(); - - // Now do various other carveouts - gpu_region_init(); - nvdec_region_init(); - tsec_region_init(); - vpr_region_init(); - print_carveouts(); -} diff --git a/ariane/src/hwinit/hwinit.h b/ariane/src/hwinit/hwinit.h deleted file mode 100644 index c6390ba..0000000 --- a/ariane/src/hwinit/hwinit.h +++ /dev/null @@ -1,26 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - -#ifndef _HWINIT_H_ -#define _HWINIT_H_ - -void config_hw(); -void mbist_workaround(); -void config_pmc_scratch(); -void config_gpios(); -void config_oscillators(); -#endif diff --git a/ariane/src/hwinit/i2c.c b/ariane/src/hwinit/i2c.c deleted file mode 100644 index aa62321..0000000 --- a/ariane/src/hwinit/i2c.c +++ /dev/null @@ -1,132 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include - -#include "i2c.h" -#include "timer.h" - -static u32 i2c_addrs[] = { 0x7000C000, 0x7000C400, 0x7000C500, 0x7000C700, 0x7000D000, 0x7000D100 }; - -static void _i2c_wait(vu32 *base) -{ - base[0x23] = 0x25; - for (u32 i = 0; i < 20; i++) - { - usleep(1); - if (!(base[0x23] & 1)) - break; - } -} - -static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) -{ - if (size > 4) - return 0; - - u32 tmp = 0; - memcpy(&tmp, buf, size); - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[1] = x << 1; //Set x (send mode). - base[3] = tmp; //Set value. - base[0] = (2 * size - 2) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. - - base[0] = (base[0] & 0xFFFFFDFF) | 0x200; - while (base[7] & 0x100) - ; - - if (base[7] << 28) - return 0; - - return 1; -} - -static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) -{ - if (size > 4) - return 0; - - vu32 *base = (vu32 *)i2c_addrs[idx]; - base[1] = (x << 1) | 1; //Set x (recv mode). - base[0] = (2 * size - 2) | 0x2840; //Set size and recv mode. - _i2c_wait(base); //Kick transaction. - - base[0] = (base[0] & 0xFFFFFDFF) | 0x200; - while (base[7] & 0x100) - ; - - if (base[7] << 28) - return 0; - - u32 tmp = base[3]; //Get value. - memcpy(buf, &tmp, size); - - return 1; -} - -void i2c_init(u32 idx) -{ - vu32 *base = (vu32 *)i2c_addrs[idx]; - - base[0x1B] = 0x50001; - base[0x21] = 0x90003; - _i2c_wait(base); - - for (u32 i = 0; i < 10; i++) - { - msleep(20); - if (base[0x1A] & 0x800) - break; - } - - (void)base[0x22]; - base[0x1A] = base[0x1A]; -} - -u32 i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) -{ - u8 tmp[4]; - - if (size > 3) - return 0; - - tmp[0] = y; - memcpy(tmp + 1, buf, size); - - return _i2c_send_pkt(idx, x, tmp, size + 1); -} - -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) -{ - int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); - if (res) - res = _i2c_recv_pkt(idx, buf, size, x); - return res; -} - -u32 i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) -{ - return i2c_send_buf_small(idx, x, y, &b, 1); -} - -u8 i2c_recv_byte(u32 idx, u32 x, u32 y) -{ - u8 tmp; - i2c_recv_buf_small(&tmp, 1, idx, x, y); - return tmp; -} diff --git a/ariane/src/hwinit/i2c.h b/ariane/src/hwinit/i2c.h deleted file mode 100644 index 84a4240..0000000 --- a/ariane/src/hwinit/i2c.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _I2C_H_ -#define _I2C_H_ - -#include "types.h" - -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - -void i2c_init(u32 idx); -u32 i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); -int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); -u32 i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); -u8 i2c_recv_byte(u32 idx, u32 x, u32 y); - -#endif diff --git a/ariane/src/hwinit/kfuse.c b/ariane/src/hwinit/kfuse.c deleted file mode 100644 index 03d95bb..0000000 --- a/ariane/src/hwinit/kfuse.c +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "kfuse.h" -#include "clock.h" -#include "t210.h" - -int kfuse_read(u32 *buf) -{ - int res = 0; - - clock_enable_kfuse(); - - while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) - ; - - if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) - goto out; - - KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; - for (int i = 0; i < KFUSE_NUM_WORDS; i++) - buf[i] = KFUSE(KFUSE_KEYS); - - res = 1; - -out:; - clock_disable_kfuse(); - return res; -} diff --git a/ariane/src/hwinit/kfuse.h b/ariane/src/hwinit/kfuse.h deleted file mode 100644 index 4aa1b09..0000000 --- a/ariane/src/hwinit/kfuse.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _KFUSE_H_ -#define _KFUSE_H_ - -#include "types.h" - -#define KFUSE_STATE_SOFTRESET (1<<31) -#define KFUSE_STATE_STOP (1<<25) -#define KFUSE_STATE_RESTART (1<<24) -#define KFUSE_STATE_CRCPASS (1<<17) -#define KFUSE_STATE_DONE (1<<16) -#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 -#define KFUSE_STATE_ERRBLOCK_SHIFT 8 -#define KFUSE_STATE_CURBLOCK_MASK 0x3F - -#define KFUSE_KEYADDR_AUTOINC (1<<16) - -#define KFUSE_STATE 0x80 -#define KFUSE_KEYADDR 0x88 -#define KFUSE_KEYS 0x8C - -#define KFUSE_NUM_WORDS 144 - -int kfuse_read(u32 *buf); - -#endif diff --git a/ariane/src/hwinit/max77620.h b/ariane/src/hwinit/max77620.h deleted file mode 100644 index 77b2c4b..0000000 --- a/ariane/src/hwinit/max77620.h +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Defining registers address and its bit definitions of MAX77620 and MAX20024 - * - * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#ifndef _MFD_MAX77620_H_ -#define _MFD_MAX77620_H_ - -#define MAX77620_I2C_ADDR 0x3C - -/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ -#define MAX77620_REG_CNFGGLBL1 0x00 -#define MAX77620_REG_CNFGGLBL2 0x01 -#define MAX77620_REG_CNFGGLBL3 0x02 -#define MAX77620_REG_CNFG1_32K 0x03 -#define MAX77620_REG_CNFGBBC 0x04 -#define MAX77620_REG_IRQTOP 0x05 -#define MAX77620_REG_INTLBT 0x06 -#define MAX77620_REG_IRQSD 0x07 -#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 -#define MAX77620_REG_IRQ_LVL2_L8 0x09 -#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A -#define MAX77620_REG_ONOFFIRQ 0x0B -#define MAX77620_REG_NVERC 0x0C -#define MAX77620_REG_IRQTOPM 0x0D -#define MAX77620_REG_INTENLBT 0x0E -#define MAX77620_REG_IRQMASKSD 0x0F -#define MAX77620_REG_IRQ_MSK_L0_7 0x10 -#define MAX77620_REG_IRQ_MSK_L8 0x11 -#define MAX77620_REG_ONOFFIRQM 0x12 -#define MAX77620_REG_STATLBT 0x13 -#define MAX77620_REG_STATSD 0x14 -#define MAX77620_REG_ONOFFSTAT 0x15 - -/* SD and LDO Registers */ -#define MAX77620_REG_SD0 0x16 -#define MAX77620_REG_SD1 0x17 -#define MAX77620_REG_SD2 0x18 -#define MAX77620_REG_SD3 0x19 -#define MAX77620_REG_SD4 0x1A -#define MAX77620_REG_DVSSD0 0x1B -#define MAX77620_REG_DVSSD1 0x1C -#define MAX77620_REG_SD0_CFG 0x1D -#define MAX77620_REG_SD1_CFG 0x1E -#define MAX77620_REG_SD2_CFG 0x1F -#define MAX77620_REG_SD3_CFG 0x20 -#define MAX77620_REG_SD4_CFG 0x21 -#define MAX77620_REG_SD_CFG2 0x22 -#define MAX77620_REG_LDO0_CFG 0x23 -#define MAX77620_REG_LDO0_CFG2 0x24 -#define MAX77620_REG_LDO1_CFG 0x25 -#define MAX77620_REG_LDO1_CFG2 0x26 -#define MAX77620_REG_LDO2_CFG 0x27 -#define MAX77620_REG_LDO2_CFG2 0x28 -#define MAX77620_REG_LDO3_CFG 0x29 -#define MAX77620_REG_LDO3_CFG2 0x2A -#define MAX77620_REG_LDO4_CFG 0x2B -#define MAX77620_REG_LDO4_CFG2 0x2C -#define MAX77620_REG_LDO5_CFG 0x2D -#define MAX77620_REG_LDO5_CFG2 0x2E -#define MAX77620_REG_LDO6_CFG 0x2F -#define MAX77620_REG_LDO6_CFG2 0x30 -#define MAX77620_REG_LDO7_CFG 0x31 -#define MAX77620_REG_LDO7_CFG2 0x32 -#define MAX77620_REG_LDO8_CFG 0x33 -#define MAX77620_REG_LDO8_CFG2 0x34 -#define MAX77620_REG_LDO_CFG3 0x35 - -#define MAX77620_LDO_SLEW_RATE_MASK 0x1 - -/* LDO Configuration 3 */ -#define MAX77620_TRACK4_MASK (1 << 5) -#define MAX77620_TRACK4_SHIFT 5 - -/* Voltage */ -#define MAX77620_SDX_VOLT_MASK 0xFF -#define MAX77620_SD0_VOLT_MASK 0x3F -#define MAX77620_SD1_VOLT_MASK 0x7F -#define MAX77620_LDO_VOLT_MASK 0x3F - -#define MAX77620_REG_GPIO0 0x36 -#define MAX77620_REG_GPIO1 0x37 -#define MAX77620_REG_GPIO2 0x38 -#define MAX77620_REG_GPIO3 0x39 -#define MAX77620_REG_GPIO4 0x3A -#define MAX77620_REG_GPIO5 0x3B -#define MAX77620_REG_GPIO6 0x3C -#define MAX77620_REG_GPIO7 0x3D -#define MAX77620_REG_PUE_GPIO 0x3E -#define MAX77620_REG_PDE_GPIO 0x3F -#define MAX77620_REG_AME_GPIO 0x40 -#define MAX77620_REG_ONOFFCNFG1 0x41 -#define MAX77620_REG_ONOFFCNFG2 0x42 - -/* FPS Registers */ -#define MAX77620_REG_FPS_CFG0 0x43 -#define MAX77620_REG_FPS_CFG1 0x44 -#define MAX77620_REG_FPS_CFG2 0x45 -#define MAX77620_REG_FPS_LDO0 0x46 -#define MAX77620_REG_FPS_LDO1 0x47 -#define MAX77620_REG_FPS_LDO2 0x48 -#define MAX77620_REG_FPS_LDO3 0x49 -#define MAX77620_REG_FPS_LDO4 0x4A -#define MAX77620_REG_FPS_LDO5 0x4B -#define MAX77620_REG_FPS_LDO6 0x4C -#define MAX77620_REG_FPS_LDO7 0x4D -#define MAX77620_REG_FPS_LDO8 0x4E -#define MAX77620_REG_FPS_SD0 0x4F -#define MAX77620_REG_FPS_SD1 0x50 -#define MAX77620_REG_FPS_SD2 0x51 -#define MAX77620_REG_FPS_SD3 0x52 -#define MAX77620_REG_FPS_SD4 0x53 -#define MAX77620_REG_FPS_NONE 0 - -#define MAX77620_FPS_SRC_MASK 0xC0 -#define MAX77620_FPS_SRC_SHIFT 6 -#define MAX77620_FPS_PU_PERIOD_MASK 0x38 -#define MAX77620_FPS_PU_PERIOD_SHIFT 3 -#define MAX77620_FPS_PD_PERIOD_MASK 0x07 -#define MAX77620_FPS_PD_PERIOD_SHIFT 0 -#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 -#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 -#define MAX77620_FPS_EN_SRC_MASK 0x06 -#define MAX77620_FPS_EN_SRC_SHIFT 1 -#define MAX77620_FPS_ENFPS_SW_MASK 0x01 -#define MAX77620_FPS_ENFPS_SW 0x01 - -/* Minimum and maximum FPS period time (in microseconds) are - * different for MAX77620 and Max20024. - */ -#define MAX77620_FPS_PERIOD_MIN_US 40 -#define MAX20024_FPS_PERIOD_MIN_US 20 - -#define MAX77620_FPS_PERIOD_MAX_US 2560 -#define MAX20024_FPS_PERIOD_MAX_US 5120 - -#define MAX77620_REG_FPS_GPIO1 0x54 -#define MAX77620_REG_FPS_GPIO2 0x55 -#define MAX77620_REG_FPS_GPIO3 0x56 -#define MAX77620_REG_FPS_RSO 0x57 -#define MAX77620_REG_CID0 0x58 -#define MAX77620_REG_CID1 0x59 -#define MAX77620_REG_CID2 0x5A -#define MAX77620_REG_CID3 0x5B -#define MAX77620_REG_CID4 0x5C -#define MAX77620_REG_CID5 0x5D - -#define MAX77620_REG_DVSSD4 0x5E -#define MAX20024_REG_MAX_ADD 0x70 - -#define MAX77620_CID_DIDM_MASK 0xF0 -#define MAX77620_CID_DIDM_SHIFT 4 - -/* CNCG2SD */ -#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) -#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) - -/* Device Identification Metal */ -#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) -/* Device Indentification OTP */ -#define MAX77620_CID5_DIDO(n) ((n) & 0xF) - -/* SD CNFG1 */ -#define MAX77620_SD_SR_MASK 0xC0 -#define MAX77620_SD_SR_SHIFT 6 -#define MAX77620_SD_POWER_MODE_MASK 0x30 -#define MAX77620_SD_POWER_MODE_SHIFT 4 -#define MAX77620_SD_CFG1_ADE_MASK (1 << 3) -#define MAX77620_SD_CFG1_ADE_DISABLE 0 -#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) -#define MAX77620_SD_FPWM_MASK 0x04 -#define MAX77620_SD_FPWM_SHIFT 2 -#define MAX77620_SD_FSRADE_MASK 0x01 -#define MAX77620_SD_FSRADE_SHIFT 0 -#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) -#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 -#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) -#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) -#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) -#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 -#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) - -/* LDO_CNFG2 */ -#define MAX77620_LDO_POWER_MODE_MASK 0xC0 -#define MAX77620_LDO_POWER_MODE_SHIFT 6 -#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) -#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE 0 -#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) -#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) -#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) -#define MAX77620_LDO_CFG2_SS_SLOW 0 - -#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) -#define MAX77620_IRQ_TOP_SD_MASK (1 << 6) -#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) -#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) -#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) -#define MAX77620_IRQ_TOP_32K_MASK (1 << 2) -#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) - -#define MAX77620_IRQ_LBM_MASK (1 << 3) -#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) -#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) - -#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0 -#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0 -#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0 -#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) -#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) -#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) -#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) -#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) -#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) -#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) -#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) - -#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) -#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) -#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) -#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) -#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) -#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) -#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) -#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) - -#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) - -#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) -#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 -#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 -#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) -#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) -#define MAX20024_ONOFFCNFG1_CLRSE 0x18 - -#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) -#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) -#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) -#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) -#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) - -#define MAX77620_GLBLM_MASK (1 << 0) - -#define MAX77620_WDTC_MASK 0x3 -#define MAX77620_WDTOFFC (1 << 4) -#define MAX77620_WDTSLPC (1 << 3) -#define MAX77620_WDTEN (1 << 2) - -#define MAX77620_TWD_MASK 0x3 -#define MAX77620_TWD_2s 0x0 -#define MAX77620_TWD_16s 0x1 -#define MAX77620_TWD_64s 0x2 -#define MAX77620_TWD_128s 0x3 - -#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) -#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) -#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4) -#define MAX77620_CNFGGLBL1_LBDAC 0x0E -#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1) -#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) - -/* CNFG BBC registers */ -#define MAX77620_CNFGBBC_ENABLE (1 << 0) -#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 -#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 -#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 -#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 -#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) -#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 -#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 - -#define MAX77620_FPS_COUNT 3 - -/* Interrupts */ -enum { - MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ - MAX77620_IRQ_TOP_SD, /* SD power fail */ - MAX77620_IRQ_TOP_LDO, /* LDO power fail */ - MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ - MAX77620_IRQ_TOP_RTC, /* RTC */ - MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ - MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ - MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ - MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ - MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ -}; - -/* GPIOs */ -enum { - MAX77620_GPIO0, - MAX77620_GPIO1, - MAX77620_GPIO2, - MAX77620_GPIO3, - MAX77620_GPIO4, - MAX77620_GPIO5, - MAX77620_GPIO6, - MAX77620_GPIO7, - MAX77620_GPIO_NR, -}; - -/* FPS Source */ -enum max77620_fps_src { - MAX77620_FPS_SRC_0, - MAX77620_FPS_SRC_1, - MAX77620_FPS_SRC_2, - MAX77620_FPS_SRC_NONE, - MAX77620_FPS_SRC_DEF, -}; - -enum max77620_chip_id { - MAX77620, - MAX20024, -}; - -#endif /* _MFD_MAX77620_H_ */ diff --git a/ariane/src/hwinit/max7762x.c b/ariane/src/hwinit/max7762x.c deleted file mode 100644 index 2379b94..0000000 --- a/ariane/src/hwinit/max7762x.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "max7762x.h" -#include "max77620.h" -#include "i2c.h" -#include "timer.h" -#include "lib/printk.h" - -#define REGULATOR_SD 0 -#define REGULATOR_LDO 1 - -typedef struct _max77620_regulator_t -{ - u8 type; - const char *name; - u8 reg_sd; - u32 mv_step; - u32 mv_min; - u32 mv_default; - u32 mv_max; - u8 volt_addr; - u8 cfg_addr; - u8 volt_mask; - u8 enable_mask; - u8 enable_shift; - u8 status_mask; - - u8 fps_addr; - u8 fps_src; - u8 pd_period; - u8 pu_period; -} max77620_regulator_t; - -static const max77620_regulator_t _pmic_regulators[] = { - { REGULATOR_SD, "sd0", MAX77620_REG_SD0, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, MAX77620_FPS_SRC_1, 7, 1 }, - { REGULATOR_SD, "sd1", MAX77620_REG_SD1, 12500, 600000, 1100000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, MAX77620_FPS_SRC_0, 1, 5 }, - { REGULATOR_SD, "sd2", MAX77620_REG_SD2, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, MAX77620_FPS_SRC_1, 5, 2 }, - { REGULATOR_SD, "sd3", MAX77620_REG_SD3, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, MAX77620_FPS_SRC_0, 3, 3 }, - { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, MAX77620_FPS_SRC_0, 7, 1 }, - { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, MAX77620_FPS_SRC_NONE, 7, 0 }, - { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, MAX77620_FPS_SRC_1, 4, 3 }, - { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, MAX77620_FPS_SRC_NONE, 7, 0 } -}; - -u32 max77620_send_byte(u32 regAddr, u8 dataByte) -{ - return i2c_send_byte(I2C_5, 0x3C, regAddr, dataByte); -} -u8 max77620_recv_byte(u32 regAddr) -{ - return i2c_recv_byte(I2C_5, 0x3C, regAddr); -} - -u32 max7762x_send_byte(u32 devAddr, u32 regAddr, u8 dataByte) -{ - return i2c_send_byte(I2C_5, devAddr, regAddr, dataByte); -} -u8 max7762x_recv_byte(u32 devAddr, u32 regAddr) -{ - return i2c_recv_byte(I2C_5, devAddr, regAddr); -} - -int max77620_regulator_get_status(u32 id) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - if (reg->type == REGULATOR_SD) - return (max77620_recv_byte(MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; - else - return (max77620_recv_byte(reg->cfg_addr) & 8) ? 1 : 0; -} - -int max77620_regulator_config_fps(u32 id) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - max77620_send_byte(reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period)); - - return 1; -} - -int max77620_regulator_set_voltage(u32 id, u32 mv) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - if (mv < reg->mv_min || mv > reg->mv_max) - { - dbg_print("max77620_regulator_set_voltage: wanted voltage %u for regulator %u outside bounds (min: %u max: %u), NOT SETTING!\n", - mv, id, reg->mv_min, reg->mv_max); - return 0; - } - - u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; - u8 val = max77620_recv_byte(reg->volt_addr); - val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - max77620_send_byte(reg->volt_addr, val); - usleep(1000); - - return 1; -} - -int max77620_regulator_enable(u32 id, int enable) -{ - if (id > REGULATOR_MAX) - return 0; - - const max77620_regulator_t *reg = &_pmic_regulators[id]; - - u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr; - u8 val = max77620_recv_byte(addr); - if (enable) - val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask); - else - val &= ~reg->enable_mask; - - max77620_send_byte(addr, val); - usleep(1000); - - return 1; -} - -void max77620_config_default() -{ - for (u32 i = 1; i <= REGULATOR_MAX; i++) - { - max77620_recv_byte(MAX77620_REG_CID4); - max77620_regulator_config_fps(i); - max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default); - if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) - max77620_regulator_enable(i, 1); - } - max77620_send_byte(MAX77620_REG_SD_CFG2, 4); -} - -void max77620_low_battery_monitor_config() -{ - i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_CNFGGLBL1, MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N); -} diff --git a/ariane/src/hwinit/mc.c b/ariane/src/hwinit/mc.c deleted file mode 100644 index ac6b2db..0000000 --- a/ariane/src/hwinit/mc.c +++ /dev/null @@ -1,149 +0,0 @@ -#include "mc.h" -#include "t210.h" -#include "mc_t210.h" -#include "clock.h" -#include "timer.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock) -{ - struct tegra_mc_regs* const mc = (void *)MC_BASE; - - mc->sec_carveout_bom = bom; - mc->sec_carveout_size_mb = size1mb; - if (lock) - mc->sec_carveout_reg_ctrl |= 1; -} - -void mc_config_carveout() -{ - struct tegra_mc_regs * const mc = (void *)MC_BASE; - - *(vu32 *)0x8005FFFC = 0xC0EDBBCC; - mc->video_protect_gpu_override_0 = 1; - mc->video_protect_gpu_override_1 = 0; - mc->video_protect_bom = 0; - mc->video_protect_size_mb = 0; - mc->video_protect_reg_ctrl = 1; - - //Configure TSEC carveout @ 0x90000000, 1MB. - //mc_config_tsec_carveout(0x90000000, 1, 0); - mc_config_tsec_carveout(0, 0, 1); - - mc->mts_carveout_bom = 0; - mc->mts_carveout_size_mb = 0; - mc->mts_carveout_adr_hi = 0; - mc->mts_carveout_reg_ctrl = 1; - mc->security_carveout1_bom = 0; - mc->security_carveout1_bom_hi = 0; - mc->security_carveout1_size_128kb = 0; - mc->security_carveout1_ca0 = 0; - mc->security_carveout1_ca1 = 0; - mc->security_carveout1_ca2 = 0; - mc->security_carveout1_ca3 = 0; - mc->security_carveout1_ca4 = 0; - mc->security_carveout1_cfia0 = 0; - mc->security_carveout1_cfia1 = 0; - mc->security_carveout1_cfia2 = 0; - mc->security_carveout1_cfia3 = 0; - mc->security_carveout1_cfia4 = 0; - mc->security_carveout1_cfg0 = 0x4000006; - mc->security_carveout2_bom = 0x80020000; - mc->security_carveout2_bom_hi = 0; - mc->security_carveout2_size_128kb = 2; - mc->security_carveout2_ca0 = 0; - mc->security_carveout2_ca1 = 0; - mc->security_carveout2_ca2 = 0x3000000; - mc->security_carveout2_ca3 = 0; - mc->security_carveout2_ca4 = 0x300; - mc->security_carveout2_cfia0 = 0; - mc->security_carveout2_cfia1 = 0; - mc->security_carveout2_cfia2 = 0; - mc->security_carveout2_cfia3 = 0; - mc->security_carveout2_cfia4 = 0; - mc->security_carveout2_cfg0 = 0x440167e; - mc->security_carveout3_bom = 0; - mc->security_carveout3_bom_hi = 0; - mc->security_carveout3_size_128kb = 0; - mc->security_carveout3_ca0 = 0; - mc->security_carveout3_ca1 = 0; - mc->security_carveout3_ca2 = 0x3000000; - mc->security_carveout3_ca3 = 0; - mc->security_carveout3_ca4 = 0x300; - mc->security_carveout3_cfia0 = 0; - mc->security_carveout3_cfia1 = 0; - mc->security_carveout3_cfia2 = 0; - mc->security_carveout3_cfia3 = 0; - mc->security_carveout3_cfia4 = 0; - mc->security_carveout3_cfg0 = 0x4401e7e; - mc->security_carveout4_bom = 0; - mc->security_carveout4_bom_hi = 0; - mc->security_carveout4_size_128kb = 0; - mc->security_carveout4_ca0 = 0; - mc->security_carveout4_ca1 = 0; - mc->security_carveout4_ca2 = 0; - mc->security_carveout4_ca3 = 0; - mc->security_carveout4_ca4 = 0; - mc->security_carveout4_cfia0 = 0; - mc->security_carveout4_cfia1 = 0; - mc->security_carveout4_cfia2 = 0; - mc->security_carveout4_cfia3 = 0; - mc->security_carveout4_cfia4 = 0; - mc->security_carveout4_cfg0 = 0x8f; - mc->security_carveout5_bom = 0; - mc->security_carveout5_bom_hi = 0; - mc->security_carveout5_size_128kb = 0; - mc->security_carveout5_ca0 = 0; - mc->security_carveout5_ca1 = 0; - mc->security_carveout5_ca2 = 0; - mc->security_carveout5_ca3 = 0; - mc->security_carveout5_ca4 = 0; - mc->security_carveout5_cfia0 = 0; - mc->security_carveout5_cfia1 = 0; - mc->security_carveout5_cfia2 = 0; - mc->security_carveout5_cfia3 = 0; - mc->security_carveout5_cfia4 = 0; - mc->security_carveout5_cfg0 = 0x8f; -} - -static const u32 ARC_CLK_OVR_ON = 1u << 19; - -void mc_enable_ahb_redirect() -{ - struct tegra_mc_regs* const mc = (void *)MC_BASE; - - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) |= ARC_CLK_OVR_ON; - - //mc->iram_reg_ctrl &= ~(1); - mc->iram_bom = 0x40000000; - mc->iram_tom = 0x4003F000; -} - -void mc_disable_ahb_redirect() -{ - struct tegra_mc_regs* const mc = (void *)MC_BASE; - - mc->iram_bom = 0xFFFFF000; - mc->iram_tom = 0; - //mc->iram_reg_ctrl |= 1; //Disable IRAM_CFG_WRITE_ACCESS (sticky). - - CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= ~ARC_CLK_OVR_ON; -} - -void mc_enable() -{ - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - //Enable EMC clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) |= CLK_H_EMC; - //Enable MEM clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) |= CLK_H_MEM; - //Enable EMC DLL clock. - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) |= CLK_X_EMC_DLL; - //Clear EMC and MEM reset. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = CLK_H_MEM | CLK_H_EMC; - usleep(5); - - mc_disable_ahb_redirect(); - #ifdef CONFIG_ENABLE_AHB_REDIRECT - mc_enable_ahb_redirect(); - #endif -} diff --git a/ariane/src/hwinit/mc.h b/ariane/src/hwinit/mc.h deleted file mode 100644 index 3639553..0000000 --- a/ariane/src/hwinit/mc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _MC_H_ -#define _MC_H_ - -#include "types.h" - -void mc_config_tsec_carveout(u32 bom, u32 size1mb, int lock); -void mc_config_carveout(); -void mc_enable_ahb_redirect(); -void mc_disable_ahb_redirect(); -void mc_enable(); - -#endif diff --git a/ariane/src/hwinit/mc_t210.h b/ariane/src/hwinit/mc_t210.h deleted file mode 100644 index 10ed883..0000000 --- a/ariane/src/hwinit/mc_t210.h +++ /dev/null @@ -1,226 +0,0 @@ -/* -* Copyright (c) 2014, NVIDIA Corporation. All rights reserved. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ - -#ifndef _MC_T210_H_ -#define _MC_T210_H_ - -#include "types.h" - -// Memory Controller registers we need/care about - -struct tegra_mc_regs { - vu32 rsvd_0x0[4]; /* 0x00 */ - vu32 smmu_config; /* 0x10 */ - vu32 smmu_tlb_config; /* 0x14 */ - vu32 smmu_ptc_config; /* 0x18 */ - vu32 smmu_ptb_asid; /* 0x1c */ - vu32 smmu_ptb_data; /* 0x20 */ - vu32 rsvd_0x24[3]; /* 0x24 */ - vu32 smmu_tlb_flush; /* 0x30 */ - vu32 smmu_ptc_flush; /* 0x34 */ - vu32 rsvd_0x38[6]; /* 0x38 */ - vu32 emem_cfg; /* 0x50 */ - vu32 emem_adr_cfg; /* 0x54 */ - vu32 emem_adr_cfg_dev0; /* 0x58 */ - vu32 emem_adr_cfg_dev1; /* 0x5c */ - vu32 emem_adr_cfg_channel_mask; /* 0x60 */ - vu32 emem_adr_cfg_bank_mask_0; /* 0x64 */ - vu32 emem_adr_cfg_bank_mask_1; /* 0x68 */ - vu32 emem_adr_cfg_bank_mask_2; /* 0x6c */ - vu32 security_cfg0; /* 0x70 */ - vu32 security_cfg1; /* 0x74 */ - vu32 rsvd_0x78[6]; /* 0x78 */ - vu32 emem_arb_cfg; /* 0x90 */ - vu32 emem_arb_outstanding_req; /* 0x94 */ - vu32 emem_arb_timing_rcd; /* 0x98 */ - vu32 emem_arb_timing_rp; /* 0x9c */ - vu32 emem_arb_timing_rc; /* 0xa0 */ - vu32 emem_arb_timing_ras; /* 0xa4 */ - vu32 emem_arb_timing_faw; /* 0xa8 */ - vu32 emem_arb_timing_rrd; /* 0xac */ - vu32 emem_arb_timing_rap2pre; /* 0xb0 */ - vu32 emem_arb_timing_wap2pre; /* 0xb4 */ - vu32 emem_arb_timing_r2r; /* 0xb8 */ - vu32 emem_arb_timing_w2w; /* 0xbc */ - vu32 emem_arb_timing_r2w; /* 0xc0 */ - vu32 emem_arb_timing_w2r; /* 0xc4 */ - vu32 emem_arb_misc2; /* 0xC8 */ - vu32 rsvd_0xcc[1]; /* 0xCC */ - vu32 emem_arb_da_turns; /* 0xd0 */ - vu32 emem_arb_da_covers; /* 0xd4 */ - vu32 emem_arb_misc0; /* 0xd8 */ - vu32 emem_arb_misc1; /* 0xdc */ - vu32 emem_arb_ring1_throttle; /* 0xe0 */ - vu32 emem_arb_ring3_throttle; /* 0xe4 */ - vu32 emem_arb_override; /* 0xe8 */ - vu32 emem_arb_rsv; /* 0xec */ - vu32 rsvd_0xf0[1]; /* 0xf0 */ - vu32 clken_override; /* 0xf4 */ - vu32 timing_control_dbg; /* 0xf8 */ - vu32 timing_control; /* 0xfc */ - vu32 stat_control; /* 0x100 */ - vu32 rsvd_0x104[65]; /* 0x104 */ - vu32 emem_arb_isochronous_0; /* 0x208 */ - vu32 emem_arb_isochronous_1; /* 0x20c */ - vu32 emem_arb_isochronous_2; /* 0x210 */ - vu32 rsvd_0x214[38]; /* 0x214 */ - vu32 dis_extra_snap_levels; /* 0x2ac */ - vu32 rsvd_0x2b0[90]; /* 0x2b0 */ - vu32 video_protect_vpr_override; /* 0x418 */ - vu32 rsvd_0x41c[93]; /* 0x41c */ - vu32 video_protect_vpr_override1; /* 0x590 */ - vu32 rsvd_0x594[29]; /* 0x594 */ - vu32 display_snap_ring; /* 0x608 */ - vu32 rsvd_0x60c[15]; /* 0x60c */ - vu32 video_protect_bom; /* 0x648 */ - vu32 video_protect_size_mb; /* 0x64c */ - vu32 video_protect_reg_ctrl; /* 0x650 */ - vu32 rsvd_0x654[2]; /* 0x654 */ - vu32 iram_bom; /* 0x65C */ - vu32 iram_tom; /* 0x660 */ - vu32 emem_cfg_access_ctrl; /* 0x664 */ - vu32 rsvd_0x668[2]; /* 0x668 */ - vu32 sec_carveout_bom; /* 0x670 */ - vu32 sec_carveout_size_mb; /* 0x674 */ - vu32 sec_carveout_reg_ctrl; /* 0x678 */ - vu32 rsvd_0x67c[17]; /* 0x67C-0x6BC */ - - vu32 emem_arb_timing_rfcpb; /* 0x6C0 */ - vu32 emem_arb_timing_ccdmw; /* 0x6C4 */ - vu32 rsvd_0x6c8[10]; /* 0x6C8-0x6EC */ - - vu32 emem_arb_refpb_hp_ctrl; /* 0x6F0 */ - vu32 emem_arb_refpb_bank_ctrl; /* 0x6F4 */ - vu32 rsvd_0x6f8[155]; /* 0x6F8-0x960 */ - vu32 iram_reg_ctrl; /* 0x964 */ - vu32 emem_arb_override_1; /* 0x968 */ - vu32 rsvd_0x96c[3]; /* 0x96c */ - vu32 video_protect_bom_adr_hi; /* 0x978 */ - vu32 rsvd_0x97c[2]; /* 0x97c */ - vu32 video_protect_gpu_override_0; /* 0x984 */ - vu32 video_protect_gpu_override_1; /* 0x988 */ - vu32 rsvd_0x98c[5]; /* 0x98c */ - vu32 mts_carveout_bom; /* 0x9a0 */ - vu32 mts_carveout_size_mb; /* 0x9a4 */ - vu32 mts_carveout_adr_hi; /* 0x9a8 */ - vu32 mts_carveout_reg_ctrl; /* 0x9ac */ - vu32 rsvd_0x9b0[4]; /* 0x9b0 */ - vu32 emem_bank_swizzle_cfg0; /* 0x9c0 */ - vu32 emem_bank_swizzle_cfg1; /* 0x9c4 */ - vu32 emem_bank_swizzle_cfg2; /* 0x9c8 */ - vu32 emem_bank_swizzle_cfg3; /* 0x9cc */ - vu32 rsvd_0x9d0[1]; /* 0x9d0 */ - vu32 sec_carveout_adr_hi; /* 0x9d4 */ - vu32 rsvd_0x9d8; /* 0x9D8 */ - vu32 da_config0; /* 0x9DC */ - vu32 rsvd_0x9c0[138]; /* 0x9E0-0xc04 */ - - vu32 security_carveout1_cfg0; /* 0xc08 */ - vu32 security_carveout1_bom; /* 0xc0c */ - vu32 security_carveout1_bom_hi; /* 0xc10 */ - vu32 security_carveout1_size_128kb; /* 0xc14 */ - vu32 security_carveout1_ca0; /* 0xc18 */ - vu32 security_carveout1_ca1; /* 0xc1c */ - vu32 security_carveout1_ca2; /* 0xc20 */ - vu32 security_carveout1_ca3; /* 0xc24 */ - vu32 security_carveout1_ca4; /* 0xc28 */ - vu32 security_carveout1_cfia0; /* 0xc2c */ - vu32 security_carveout1_cfia1; /* 0xc30 */ - vu32 security_carveout1_cfia2; /* 0xc34 */ - vu32 security_carveout1_cfia3; /* 0xc38 */ - vu32 security_carveout1_cfia4; /* 0xc3c */ - vu32 rsvd_0xc40[6]; /* 0xc40-0xc54 */ - - vu32 security_carveout2_cfg0; /* 0xc58 */ - vu32 security_carveout2_bom; /* 0xc5c */ - vu32 security_carveout2_bom_hi; /* 0xc60 */ - vu32 security_carveout2_size_128kb; /* 0xc64 */ - vu32 security_carveout2_ca0; /* 0xc68 */ - vu32 security_carveout2_ca1; /* 0xc6c */ - vu32 security_carveout2_ca2; /* 0xc70 */ - vu32 security_carveout2_ca3; /* 0xc74 */ - vu32 security_carveout2_ca4; /* 0xc78 */ - vu32 security_carveout2_cfia0; /* 0xc7c */ - vu32 security_carveout2_cfia1; /* 0xc80 */ - vu32 security_carveout2_cfia2; /* 0xc84 */ - vu32 security_carveout2_cfia3; /* 0xc88 */ - vu32 security_carveout2_cfia4; /* 0xc8c */ - vu32 rsvd_0xc90[6]; /* 0xc90-0xca4 */ - - vu32 security_carveout3_cfg0; /* 0xca8 */ - vu32 security_carveout3_bom; /* 0xcac */ - vu32 security_carveout3_bom_hi; /* 0xcb0 */ - vu32 security_carveout3_size_128kb; /* 0xcb4 */ - vu32 security_carveout3_ca0; /* 0xcb8 */ - vu32 security_carveout3_ca1; /* 0xcbc */ - vu32 security_carveout3_ca2; /* 0xcc0 */ - vu32 security_carveout3_ca3; /* 0xcc4 */ - vu32 security_carveout3_ca4; /* 0xcc8 */ - vu32 security_carveout3_cfia0; /* 0xccc */ - vu32 security_carveout3_cfia1; /* 0xcd0 */ - vu32 security_carveout3_cfia2; /* 0xcd4 */ - vu32 security_carveout3_cfia3; /* 0xcd8 */ - vu32 security_carveout3_cfia4; /* 0xcdc */ - vu32 rsvd_0xce0[6]; /* 0xce0-0xcf4 */ - - vu32 security_carveout4_cfg0; /* 0xcf8 */ - vu32 security_carveout4_bom; /* 0xcfc */ - vu32 security_carveout4_bom_hi; /* 0xd00 */ - vu32 security_carveout4_size_128kb; /* 0xd04 */ - vu32 security_carveout4_ca0; /* 0xd08 */ - vu32 security_carveout4_ca1; /* 0xd0c */ - vu32 security_carveout4_ca2; /* 0xd10 */ - vu32 security_carveout4_ca3; /* 0xd14 */ - vu32 security_carveout4_ca4; /* 0xd18 */ - vu32 security_carveout4_cfia0; /* 0xd1c */ - vu32 security_carveout4_cfia1; /* 0xd20 */ - vu32 security_carveout4_cfia2; /* 0xd24 */ - vu32 security_carveout4_cfia3; /* 0xd28 */ - vu32 security_carveout4_cfia4; /* 0xd2c */ - vu32 rsvd_0xd30[6]; /* 0xd30-0xd44 */ - - vu32 security_carveout5_cfg0; /* 0xd48 */ - vu32 security_carveout5_bom; /* 0xd4c */ - vu32 security_carveout5_bom_hi; /* 0xd50 */ - vu32 security_carveout5_size_128kb; /* 0xd54 */ - vu32 security_carveout5_ca0; /* 0xd58 */ - vu32 security_carveout5_ca1; /* 0xd5c */ - vu32 security_carveout5_ca2; /* 0xd60 */ - vu32 security_carveout5_ca3; /* 0xd64 */ - vu32 security_carveout5_ca4; /* 0xd68 */ - vu32 security_carveout5_cfia0; /* 0xd6c */ - vu32 security_carveout5_cfia1; /* 0xd70 */ - vu32 security_carveout5_cfia2; /* 0xd74 */ - vu32 security_carveout5_cfia3; /* 0xd78 */ - vu32 security_carveout5_cfia4; /* 0xd7c */ -}; - -enum { - MC_SMMU_CONFIG_ENABLE = 1, - - MC_EMEM_CFG_SIZE_MB_SHIFT = 0, - MC_EMEM_CFG_SIZE_MB_MASK = 0x3fff, - - MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_SHIFT = 27, - MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_MASK = 1 << 27, - - MC_EMEM_CFG_ACCESS_CTRL_WRITE_ACCESS_DISABLED = 1, - - MC_TIMING_CONTROL_TIMING_UPDATE = 1, -}; - -#define MC_SECURITY_CARVEOUT_LOCKED (1 << 1) -#define MC_VPR_WR_ACCESS_DISABLE (1 << 0) -#define MC_VPR_ALLOW_TZ_WR_ACCESS_ENABLE (1 << 1) - -#endif diff --git a/ariane/src/hwinit/mtc.c b/ariane/src/hwinit/mtc.c deleted file mode 100644 index 9e0621c..0000000 --- a/ariane/src/hwinit/mtc.c +++ /dev/null @@ -1,236 +0,0 @@ -#include "timer.h" -#include "sdram.h" -#include "lib/decomp.h" -#include "lib/crc32.h" -#include "lib/printk.h" -#include "lib/heap.h" -#include - -typedef int bool; -#define true 1 -#define false 0 -#include "minerva_tc/mtc/mtc.h" -#include "minerva_tc/mtc/mtc_mc_emc_regs.h" - -extern size_t mtc_sdram_lzma_size; -extern const char mtc_sdram_lzma[]; - -static mtc_config_t _current_config = {0}; -static u32 _current_table_crc = 0; - -static bool _initialize_mtc_table() -{ - const size_t mtc_tables_size = ulzman(mtc_sdram_lzma, mtc_sdram_lzma_size, NULL, 0); - if (mtc_tables_size > 0) - { -#ifdef MTC_DEBUGGING - printk("[MTC_LOAD] Decompressing %u -> %u bytes of MTC tables...\n", mtc_sdram_lzma_size, mtc_tables_size); -#endif - u8* decomp_buffer = malloc(mtc_tables_size); - -#ifdef MTC_DEBUGGING - const u32 decomp_time_start = get_tmr_us(); -#endif - const size_t mtc_decomp_size = ulzman(mtc_sdram_lzma, mtc_sdram_lzma_size, decomp_buffer, mtc_tables_size); -#ifdef MTC_DEBUGGING - const u32 decomp_time_end = get_tmr_us(); -#endif - if (mtc_decomp_size != mtc_tables_size) - { - printk("[MTC_LOAD] Error during lzma decompression, got %u instead of %u bytes out!\n", mtc_decomp_size, mtc_tables_size); - free(decomp_buffer); - } - else - { -#ifdef MTC_DEBUGGING - printk("[MTC_LOAD] Decompression took %u us.\n", decomp_time_end - decomp_time_start); -#endif - - u8 matchBuffer[0x40]; - memcpy(matchBuffer, decomp_buffer, sizeof(matchBuffer)); - - const u8* matchStart = &decomp_buffer[sizeof(matchBuffer)]; - const u8* matchEnd = &decomp_buffer[mtc_tables_size]; - - typedef struct - { - u32 start; - u32 len; - } ramEntry_t; - - ramEntry_t entries[8]; - memset(entries, 0, sizeof(entries)); - -#ifdef MTC_DEBUGGING - const u32 search_time_start = get_tmr_us(); -#endif - u32 numEntries = 0; - while (matchStart < matchEnd) - { - if (memcmp(matchStart, matchBuffer, sizeof(matchBuffer)) == 0) - { - entries[numEntries].len = (matchStart - decomp_buffer) - entries[numEntries].start; - entries[++numEntries].start = (matchStart - decomp_buffer); - } - matchStart += sizeof(matchBuffer); - } - entries[numEntries].len = (matchEnd - decomp_buffer) - entries[numEntries].start; - numEntries++; -#ifdef MTC_DEBUGGING - const u32 search_time_end = get_tmr_us(); -#endif - - _current_config.sdram_id = get_sdram_id(); - for (u32 i=0; i= numEntries) - { - printk("[MTC] failed to find currently running entry\n"); - return 0; - } - currentTable = &mtcTable[runningEntry]; - } - -#ifdef MTC_DEBUGGING - printk("[MTC] currently using entry for %d kHz: %s\n", currentTable->rate_khz, currentTable->dvfs_ver); -#endif - -#ifdef MTC_SEPARATE_TRAINING - for (u32 i=0; irate_khz; - _current_config.rate_to = mtcTable[i].rate_khz; - _current_config.train_mode = OP_TRAIN; - printk("[MTC] Training %d kHz -> %d kHz\n", _current_config.rate_from, _current_config.rate_to); - minerva_main(&_current_config); - } -#endif - - const u32 wantedRateKhz = (targetFreq < 0) ? (-targetFreq) : targetFreq; - for (u32 nextTableIdx=(currentTable-mtcTable)+1; nextTableIdxrate_khz > wantedRateKhz) - break; - - if (nextTable->periodic_training && targetFreq > 0) - break; - - _current_config.rate_from = currentTable->rate_khz; - _current_config.rate_to = nextTable->rate_khz; -#ifdef MTC_SEPARATE_TRAINING - _current_config.train_mode = OP_SWITCH; -#else - _current_config.train_mode = OP_TRAIN_SWITCH; -#endif - printk("[MTC] Switching %d kHz -> %d kHz\n", _current_config.rate_from, _current_config.rate_to); - minerva_main(&_current_config); - if (_current_config.current_emc_table != NULL) - currentTable = _current_config.current_emc_table; - - if (_current_config.current_emc_table != nextTable) - { - printk("[MTC] Failed to switch! Remaining on %d kHz\n", currentTable->rate_khz); - break; - } - } - - int newClock = currentTable->rate_khz; - if (currentTable->periodic_training) - newClock = -newClock; - - return newClock; -} - -u32 mtc_redo_periodic_training(u32 lastPeriodicMs) -{ - const emc_table_t* mtcTable = _current_config.mtc_table; - const u32 numEntries = _current_config.table_entries; - const size_t mtcTableSize = numEntries * sizeof(emc_table_t); - - if (mtcTable == NULL || numEntries == 0) - return 0; - - if (crc32b((unsigned char*)mtcTable, mtcTableSize) != _current_table_crc) - return 0; - - const emc_table_t* currentTable = _current_config.current_emc_table; - if (currentTable == NULL) - return 0; - - const u32 currTimeMs = get_tmr_ms(); - if (currTimeMs < (lastPeriodicMs + EMC_PERIODIC_TRAIN_MS)) - return lastPeriodicMs; - - _current_config.rate_from = currentTable->rate_khz; - _current_config.rate_to = currentTable->rate_khz; - _current_config.train_mode = OP_PERIODIC_TRAIN; - minerva_main(&_current_config); - return currTimeMs; -} \ No newline at end of file diff --git a/ariane/src/hwinit/mtc.h b/ariane/src/hwinit/mtc.h deleted file mode 100644 index 8449bd2..0000000 --- a/ariane/src/hwinit/mtc.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _HWINIT_MTC_H_ -#define _HWINIT_MTC_H_ - -#include "types.h" -//negative targetFreq => periodic training is allowed as parameter, as return value periodic training is required -int mtc_perform_memory_training(int targetFreq); -//performs periodic training if the time interval since last one is greater than periodic training timeout -u32 mtc_redo_periodic_training(u32 lastPeriodicMs); - -#endif diff --git a/ariane/src/hwinit/pinmux.c b/ariane/src/hwinit/pinmux.c deleted file mode 100644 index 37a351c..0000000 --- a/ariane/src/hwinit/pinmux.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2013 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "pinmux.h" -#include "t210.h" -#include "gpio.h" - -static volatile uint32_t *pinmux_regs = (void *)PINMUX_AUX_BASE; - -void pinmux_set_config(int pin_index, uint32_t config) -{ - pinmux_regs[pin_index] = config; -} - -uint32_t pinmux_get_config(int pin_index) -{ - return pinmux_regs[pin_index]; -} - -void pinmux_set_unused(int pin_index, int gpio_index, int has_gpio, int pulltype) -{ - uint32_t reg = pinmux_get_config(pin_index); - reg &= ~PINMUX_INPUT_ENABLE; - reg |= PINMUX_TRISTATE; - reg &= ~PINMUX_PULL_MASK; - if (pulltype == POR_PU) - reg |= PINMUX_PULL_UP; - else if (pulltype == POR_PD) - reg |= PINMUX_PULL_DOWN; - pinmux_set_config(pin_index, reg); - - if (has_gpio) - { - gpio_config(gpio_index_port(gpio_index), gpio_index_bitmask(gpio_index), GPIO_MODE_GPIO); - gpio_output_enable(gpio_index_port(gpio_index), gpio_index_bitmask(gpio_index), GPIO_OUTPUT_DISABLE); - } -} - -void pinmux_config_i2c(int i2c_index) -{ - static const int pinmux_i2c[] = { - PINMUX_GEN1_I2C_SDA_INDEX, PINMUX_GEN1_I2C_SCL_INDEX, - PINMUX_GEN2_I2C_SDA_INDEX, PINMUX_GEN2_I2C_SCL_INDEX, - PINMUX_GEN3_I2C_SDA_INDEX, PINMUX_GEN3_I2C_SCL_INDEX, - PINMUX_CAM_I2C_SDA_INDEX, PINMUX_CAM_I2C_SCL_INDEX, - PINMUX_PWR_I2C_SDA_INDEX, PINMUX_PWR_I2C_SCL_INDEX }; - - pinmux_set_config(pinmux_i2c[i2c_index*2+0], PINMUX_INPUT_ENABLE); - pinmux_set_config(pinmux_i2c[i2c_index*2+1], PINMUX_INPUT_ENABLE); - - static const int gpio_i2c[] = { - PAD_TO_GPIO_GEN1_I2C_SDA, PAD_TO_GPIO_GEN1_I2C_SCL, - PAD_TO_GPIO_GEN2_I2C_SDA, PAD_TO_GPIO_GEN2_I2C_SCL, - PAD_TO_GPIO_GEN3_I2C_SDA, PAD_TO_GPIO_GEN3_I2C_SCL, - PAD_TO_GPIO_CAM_I2C_SDA, PAD_TO_GPIO_CAM_I2C_SCL, - PAD_TO_GPIO_PWR_I2C_SDA, PAD_TO_GPIO_PWR_I2C_SCL }; - - const int gpio_index_sda = gpio_i2c[i2c_index*2+0]; - const int gpio_index_scl = gpio_i2c[i2c_index*2+1]; - gpio_config(gpio_index_port(gpio_index_sda), gpio_index_bitmask(gpio_index_sda), GPIO_MODE_SPIO); - gpio_config(gpio_index_port(gpio_index_scl), gpio_index_bitmask(gpio_index_scl), GPIO_MODE_SPIO); -} - -void pinmux_config_uart(int uart_index) -{ - static const int pinmux_uart[] = { - PINMUX_UART1_TX_INDEX, PINMUX_UART1_RX_INDEX, PINMUX_UART1_RTS_INDEX, PINMUX_UART1_CTS_INDEX, - PINMUX_UART2_TX_INDEX, PINMUX_UART2_RX_INDEX, PINMUX_UART2_RTS_INDEX, PINMUX_UART2_CTS_INDEX, - PINMUX_UART3_TX_INDEX, PINMUX_UART3_RX_INDEX, PINMUX_UART3_RTS_INDEX, PINMUX_UART3_CTS_INDEX, - PINMUX_UART4_TX_INDEX, PINMUX_UART4_RX_INDEX, PINMUX_UART4_RTS_INDEX, PINMUX_UART4_CTS_INDEX }; - - pinmux_set_config(pinmux_uart[uart_index*4+0], PINMUX_PULL_UP); - pinmux_set_config(pinmux_uart[uart_index*4+1], PINMUX_INPUT_ENABLE | PINMUX_PULL_UP); - pinmux_set_config(pinmux_uart[uart_index*4+2], PINMUX_PULL_UP); - pinmux_set_config(pinmux_uart[uart_index*4+3], PINMUX_INPUT_ENABLE | PINMUX_PULL_UP); - - static const int gpio_uart[] = { - PAD_TO_GPIO_UART1_TX, PAD_TO_GPIO_UART1_RX, PAD_TO_GPIO_UART1_RTS, PAD_TO_GPIO_UART1_CTS, - PAD_TO_GPIO_UART2_TX, PAD_TO_GPIO_UART2_RX, PAD_TO_GPIO_UART2_RTS, PAD_TO_GPIO_UART2_CTS, - PAD_TO_GPIO_UART3_TX, PAD_TO_GPIO_UART3_RX, PAD_TO_GPIO_UART3_RTS, PAD_TO_GPIO_UART3_CTS, - PAD_TO_GPIO_UART4_TX, PAD_TO_GPIO_UART4_RX, PAD_TO_GPIO_UART4_RTS, PAD_TO_GPIO_UART4_CTS }; - - for (int i=0; i<4; i++) - { - const int gpio_index = gpio_uart[uart_index*4+i]; - gpio_config(gpio_index_port(gpio_index), gpio_index_bitmask(gpio_index), GPIO_MODE_SPIO); - } -} \ No newline at end of file diff --git a/ariane/src/hwinit/pinmux.h b/ariane/src/hwinit/pinmux.h deleted file mode 100644 index 769ce31..0000000 --- a/ariane/src/hwinit/pinmux.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __SOC_NVIDIA_TEGRA210_PINMUX_H__ -#define __SOC_NVIDIA_TEGRA210_PINMUX_H__ - -#include - -void pinmux_set_config(int pin_index, uint32_t config); -uint32_t pinmux_get_config(int pin_index); - -void pinmux_set_unused(int pin_index, int gpio_index, int has_gpio, int pulltype); -#define PINMUX_SET_UNUSED_BY_NAME(name) pinmux_set_unused(PINMUX_##name##_INDEX, PAD_TO_GPIO_##name, PAD_HAS_GPIO_##name, PAD_POR_PU_##name) -#define PINMUX_SET_UNUSED_BY_GPIO(gpio) pinmux_set_unused(PINMUX_GPIO_##gpio, GPIO_##gpio##_index, 1, GPIO_POR_PU_##gpio) - -void pinmux_config_i2c(int i2c_index); -void pinmux_config_uart(int uart_index); - -enum { - PINMUX_FUNC_MASK = 3 << 0, - - PINMUX_PULL_MASK = 3 << 2, - PINMUX_PULL_NONE = 0 << 2, - PINMUX_PULL_DOWN = 1 << 2, - PINMUX_PULL_UP = 2 << 2, - - PINMUX_TRISTATE = 1 << 4, - PINMUX_PARKED = 1 << 5, - PINMUX_INPUT_ENABLE = 1 << 6, - PINMUX_LOCK = 1 << 7, - PINMUX_LPDR = 1 << 8, - PINMUX_HSM = 1 << 9, - PINMUX_IO_HV = 1 << 10, - PINMUX_OPEN_DRAIN = 1 << 11, - PINMUX_SCHMT = 1 << 12, - - PINMUX_DRIVE_1X = 0 << 13, - PINMUX_DRIVE_2X = 1 << 13, - PINMUX_DRIVE_3X = 2 << 13, - PINMUX_DRIVE_4X = 3 << 13, -}; - -/* GPIO index constants. */ - -#define GPIO_PORT_CONSTANTS(port) \ - GPIO_##port##0_INDEX, GPIO_##port##1_INDEX, GPIO_##port##2_INDEX, \ - GPIO_##port##3_INDEX, GPIO_##port##4_INDEX, GPIO_##port##5_INDEX, \ - GPIO_##port##6_INDEX, GPIO_##port##7_INDEX - -enum { - GPIO_PORT_CONSTANTS(A), - GPIO_PORT_CONSTANTS(B), - GPIO_PORT_CONSTANTS(C), - GPIO_PORT_CONSTANTS(D), - GPIO_PORT_CONSTANTS(E), - GPIO_PORT_CONSTANTS(F), - GPIO_PORT_CONSTANTS(G), - GPIO_PORT_CONSTANTS(H), - GPIO_PORT_CONSTANTS(I), - GPIO_PORT_CONSTANTS(J), - GPIO_PORT_CONSTANTS(K), - GPIO_PORT_CONSTANTS(L), - GPIO_PORT_CONSTANTS(M), - GPIO_PORT_CONSTANTS(N), - GPIO_PORT_CONSTANTS(O), - GPIO_PORT_CONSTANTS(P), - GPIO_PORT_CONSTANTS(Q), - GPIO_PORT_CONSTANTS(R), - GPIO_PORT_CONSTANTS(S), - GPIO_PORT_CONSTANTS(T), - GPIO_PORT_CONSTANTS(U), - GPIO_PORT_CONSTANTS(V), - GPIO_PORT_CONSTANTS(W), - GPIO_PORT_CONSTANTS(X), - GPIO_PORT_CONSTANTS(Y), - GPIO_PORT_CONSTANTS(Z), - GPIO_PORT_CONSTANTS(AA), - GPIO_PORT_CONSTANTS(BB), - GPIO_PORT_CONSTANTS(CC), - GPIO_PORT_CONSTANTS(DD), - GPIO_PORT_CONSTANTS(EE), - GPIO_PORT_CONSTANTS(FF), - GPIO_NONE_INDEX = 0, -}; - -#define PINMUX_CONSTANTS_GPIO(name, gpio) \ - PINMUX_GPIO_##gpio = PINMUX_##name##_INDEX, \ - GPIO_POR_PU_##gpio = PAD_POR_PU_##name - -#define PINMUX_CONSTANTS(index, name, por_pu, gpio, has_gpio, \ - func0, func1, func2, func3) \ - PINMUX_##name##_INDEX = index, \ - PINMUX_##name##_FUNC_##func0 = 0, \ - PINMUX_##name##_FUNC_##func1 = 1, \ - PINMUX_##name##_FUNC_##func2 = 2, \ - PINMUX_##name##_FUNC_##func3 = 3, \ - PAD_TO_GPIO_##name = GPIO_##gpio##_INDEX, \ - PAD_HAS_GPIO_##name = has_gpio, \ - PAD_POR_PU_##name = por_pu - -#define PAD_GPIO(index, name, por_pu, gpio, func0, func1, func2, func3) \ - PINMUX_CONSTANTS(index, name, por_pu, gpio, 1, \ - func0, func1, func2, func3), \ - PINMUX_CONSTANTS_GPIO(name, gpio) - -#define PAD_NO_GPIO(index, name, por_pu, func0, func1, func2, func3) \ - PINMUX_CONSTANTS(index, name, por_pu, NONE, 0, \ - func0, func1, func2, func3) - -enum { - /* Power-on-reset pull states. */ - POR_PU = 2, - POR_PD = 1, - POR_NP = 0, - - PAD_GPIO(0, SDMMC1_CLK, POR_PD, M0, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(1, SDMMC1_CMD, POR_PU, M1, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(2, SDMMC1_DAT3, POR_PU, M2, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(3, SDMMC1_DAT2, POR_PU, M3, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(4, SDMMC1_DAT1, POR_PU, M4, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(5, SDMMC1_DAT0, POR_PU, M5, SDMMC1, RES1, RES2, RES3), - PAD_GPIO(6, SDMMC3_CLK, POR_PD, P0, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(7, SDMMC3_CMD, POR_PU, P1, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(8, SDMMC3_DAT0, POR_PU, P2, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(9, SDMMC3_DAT1, POR_PU, P3, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(10, SDMMC3_DAT2, POR_PU, P4, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(11, SDMMC3_DAT3, POR_PU, P5, SDMMC3, RES1, RES2, RES3), - /* GPIO12 - unused */ - /* GPIO13 - unused */ - PAD_GPIO(14, PEX_L0_RST_N, POR_NP, A0, PE0, RES1, RES2, RES3), - PAD_GPIO(15, PEX_L0_CLKREQ_N, POR_NP, A1, PE0, RES1, RES2, RES3), - PAD_GPIO(16, PEX_WAKE_N, POR_NP, A2, PE, RES1, RES2, RES3), - PAD_GPIO(17, PEX_L1_RST_N, POR_NP, A3, PE1, RES1, RES2, RES3), - PAD_GPIO(18, PEX_L1_CLKREQ_N, POR_NP, A4, PE1, RES1, RES2, RES3), - PAD_GPIO(19, SATA_LED_ACTIVE, POR_NP, A5, SATA, RES1, RES2, RES3), - PAD_GPIO(20, SPI1_MOSI, POR_PD, C0, SPI1, RES1, RES2, RES3), - PAD_GPIO(21, SPI1_MISO, POR_PD, C1, SPI1, RES1, RES2, RES3), - PAD_GPIO(22, SPI1_SCK, POR_PD, C2, SPI1, RES1, RES2, RES3), - PAD_GPIO(23, SPI1_CS0, POR_PU, C3, SPI1, RES1, RES2, RES3), - PAD_GPIO(24, SPI1_CS1, POR_PU, C4, SPI1, RES1, RES2, RES3), - PAD_GPIO(25, SPI2_MOSI, POR_PD, B4, SPI2, DTV, RES2, RES3), - PAD_GPIO(26, SPI2_MISO, POR_PD, B5, SPI2, DTV, RES2, RES3), - PAD_GPIO(27, SPI2_SCK, POR_PD, B6, SPI2, DTV, RES2, RES3), - PAD_GPIO(28, SPI2_CS0, POR_PU, B7, SPI2, DTV, RES2, RES3), - PAD_GPIO(29, SPI2_CS1, POR_PU, DD0, SPI2, RES1, RES2, RES3), - PAD_GPIO(30, SPI4_MOSI, POR_PD, C7, SPI4, RES1, RES2, RES3), - PAD_GPIO(31, SPI4_MISO, POR_PD, D0, SPI4, RES1, RES2, RES3), - PAD_GPIO(32, SPI4_SCK, POR_PD, C5, SPI4, RES1, RES2, RES3), - PAD_GPIO(33, SPI4_CS0, POR_PU, C6, SPI4, RES1, RES2, RES3), - PAD_GPIO(34, QSPI_SCK, POR_PU, EE0, QSPI, RES1, RES2, RES3), - PAD_GPIO(35, QSPI_CS_N, POR_PU, EE1, QSPI, RES1, RES2, RES3), - PAD_GPIO(36, QSPI_IO0, POR_PU, EE2, QSPI, RES1, RES2, RES3), - PAD_GPIO(37, QSPI_IO1, POR_PU, EE3, QSPI, RES1, RES2, RES3), - PAD_GPIO(38, QSPI_IO2, POR_PU, EE4, QSPI, RES1, RES2, RES3), - PAD_GPIO(39, QSPI_IO3, POR_PU, EE5, QSPI, RES1, RES2, RES3), - /* GPIO40 - unused */ - PAD_GPIO(41, DMIC1_CLK, POR_PD, E0, DMIC1, I2S3, RES2, RES3), - PAD_GPIO(42, DMIC1_DAT, POR_PD, E1, DMIC1, I2S3, RES2, RES3), - PAD_GPIO(43, DMIC2_CLK, POR_PD, E2, DMIC2, I2S3, RES2, RES3), - PAD_GPIO(44, DMIC2_DAT, POR_PD, E3, DMIC2, I2S3, RES2, RES3), - PAD_GPIO(45, DMIC3_CLK, POR_PD, E4, DMIC3, I2S5A, RES2, RES3), - PAD_GPIO(46, DMIC3_DAT, POR_PD, E5, DMIC3, I2S5A, RES2, RES3), - PAD_GPIO(47, GEN1_I2C_SDA, POR_NP, J0, I2C1, RES1, RES2, RES3), - PAD_GPIO(48, GEN1_I2C_SCL, POR_NP, J1, I2C1, RES1, RES2, RES3), - PAD_GPIO(49, GEN2_I2C_SCL, POR_NP, J2, I2C2, RES1, RES2, RES3), - PAD_GPIO(50, GEN2_I2C_SDA, POR_NP, J3, I2C2, RES1, RES2, RES3), - PAD_GPIO(51, GEN3_I2C_SCL, POR_NP, F0, I2C3, RES1, RES2, RES3), - PAD_GPIO(52, GEN3_I2C_SDA, POR_NP, F1, I2C3, RES1, RES2, RES3), - PAD_GPIO(53, CAM_I2C_SCL, POR_NP, S2, I2C3, I2CVI, RES2, RES3), - PAD_GPIO(54, CAM_I2C_SDA, POR_NP, S3, I2C3, I2CVI, RES2, RES3), - PAD_GPIO(55, PWR_I2C_SCL, POR_NP, Y3, I2CPMU, RES1, RES2, RES3), - PAD_GPIO(56, PWR_I2C_SDA, POR_NP, Y4, I2CPMU, RES1, RES2, RES3), - PAD_GPIO(57, UART1_TX, POR_PD, U0, UARTA, RES1, RES2, RES3), - PAD_GPIO(58, UART1_RX, POR_PD, U1, UARTA, RES1, RES2, RES3), - PAD_GPIO(59, UART1_RTS, POR_PD, U2, UARTA, RES1, RES2, RES3), - PAD_GPIO(60, UART1_CTS, POR_PD, U3, UARTA, RES1, RES2, RES3), - PAD_GPIO(61, UART2_TX, POR_PD, G0, UARTB, I2S4A, SPDIF, UART), - PAD_GPIO(62, UART2_RX, POR_PD, G1, UARTB, I2S4A, SPDIF, UART), - PAD_GPIO(63, UART2_RTS, POR_PD, G2, UARTB, I2S4A, RES2, UART), - PAD_GPIO(64, UART2_CTS, POR_PD, G3, UARTB, I2S4A, RES2, UART), - PAD_GPIO(65, UART3_TX, POR_PD, D1, UARTC, SPI4, RES2, RES3), - PAD_GPIO(66, UART3_RX, POR_PD, D2, UARTC, SPI4, RES2, RES3), - PAD_GPIO(67, UART3_RTS, POR_PD, D3, UARTC, SPI4, RES2, RES3), - PAD_GPIO(68, UART3_CTS, POR_PD, D4, UARTC, SPI4, RES2, RES3), - PAD_GPIO(69, UART4_TX, POR_PD, I4, UARTD, UART, RES2, RES3), - PAD_GPIO(70, UART4_RX, POR_PD, I5, UARTD, UART, RES2, RES3), - PAD_GPIO(71, UART4_RTS, POR_PD, I6, UARTD, UART, RES2, RES3), - PAD_GPIO(72, UART4_CTS, POR_PD, I7, UARTD, UART, RES2, RES3), - PAD_GPIO(73, DAP1_FS, POR_PD, B0, I2S1, RES1, RES2, RES3), - PAD_GPIO(74, DAP1_DIN, POR_PD, B1, I2S1, RES1, RES2, RES3), - PAD_GPIO(75, DAP1_DOUT, POR_PD, B2, I2S1, RES1, RES2, RES3), - PAD_GPIO(76, DAP1_SCLK, POR_PD, B3, I2S1, RES1, RES2, RES3), - PAD_GPIO(77, DAP2_FS, POR_PD, AA0, I2S2, RES1, RES2, RES3), - PAD_GPIO(78, DAP2_DIN, POR_PD, AA1, I2S2, RES1, RES2, RES3), - PAD_GPIO(79, DAP2_DOUT, POR_PD, AA2, I2S2, RES1, RES2, RES3), - PAD_GPIO(80, DAP2_SCLK, POR_PD, AA3, I2S2, RES1, RES2, RES3), - PAD_GPIO(81, DAP4_FS, POR_PD, J4, I2S4B, RES1, RES2, RES3), - PAD_GPIO(82, DAP4_DIN, POR_PD, J5, I2S4B, RES1, RES2, RES3), - PAD_GPIO(83, DAP4_DOUT, POR_PD, J6, I2S4B, RES1, RES2, RES3), - PAD_GPIO(84, DAP4_SCLK, POR_PD, J7, I2S4B, RES1, RES2, RES3), - PAD_GPIO(85, CAM1_MCLK, POR_PD, S0, EXTPERIPH3, RES1, RES2, RES3), - PAD_GPIO(86, CAM2_MCLK, POR_PD, S1, EXTPERIPH3, RES1, RES2, RES3), - PAD_NO_GPIO(87, JTAG_RTCK, POR_PU, JTAG, RES1, RES2, RES3), - PAD_NO_GPIO(88, CLK_32K_IN, POR_NP, CLK_32K_IN, RES1, RES2, RES3), - PAD_GPIO(89, CLK_32K_OUT, POR_PD, Y5, SOC, BLINK, RES2, RES3), - PAD_NO_GPIO(90, BATT_BCL, POR_NP, BCL, RES1, RES2, RES3), - PAD_NO_GPIO(91, CLK_REQ, POR_NP, CLK_REQ, RES1, RES2, RES3), - PAD_NO_GPIO(92, CPU_PWR_REQ, POR_NP, CPU, RES1, RES2, RES3), - PAD_NO_GPIO(93, PWR_INT_N, POR_NP, PMI, RES1, RES2, RES3), - PAD_NO_GPIO(94, SHUTDOWN, POR_NP, SHUTDOWN, RES1, RES2, RES3), - PAD_NO_GPIO(95, CORE_PWR_REQ, POR_NP, PWRON, RES1, RES2, RES3), - PAD_GPIO(96, AUD_MCLK, POR_PD, BB0, AUD, RES1, RES2, RES3), - PAD_GPIO(97, DVFS_PWM, POR_PD, BB1, RES0, CLDVFS, SPI3, RES3), - PAD_GPIO(98, DVFS_CLK, POR_PU, BB2, RES0, CLDVFS, SPI3, RES3), - PAD_GPIO(99, GPIO_X1_AUD, POR_PD, BB3, RES0, RES1, SPI3, RES3), - PAD_GPIO(100, GPIO_X3_AUD, POR_PU, BB4, RES0, RES1, SPI3, RES3), - PAD_NO_GPIO(101, GPIO_PCC7, POR_NP, RES0, RES1, RES2, RES3), - PAD_GPIO(102, HDMI_CEC, POR_NP, CC0, CEC, RES1, RES2, RES3), - PAD_GPIO(103, HDMI_INT_DP_HPD, POR_PD, CC1, DP, RES1, RES2, RES3), - PAD_GPIO(104, SPDIF_OUT, POR_PU, CC2, SPDIF, RES1, RES2, I2C3), - PAD_GPIO(105, SPDIF_IN, POR_PD, CC3, SPDIF, RES1, RES2, I2C3), - PAD_GPIO(106, USB_VBUS_EN0, POR_NP, CC4, USB, RES1, RES2, RES3), - PAD_GPIO(107, USB_VBUS_EN1, POR_NP, CC5, USB, RES1, RES2, RES3), - PAD_GPIO(108, DP_HPD0, POR_PD, CC6, DP, RES1, RES2, RES3), - PAD_GPIO(109, WIFI_EN, POR_PD, H0, RES0, RES1, RES2, RES3), - PAD_GPIO(110, WIFI_RST, POR_PD, H1, RES0, RES1, RES2, RES3), - PAD_GPIO(111, WIFI_WAKE_AP, POR_PD, H2, RES0, RES1, RES2, RES3), - PAD_GPIO(112, AP_WAKE_BT, POR_PD, H3, RES0, UARTB, SPDIF, RES3), - PAD_GPIO(113, BT_RST, POR_PD, H4, RES0, UARTB, SPDIF, RES3), - PAD_GPIO(114, BT_WAKE_AP, POR_PD, H5, RES0, RES1, RES2, RES3), - PAD_GPIO(115, AP_WAKE_NFC, POR_PD, H7, RES0, RES1, RES2, RES3), - PAD_GPIO(116, NFC_EN, POR_PD, I0, RES0, RES1, RES2, RES3), - PAD_GPIO(117, NFC_INT, POR_PD, I1, RES0, RES1, RES2, RES3), - PAD_GPIO(118, GPS_EN, POR_PD, I2, RES0, RES1, RES2, RES3), - PAD_GPIO(119, GPS_RST, POR_PD, I3, RES0, RES1, RES2, RES3), - PAD_GPIO(120, CAM_RST, POR_PD, S4, VGP1, RES1, RES2, RES3), - PAD_GPIO(121, CAM_AF_EN, POR_PD, S5, VIMCLK, VGP2, RES2, RES3), - PAD_GPIO(122, CAM_FLASH_EN, POR_PD, S6, VIMCLK, VGP3, RES2, RES3), - PAD_GPIO(123, CAM1_PWDN, POR_PD, S7, VGP4, RES1, RES2, RES3), - PAD_GPIO(124, CAM2_PWDN, POR_PD, T0, VGP5, RES1, RES2, RES3), - PAD_GPIO(125, CAM1_STROBE, POR_PD, T1, VGP6, RES1, RES2, RES3), - PAD_GPIO(126, LCD_TE, POR_PD, Y2, DISPLAYA, RES1, RES2, RES3), - PAD_GPIO(127, LCD_BL_PWM, POR_PD, V0, DISPLAYA, PWM0, SOR0, RES3), - PAD_GPIO(128, LCD_BL_EN, POR_PD, V1, RES0, RES1, RES2, RES3), - PAD_GPIO(129, LCD_RST, POR_PD, V2, RES0, RES1, RES2, RES3), - PAD_GPIO(130, LCD_GPIO1, POR_PD, V3, DISPLAYB, RES1, RES2, RES3), - PAD_GPIO(131, LCD_GPIO2, POR_PD, V4, DISPLAYB, PWM1, RES2, SOR1), - PAD_GPIO(132, AP_READY, POR_PD, V5, RES0, RES1, RES2, RES3), - PAD_GPIO(133, TOUCH_RST, POR_PD, V6, RES0, RES1, RES2, RES3), - PAD_GPIO(134, TOUCH_CLK, POR_PD, V7, TOUCH, RES1, RES2, RES3), - PAD_GPIO(135, MODEM_WAKE_AP, POR_PD, X0, RES0, RES1, RES2, RES3), - PAD_GPIO(136, TOUCH_INT, POR_PD, X1, RES0, RES1, RES2, RES3), - PAD_GPIO(137, MOTION_INT, POR_PD, X2, RES0, RES1, RES2, RES3), - PAD_GPIO(138, ALS_PROX_INT, POR_PD, X3, RES0, RES1, RES2, RES3), - PAD_GPIO(139, TEMP_ALERT, POR_PD, X4, RES0, RES1, RES2, RES3), - PAD_GPIO(140, BUTTON_POWER_ON, POR_PU, X5, RES0, RES1, RES2, RES3), - PAD_GPIO(141, BUTTON_VOL_UP, POR_PU, X6, RES0, RES1, RES2, RES3), - PAD_GPIO(142, BUTTON_VOL_DOWN, POR_PU, X7, RES0, RES1, RES2, RES3), - PAD_GPIO(143, BUTTON_SLIDE_SW, POR_PU, Y0, RES0, RES1, RES2, RES3), - PAD_GPIO(144, BUTTON_HOME, POR_PU, Y1, RES0, RES1, RES2, RES3), - PAD_NO_GPIO(145, GPIO_PA6, POR_NP, SATA, RES1, RES2, RES3), - PAD_NO_GPIO(146, GPIO_PE6, POR_PD, RES0, I2S5A, PWM2, RES3), - PAD_NO_GPIO(147, GPIO_PE7, POR_PD, RES0, I2S5A, PWM3, RES3), - PAD_NO_GPIO(148, GPIO_PH6, POR_PD, RES0, RES1, RES2, RES3), - PAD_GPIO(149, GPIO_PK0, POR_PD, K0, IQC0, I2S5B, RES2, RES3), - PAD_GPIO(150, GPIO_PK1, POR_PD, K1, IQC0, I2S5B, RES2, RES3), - PAD_GPIO(151, GPIO_PK2, POR_PD, K2, IQC0, I2S5B, RES2, RES3), - PAD_NO_GPIO(152, GPIO_PK3, POR_PD, IQC0, I2S5B, RES2, RES3), - PAD_NO_GPIO(153, GPIO_PK4, POR_PD, IQC1, RES1, RES2, RES3), - PAD_NO_GPIO(154, GPIO_PK5, POR_PD, IQC1, RES1, RES2, RES3), - PAD_NO_GPIO(155, GPIO_PK6, POR_PD, IQC1, RES1, RES2, RES3), - PAD_NO_GPIO(156, GPIO_PK7, POR_PD, IQC1, RES1, RES2, RES3), - PAD_NO_GPIO(157, GPIO_PL0, POR_PD, RES0, RES1, RES2, RES3), - PAD_NO_GPIO(158, GPIO_PL1, POR_PD, SOC, RES1, RES2, RES3), - PAD_NO_GPIO(159, GPIO_PZ0, POR_PD, VIMCLK2, RES1, RES2, RES3), - PAD_GPIO(160, GPIO_PZ1, POR_PD, Z1, VIMCLK2, SDMMC1, RES2, RES3), - PAD_NO_GPIO(161, GPIO_PZ2, POR_PD, SDMMC3, CCLA, RES2, RES3), - PAD_NO_GPIO(162, GPIO_PZ3, POR_PD, SDMMC3, RES1, RES2, RES3), - PAD_GPIO(163, GPIO_PZ4, POR_PD, Z4, SDMMC1, RES1, RES2, RES3), - PAD_NO_GPIO(164, GPIO_PZ5, POR_PD, SOC, RES1, RES2, RES3), -}; - -#define GPIO_BY_NAME(x) GPIO_DECOMPOSE(PAD_TO_GPIO_ ## x) - -#endif /* __SOC_NVIDIA_TEGRA210_PINMUX_H__ */ diff --git a/ariane/src/hwinit/pmc.h b/ariane/src/hwinit/pmc.h deleted file mode 100644 index 2adf375..0000000 --- a/ariane/src/hwinit/pmc.h +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _TEGRA210_PMC_H_ -#define _TEGRA210_PMC_H_ - -#include "types.h" - -enum { - POWER_PARTID_CRAIL = 0, - POWER_PARTID_TD = 1, - POWER_PARTID_VE = 2, - POWER_PARTID_PCX = 3, - POWER_PARTID_C0L2 = 5, - POWER_PARTID_MPE = 6, - POWER_PARTID_HEG = 7, - POWER_PARTID_SAX = 8, - POWER_PARTID_CE1 = 9, - POWER_PARTID_CE2 = 10, - POWER_PARTID_CE3 = 11, - POWER_PARTID_CELP = 12, - POWER_PARTID_CE0 = 14, - POWER_PARTID_C0NC = 15, - POWER_PARTID_C1NC = 16, - POWER_PARTID_SOR = 17, - POWER_PARTID_DIS = 18, - POWER_PARTID_DISB = 19, - POWER_PARTID_XUSBA = 20, - POWER_PARTID_XUSBB = 21, - POWER_PARTID_XUSBC = 22, - POWER_PARTID_VIC = 23, - POWER_PARTID_IRAM = 24, - POWER_PARTID_NVDEC = 25, - POWER_PARTID_NVJPG = 26, - POWER_PARTID_APE = 27, - POWER_PARTID_DFD = 28, - POWER_PARTID_VE2 = 29, -}; - -struct tegra_pmc_regs { - vu32 cntrl; - vu32 sec_disable; - vu32 pmc_swrst; - vu32 wake_mask; - vu32 wake_lvl; - vu32 wake_status; - vu32 sw_wake_status; - vu32 dpd_pads_oride; - vu32 dpd_sample; - vu32 dpd_enable; - vu32 pwrgate_timer_off; - vu32 clamp_status; - vu32 pwrgate_toggle; - vu32 remove_clamping_cmd; - vu32 pwrgate_status; - vu32 pwrgood_timer; - vu32 blink_timer; - vu32 no_iopower; - vu32 pwr_det; - vu32 pwr_det_latch; - vu32 scratch0; - vu32 scratch1; - vu32 scratch2; - vu32 scratch3; - vu32 scratch4; - vu32 scratch5; - vu32 scratch6; - vu32 scratch7; - vu32 scratch8; - vu32 scratch9; - vu32 scratch10; - vu32 scratch11; - vu32 scratch12; - vu32 scratch13; - vu32 scratch14; - vu32 scratch15; - vu32 scratch16; - vu32 scratch17; - vu32 scratch18; - vu32 scratch19; - vu32 odmdata; - vu32 scratch21; - vu32 scratch22; - vu32 scratch23; - vu32 secure_scratch0; - vu32 secure_scratch1; - vu32 secure_scratch2; - vu32 secure_scratch3; - vu32 secure_scratch4; - vu32 secure_scratch5; - vu32 cpupwrgood_timer; - vu32 cpupwroff_timer; - vu32 pg_mask; - vu32 pg_mask_1; - vu32 auto_wake_lvl; - vu32 auto_wake_lvl_mask; - vu32 wake_delay; - vu32 pwr_det_val; - vu32 ddr_pwr; - vu32 usb_debounce_del; - vu32 usb_a0; - vu32 crypto_op; - vu32 pllp_wb0_override; - vu32 scratch24; - vu32 scratch25; - vu32 scratch26; - vu32 scratch27; - vu32 scratch28; - vu32 scratch29; - vu32 scratch30; - vu32 scratch31; - vu32 scratch32; - vu32 scratch33; - vu32 scratch34; - vu32 scratch35; - vu32 scratch36; - vu32 scratch37; - vu32 scratch38; - vu32 scratch39; - vu32 scratch40; - vu32 scratch41; - vu32 scratch42; - vu32 bondout_mirror[3]; - vu32 sys_33v_en; - vu32 bondout_mirror_access; - vu32 gate; - vu32 wake2_mask; - vu32 wake2_lvl; - vu32 wake2_status; - vu32 sw_wake2_status; - vu32 auto_wake2_lvl_mask; - vu32 pg_mask_2; - vu32 pg_mask_ce1; - vu32 pg_mask_ce2; - vu32 pg_mask_ce3; - vu32 pwrgate_timer_ce[7]; - vu32 pcx_edpd_cntrl; - vu32 osc_edpd_over; - vu32 clk_out_cntrl; - vu32 sata_pwrgt; - vu32 sensor_ctrl; - vu32 rst_status; - vu32 io_dpd_req; - vu32 io_dpd_status; - vu32 io_dpd2_req; - vu32 io_dpd2_status; - vu32 sel_dpd_tim; - vu32 vddp_sel; - vu32 ddr_cfg; - vu32 e_no_vttgen; - u8 _rsv0[4]; - vu32 pllm_wb0_override_freq; - vu32 test_pwrgate; - vu32 pwrgate_timer_mult; - vu32 dis_sel_dpd; - vu32 utmip_uhsic_triggers; - vu32 utmip_uhsic_saved_state; - vu32 utmip_pad_cfg; - vu32 utmip_term_pad_cfg; - vu32 utmip_uhsic_sleep_cfg; - vu32 utmip_uhsic_sleepwalk_cfg; - vu32 utmip_sleepwalk_p[3]; - vu32 uhsic_sleepwalk_p0; - vu32 utmip_uhsic_status; - vu32 utmip_uhsic_fake; - vu32 bondout_mirror3[5 - 3]; - vu32 secure_scratch6; - vu32 secure_scratch7; - vu32 scratch43; - vu32 scratch44; - vu32 scratch45; - vu32 scratch46; - vu32 scratch47; - vu32 scratch48; - vu32 scratch49; - vu32 scratch50; - vu32 scratch51; - vu32 scratch52; - vu32 scratch53; - vu32 scratch54; - vu32 scratch55; - vu32 scratch0_eco; - vu32 por_dpd_ctrl; - vu32 scratch2_eco; - vu32 utmip_uhsic_line_wakeup; - vu32 utmip_bias_master_cntrl; - vu32 utmip_master_config; - vu32 td_pwrgate_inter_part_timer; - vu32 utmip_uhsic2_triggers; - vu32 utmip_uhsic2_saved_state; - vu32 utmip_uhsic2_sleep_cfg; - vu32 utmip_uhsic2_sleepwalk_cfg; - vu32 uhsic2_sleepwalk_p1; - vu32 utmip_uhsic2_status; - vu32 utmip_uhsic2_fake; - vu32 utmip_uhsic2_line_wakeup; - vu32 utmip_master2_config; - vu32 utmip_uhsic_rpd_cfg; - vu32 pg_mask_ce0; - vu32 pg_mask3[5 - 3]; - vu32 pllm_wb0_override2; - vu32 tsc_mult; - vu32 cpu_vsense_override; - vu32 glb_amap_cfg; - vu32 sticky_bits; - vu32 sec_disable2; - vu32 weak_bias; - vu32 reg_short; - vu32 pg_mask_andor; - u8 _rsv1[0x2c]; - vu32 secure_scratch8; /* offset 0x300 */ - vu32 secure_scratch9; - vu32 secure_scratch10; - vu32 secure_scratch11; - vu32 secure_scratch12; - vu32 secure_scratch13; - vu32 secure_scratch14; - vu32 secure_scratch15; - vu32 secure_scratch16; - vu32 secure_scratch17; - vu32 secure_scratch18; - vu32 secure_scratch19; - vu32 secure_scratch20; - vu32 secure_scratch21; - vu32 secure_scratch22; - vu32 secure_scratch23; - vu32 secure_scratch24; - vu32 secure_scratch25; - vu32 secure_scratch26; - vu32 secure_scratch27; - vu32 secure_scratch28; - vu32 secure_scratch29; - vu32 secure_scratch30; - vu32 secure_scratch31; - vu32 secure_scratch32; - vu32 secure_scratch33; - vu32 secure_scratch34; - vu32 secure_scratch35; - vu32 secure_scratch36; - vu32 secure_scratch37; - vu32 secure_scratch38; - vu32 secure_scratch39; - vu32 secure_scratch40; - vu32 secure_scratch41; - vu32 secure_scratch42; - vu32 secure_scratch43; - vu32 secure_scratch44; - vu32 secure_scratch45; - vu32 secure_scratch46; - vu32 secure_scratch47; - vu32 secure_scratch48; - vu32 secure_scratch49; - vu32 secure_scratch50; - vu32 secure_scratch51; - vu32 secure_scratch52; - vu32 secure_scratch53; - vu32 secure_scratch54; - vu32 secure_scratch55; - vu32 secure_scratch56; - vu32 secure_scratch57; - vu32 secure_scratch58; - vu32 secure_scratch59; - vu32 secure_scratch60; - vu32 secure_scratch61; - vu32 secure_scratch62; - vu32 secure_scratch63; - vu32 secure_scratch64; - vu32 secure_scratch65; - vu32 secure_scratch66; - vu32 secure_scratch67; - vu32 secure_scratch68; - vu32 secure_scratch69; - vu32 secure_scratch70; - vu32 secure_scratch71; - vu32 secure_scratch72; - vu32 secure_scratch73; - vu32 secure_scratch74; - vu32 secure_scratch75; - vu32 secure_scratch76; - vu32 secure_scratch77; - vu32 secure_scratch78; - vu32 secure_scratch79; - vu32 _rsv0x420[8]; - vu32 cntrl2; /* 0x440 */ - vu32 _rsv0x444[2]; - vu32 event_counter; /* 0x44C */ - vu32 fuse_control; - vu32 scratch1_eco; - vu32 _rsv0x458[1]; - vu32 io_dpd3_req; /* 0x45C */ - vu32 io_dpd3_status; - vu32 io_dpd4_req; - vu32 io_dpd4_status; - vu32 _rsv0x46C[30]; - vu32 ddr_cntrl; /* 0x4E4 */ - vu32 _rsv0x4E8[70]; - vu32 scratch56; /* 0x600 */ - vu32 scratch57; - vu32 scratch58; - vu32 scratch59; - vu32 scratch60; - vu32 scratch61; - vu32 scratch62; - vu32 scratch63; - vu32 scratch64; - vu32 scratch65; - vu32 scratch66; - vu32 scratch67; - vu32 scratch68; - vu32 scratch69; - vu32 scratch70; - vu32 scratch71; - vu32 scratch72; - vu32 scratch73; - vu32 scratch74; - vu32 scratch75; - vu32 scratch76; - vu32 scratch77; - vu32 scratch78; - vu32 scratch79; - vu32 scratch80; - vu32 scratch81; - vu32 scratch82; - vu32 scratch83; - vu32 scratch84; - vu32 scratch85; - vu32 scratch86; - vu32 scratch87; - vu32 scratch88; - vu32 scratch89; - vu32 scratch90; - vu32 scratch91; - vu32 scratch92; - vu32 scratch93; - vu32 scratch94; - vu32 scratch95; - vu32 scratch96; - vu32 scratch97; - vu32 scratch98; - vu32 scratch99; - vu32 scratch100; - vu32 scratch101; - vu32 scratch102; - vu32 scratch103; - vu32 scratch104; - vu32 scratch105; - vu32 scratch106; - vu32 scratch107; - vu32 scratch108; - vu32 scratch109; - vu32 scratch110; - vu32 scratch111; - vu32 scratch112; - vu32 scratch113; - vu32 scratch114; - vu32 scratch115; - vu32 scratch116; - vu32 scratch117; - vu32 scratch118; - vu32 scratch119; - vu32 scratch120; /* 0x700 */ - vu32 scratch121; - vu32 scratch122; - vu32 scratch123; - vu32 scratch124; - vu32 scratch125; - vu32 scratch126; - vu32 scratch127; - vu32 scratch128; - vu32 scratch129; - vu32 scratch130; - vu32 scratch131; - vu32 scratch132; - vu32 scratch133; - vu32 scratch134; - vu32 scratch135; - vu32 scratch136; - vu32 scratch137; - vu32 scratch138; - vu32 scratch139; - vu32 scratch140; - vu32 scratch141; - vu32 scratch142; - vu32 scratch143; - vu32 scratch144; - vu32 scratch145; - vu32 scratch146; - vu32 scratch147; - vu32 scratch148; - vu32 scratch149; - vu32 scratch150; - vu32 scratch151; - vu32 scratch152; - vu32 scratch153; - vu32 scratch154; - vu32 scratch155; - vu32 scratch156; - vu32 scratch157; - vu32 scratch158; - vu32 scratch159; - vu32 scratch160; - vu32 scratch161; - vu32 scratch162; - vu32 scratch163; - vu32 scratch164; - vu32 scratch165; - vu32 scratch166; - vu32 scratch167; - vu32 scratch168; - vu32 scratch169; - vu32 scratch170; - vu32 scratch171; - vu32 scratch172; - vu32 scratch173; - vu32 scratch174; - vu32 scratch175; - vu32 scratch176; - vu32 scratch177; - vu32 scratch178; - vu32 scratch179; - vu32 scratch180; - vu32 scratch181; - vu32 scratch182; - vu32 scratch183; - vu32 scratch184; - vu32 scratch185; - vu32 scratch186; - vu32 scratch187; - vu32 scratch188; - vu32 scratch189; - vu32 scratch190; - vu32 scratch191; - vu32 scratch192; - vu32 scratch193; - vu32 scratch194; - vu32 scratch195; - vu32 scratch196; - vu32 scratch197; - vu32 scratch198; - vu32 scratch199; - vu32 scratch200; - vu32 scratch201; - vu32 scratch202; - vu32 scratch203; - vu32 scratch204; - vu32 scratch205; - vu32 scratch206; - vu32 scratch207; - vu32 scratch208; - vu32 scratch209; - vu32 scratch210; - vu32 scratch211; - vu32 scratch212; - vu32 scratch213; - vu32 scratch214; - vu32 scratch215; - vu32 scratch216; - vu32 scratch217; - vu32 scratch218; - vu32 scratch219; - vu32 scratch220; - vu32 scratch221; - vu32 scratch222; - vu32 scratch223; - vu32 scratch224; - vu32 scratch225; - vu32 scratch226; - vu32 scratch227; - vu32 scratch228; - vu32 scratch229; - vu32 scratch230; - vu32 scratch231; - vu32 scratch232; - vu32 scratch233; - vu32 scratch234; - vu32 scratch235; - vu32 scratch236; - vu32 scratch237; - vu32 scratch238; - vu32 scratch239; - vu32 scratch240; - vu32 scratch241; - vu32 scratch242; - vu32 scratch243; - vu32 scratch244; - vu32 scratch245; - vu32 scratch246; - vu32 scratch247; - vu32 scratch248; - vu32 scratch249; - vu32 scratch250; - vu32 scratch251; - vu32 scratch252; - vu32 scratch253; - vu32 scratch254; - vu32 scratch255; - vu32 scratch256; - vu32 scratch257; - vu32 scratch258; - vu32 scratch259; - vu32 scratch260; - vu32 scratch261; - vu32 scratch262; - vu32 scratch263; - vu32 scratch264; - vu32 scratch265; - vu32 scratch266; - vu32 scratch267; - vu32 scratch268; - vu32 scratch269; - vu32 scratch270; - vu32 scratch271; - vu32 scratch272; - vu32 scratch273; - vu32 scratch274; - vu32 scratch275; - vu32 scratch276; - vu32 scratch277; - vu32 scratch278; - vu32 scratch279; - vu32 scratch280; - vu32 scratch281; - vu32 scratch282; - vu32 scratch283; - vu32 scratch284; - vu32 scratch285; - vu32 scratch286; - vu32 scratch287; - vu32 scratch288; - vu32 scratch289; - vu32 scratch290; - vu32 scratch291; - vu32 scratch292; - vu32 scratch293; - vu32 scratch294; - vu32 scratch295; - vu32 scratch296; - vu32 scratch297; - vu32 scratch298; - vu32 scratch299; /* 0x9CC */ - vu32 _rsv0x9D0[50]; - vu32 secure_scratch80; /* 0xa98 */ - vu32 secure_scratch81; - vu32 secure_scratch82; - vu32 secure_scratch83; - vu32 secure_scratch84; - vu32 secure_scratch85; - vu32 secure_scratch86; - vu32 secure_scratch87; - vu32 secure_scratch88; - vu32 secure_scratch89; - vu32 secure_scratch90; - vu32 secure_scratch91; - vu32 secure_scratch92; - vu32 secure_scratch93; - vu32 secure_scratch94; - vu32 secure_scratch95; - vu32 secure_scratch96; - vu32 secure_scratch97; - vu32 secure_scratch98; - vu32 secure_scratch99; - vu32 secure_scratch100; - vu32 secure_scratch101; - vu32 secure_scratch102; - vu32 secure_scratch103; - vu32 secure_scratch104; - vu32 secure_scratch105; - vu32 secure_scratch106; - vu32 secure_scratch107; - vu32 secure_scratch108; - vu32 secure_scratch109; - vu32 secure_scratch110; - vu32 secure_scratch111; - vu32 secure_scratch112; - vu32 secure_scratch113; - vu32 secure_scratch114; - vu32 secure_scratch115; - vu32 secure_scratch116; - vu32 secure_scratch117; - vu32 secure_scratch118; - vu32 secure_scratch119; -}; - -enum { - PMC_RST_STATUS_SOURCE_MASK = 0x7, - PMC_RST_STATUS_SOURCE_POR = 0x0, - PMC_RST_STATUS_SOURCE_WATCHDOG = 0x1, - PMC_RST_STATUS_SOURCE_SENSOR = 0x2, - PMC_RST_STATUS_SOURCE_SW_MAIN = 0x3, - PMC_RST_STATUS_SOURCE_LP0 = 0x4, - PMC_RST_STATUS_NUM_SOURCES = 0x5, -}; - -enum { - PMC_PWRGATE_TOGGLE_PARTID_MASK = 0x1f, - PMC_PWRGATE_TOGGLE_PARTID_SHIFT = 0, - PMC_PWRGATE_TOGGLE_START = 0x1 << 8 -}; - -enum { - PMC_CNTRL_KBC_CLK_DIS = 0x1 << 0, - PMC_CNTRL_RTC_CLK_DIS = 0x1 << 1, - PMC_CNTRL_RTC_RST = 0x1 << 2, - PMC_CNTRL_KBC_RST = 0x1 << 3, - PMC_CNTRL_MAIN_RST = 0x1 << 4, - PMC_CNTRL_LATCHWAKE_EN = 0x1 << 5, - PMC_CNTRL_GLITCHDET_DIS = 0x1 << 6, - PMC_CNTRL_BLINK_EN = 0x1 << 7, - PMC_CNTRL_PWRREQ_POLARITY = 0x1 << 8, - PMC_CNTRL_PWRREQ_OE = 0x1 << 9, - PMC_CNTRL_SYSCLK_POLARITY = 0x1 << 10, - PMC_CNTRL_SYSCLK_OE = 0x1 << 11, - PMC_CNTRL_PWRGATE_DIS = 0x1 << 12, - PMC_CNTRL_AOINIT = 0x1 << 13, - PMC_CNTRL_SIDE_EFFECT_LP0 = 0x1 << 14, - PMC_CNTRL_CPUPWRREQ_POLARITY = 0x1 << 15, - PMC_CNTRL_CPUPWRREQ_OE = 0x1 << 16, - PMC_CNTRL_INTR_POLARITY = 0x1 << 17, - PMC_CNTRL_FUSE_OVERRIDE = 0x1 << 18, - PMC_CNTRL_CPUPWRGOOD_EN = 0x1 << 19, - PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT = 20, - PMC_CNTRL_CPUPWRGOOD_SEL_MASK = - 0x3 << PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT -}; - -enum { - PMC_DDR_PWR_EMMC_MASK = 1 << 1, - PMC_DDR_PWR_VAL_MASK = 1 << 0, -}; - -enum { - PMC_DDR_CFG_PKG_MASK = 1 << 0, - PMC_DDR_CFG_IF_MASK = 1 << 1, - PMC_DDR_CFG_XM0_RESET_TRI_MASK = 1 << 12, - PMC_DDR_CFG_XM0_RESET_DPDIO_MASK = 1 << 13, -}; - -enum { - PMC_NO_IOPOWER_MEM_MASK = 1 << 7, - PMC_NO_IOPOWER_MEM_COMP_MASK = 1 << 16, -}; - -enum { - PMC_POR_DPD_CTRL_MEM0_ADDR0_CLK_SEL_DPD_MASK = 1 << 0, - PMC_POR_DPD_CTRL_MEM0_ADDR1_CLK_SEL_DPD_MASK = 1 << 1, - PMC_POR_DPD_CTRL_MEM0_HOLD_CKE_LOW_OVR_MASK = 1 << 31, -}; - -enum { - PMC_CNTRL2_HOLD_CKE_LOW_EN = 0x1 << 12 -}; - -enum { - PMC_OSC_EDPD_OVER_XOFS_SHIFT = 1, - PMC_OSC_EDPD_OVER_XOFS_MASK = - 0x3f << PMC_OSC_EDPD_OVER_XOFS_SHIFT -}; - -enum { - PMC_CMD_HOLD_LOW_BR00_11_MASK = 0x0007FF80, - DPD_OFF = 1 << 30, - DPD_ON = 2 << 30, -}; - -enum { - PMC_GPIO_RAIL_AO_SHIFT = 21, - PMC_GPIO_RAIL_AO_MASK = (1 << PMC_GPIO_RAIL_AO_SHIFT), - PMC_GPIO_RAIL_AO_DISABLE = (0 << PMC_GPIO_RAIL_AO_SHIFT), - PMC_GPIO_RAIL_AO_ENABLE = (1 << PMC_GPIO_RAIL_AO_SHIFT), - - PMC_AUDIO_RAIL_AO_SHIFT = 18, - PMC_AUDIO_RAIL_AO_MASK = (1 << PMC_AUDIO_RAIL_AO_SHIFT), - PMC_AUDIO_RAIL_AO_DISABLE = (0 << PMC_AUDIO_RAIL_AO_SHIFT), - PMC_AUDIO_RAIL_AO_ENABLE = (1 << PMC_AUDIO_RAIL_AO_SHIFT), - - PMC_SDMMC3_RAIL_AO_SHIFT = 13, - PMC_SDMMC3_RAIL_AO_MASK = (1 << PMC_SDMMC3_RAIL_AO_SHIFT), - PMC_SDMMC3_RAIL_AO_DISABLE = (0 << PMC_SDMMC3_RAIL_AO_SHIFT), - PMC_SDMMC3_RAIL_AO_ENABLE = (1 << PMC_SDMMC3_RAIL_AO_SHIFT), -}; - -/*! PMC registers. */ -#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 -#define APBDEV_PMC_PWRGATE_STATUS 0x38 -#define APBDEV_PMC_NO_IOPOWER 0x44 -#define APBDEV_PMC_SCRATCH0 0x50 -#define APBDEV_PMC_SCRATCH1 0x54 -#define APBDEV_PMC_SCRATCH20 0xA0 -#define APBDEV_PMC_PWR_DET_VAL 0xE4 -#define APBDEV_PMC_DDR_PWR 0xE8 -#define APBDEV_PMC_CRYPTO_OP 0xF4 -#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 -#define APBDEV_PMC_IO_DPD_REQ 0x1B8 -#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 -#define APBDEV_PMC_VDDP_SEL 0x1CC -#define APBDEV_PMC_TSC_MULT 0x2B4 -#define APBDEV_PMC_REG_SHORT 0x2CC -#define APBDEV_PMC_WEAK_BIAS 0x2C8 -#define APBDEV_PMC_SECURE_SCRATCH21 0x334 -#define APBDEV_PMC_SECURE_SCRATCH32 0x360 -#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 -#define APBDEV_PMC_CNTRL2 0x440 -#define APBDEV_PMC_IO_DPD4_REQ 0x464 -#define APBDEV_PMC_DDR_CNTRL 0x4E4 -#define APBDEV_PMC_SCRATCH188 0x810 -#define APBDEV_PMC_SCRATCH190 0x818 -#define APBDEV_PMC_SCRATCH200 0x840 -#define APBDEV_PMC_SCRATCH49 0x244 -#endif diff --git a/ariane/src/hwinit/sdmmc_driver.c b/ariane/src/hwinit/sdmmc_driver.c deleted file mode 100644 index a02fef1..0000000 --- a/ariane/src/hwinit/sdmmc_driver.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include - -#include "sdmmc.h" -#include "timer.h" -#include "clock.h" -#include "mmc.h" -#include "max7762x.h" -#include "t210.h" -#include "pmc.h" -#include "pinmux.h" -#include "gpio.h" - -#ifdef SDMMCDRIVER_DEBUGGING -#include "lib/printk.h" -#define DPRINTF(...) dbg_print(__VA_ARGS__) -#else -#define DPRINTF(...) -#endif - -/*! SCMMC controller base addresses. */ -static const u32 _sdmmc_bases[4] = { - 0x700B0000, - 0x700B0200, - 0x700B0400, - 0x700B0600, -}; - -int sdmmc_get_voltage(sdmmc_t *sdmmc) -{ - u32 p = sdmmc->regs->pwrcon; - if (!(p & TEGRA_MMC_PWRCTL_SD_BUS_POWER)) - return SDMMC_POWER_OFF; - if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8) - return SDMMC_POWER_1_8; - if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3) - return SDMMC_POWER_3_3; - return -1; -} - -static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) -{ - u8 pwr = (power == SDMMC_POWER_1_8) ? TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 : TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; - - switch (power) - { - case SDMMC_POWER_OFF: - sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; - break; - case SDMMC_POWER_1_8: - case SDMMC_POWER_3_3: - sdmmc->regs->pwrcon = pwr; - break; - default: - return 0; - } - - if (power != SDMMC_POWER_OFF) - { - pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; - sdmmc->regs->pwrcon = pwr; - } - - return 1; -} - -u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) -{ - u32 h = sdmmc->regs->hostctl; - if (h & TEGRA_MMC_HOSTCTL_8BIT) - return SDMMC_BUS_WIDTH_8; - if (h & TEGRA_MMC_HOSTCTL_4BIT) - return SDMMC_BUS_WIDTH_4; - return SDMMC_BUS_WIDTH_1; -} - -void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) -{ - if (bus_width == SDMMC_BUS_WIDTH_1) - sdmmc->regs->hostctl &= ~(TEGRA_MMC_HOSTCTL_4BIT | TEGRA_MMC_HOSTCTL_8BIT); - else if (bus_width == SDMMC_BUS_WIDTH_4) - { - sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_4BIT; - sdmmc->regs->hostctl &= ~TEGRA_MMC_HOSTCTL_8BIT; - } - else if (bus_width == SDMMC_BUS_WIDTH_8) - sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_8BIT; -} - -void sdmmc_get_venclkctl(sdmmc_t *sdmmc) -{ - sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; - sdmmc->venclkctl_set = 1; -} - -static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) -{ - u32 tap_val = 0; - - if (id == 4) - sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800; - sdmmc->regs->field_1C0 &= 0xFFFDFFFF; - if (id == 4) - { - if (!sdmmc->venclkctl_set) - return 0; - tap_val = sdmmc->venclkctl_tap; - } - else - { - static const u32 tap_values[] = { 4, 0, 3, 0 }; - tap_val = tap_values[sdmmc->id]; - } - sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); - - return 1; -} - -static int _sdmmc_get_clkcon(sdmmc_t *sdmmc) -{ - return sdmmc->regs->clkcon; -} - -static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) -{ - _sdmmc_get_clkcon(sdmmc); - if (sdmmc->id == SDMMC_4) - *(vu32 *)0x70000AB4 = ((*(vu32 *)0x70000AB4) & 0x3FFC) | 0x1040; - //TODO: load standard values for other controllers, can depend on power. -} - -static int _sdmmc_wait_type4(sdmmc_t *sdmmc) -{ - int res = 1, should_disable_sd_clock = 0; - - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - { - should_disable_sd_clock = 1; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - sdmmc->regs->field_1B0 |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 5; - while (sdmmc->regs->field_1B0 & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - res = 0; - goto out; - } - } - - timeout = get_tmr_ms() + 10; - while (sdmmc->regs->field_1BC & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - res = 0; - goto out; - } - } - -out:; - if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - return res; -} - -int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) -{ - //Disable the SD clock if it was enabled, and reenable it later. - int should_enable_sd_clock = 0; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = 1; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - _sdmmc_config_ven_ceata_clk(sdmmc, type); - - switch (type) - { - case 0: - case 1: - case 5: - case 6: - sdmmc->regs->hostctl &= 0xFB; //Should this be 0xFFFB (~4) ? - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 2: - case 7: - sdmmc->regs->hostctl |= 4; - sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; - break; - case 3: - case 11: - case 13: - case 14: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 4: - //Non standard - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 8: - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - case 10: - //T210 Errata for SDR50, the host must be set to SDR104. - sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; - break; - } - - _sdmmc_get_clkcon(sdmmc); - - u32 tmp; - u16 divisor; - clock_sdmmc_get_params(&tmp, &divisor, type); - clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp); - sdmmc->divisor = (tmp + divisor - 1) / divisor; - - //if divisor != 1 && divisor << 31 -> error - - u16 div = divisor >> 1; - divisor = 0; - if (div > 0xFF) - divisor = div >> 8; - sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6); - - //Enable the SD clock again. - if (should_enable_sd_clock) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - - if (type == 4) - return _sdmmc_wait_type4(sdmmc); - return 1; -} - -static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc) -{ - if (!sdmmc->no_sd) - { - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - sdmmc->sd_clock_enabled = 1; -} - -static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) -{ - sdmmc->sd_clock_enabled = 0; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; -} - -void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd) -{ - sdmmc->no_sd = no_sd; - if (no_sd) - { - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - return; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - return; - } - if (sdmmc->sd_clock_enabled) - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; -} - -static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) -{ - switch (type) - { - case SDMMC_RSP_TYPE_1: - case SDMMC_RSP_TYPE_3: - case SDMMC_RSP_TYPE_4: - case SDMMC_RSP_TYPE_5: - if (size < 4) - return 0; - rsp[0] = sdmmc->regs->rspreg0; - break; - case SDMMC_RSP_TYPE_2: - if (size < 0x10) - return 0; - // CRC is stripped, so shifting is needed. - u32 tempreg; - for (int i = 0; i < 4; i++) - { - switch(i) - { - case 0: - tempreg = sdmmc->regs->rspreg3; - break; - case 1: - tempreg = sdmmc->regs->rspreg2; - break; - case 2: - tempreg = sdmmc->regs->rspreg1; - break; - case 3: - tempreg = sdmmc->regs->rspreg0; - break; - } - rsp[i] = tempreg << 8; - - if (i != 0) - rsp[i - 1] |= (tempreg >> 24) & 0xFF; - } - break; - default: - return 0; - break; - } - - return 1; -} - -int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) -{ - if (!rsp || sdmmc->expected_rsp_type != type) - return 0; - - switch (type) - { - case SDMMC_RSP_TYPE_1: - case SDMMC_RSP_TYPE_3: - case SDMMC_RSP_TYPE_4: - case SDMMC_RSP_TYPE_5: - if (size < 4) - return 0; - rsp[0] = sdmmc->rsp[0]; - break; - case SDMMC_RSP_TYPE_2: - if (size < 0x10) - return 0; - rsp[0] = sdmmc->rsp[0]; - rsp[1] = sdmmc->rsp[1]; - rsp[2] = sdmmc->rsp[2]; - rsp[3] = sdmmc->rsp[3]; - break; - default: - return 0; - break; - } - - return 1; -} - -static void _sdmmc_reset(sdmmc_t *sdmmc) -{ - sdmmc->regs->swrst |= TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE; - _sdmmc_get_clkcon(sdmmc); - u32 timeout = get_tmr_ms() + 2000; - while ( (sdmmc->regs->swrst << 29 >> 30) && get_tmr_ms() < timeout) {} -} - -static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) -{ - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) //CMD inhibit. - { - if (get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - } - - if (wait_dat) - { - timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) //DAT inhibit. - { - if (get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - } - } - - return 1; -} - -static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc) -{ - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level. - { - if (get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - } - - return 1; -} - -static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) -{ - switch (sdmmc_get_bus_width(sdmmc)) - { - case SDMMC_BUS_WIDTH_1: - return 0; - break; - case SDMMC_BUS_WIDTH_4: - sdmmc->regs->blksize = 0x40; - break; - case SDMMC_BUS_WIDTH_8: - sdmmc->regs->blksize = 0x80; - break; - } - sdmmc->regs->blkcnt = 1; - sdmmc->regs->trnmod = TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; - return 1; -} - -static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, int is_data_present) -{ - u16 cmdflags = 0; - - switch (cmd->rsp_type) - { - case SDMMC_RSP_TYPE_0: - break; - case SDMMC_RSP_TYPE_1: - case SDMMC_RSP_TYPE_4: - case SDMMC_RSP_TYPE_5: - if (cmd->check_busy) - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY | - TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; - else - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 | - TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; - break; - case SDMMC_RSP_TYPE_2: - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 | - TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; - break; - case SDMMC_RSP_TYPE_3: - cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48; - break; - default: - return 0; - break; - } - - if (is_data_present) - cmdflags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER; - sdmmc->regs->argument = cmd->arg; - sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags; - - return 1; -} - -static void _sdmmc_parse_cmd_48(sdmmc_t *sdmmc, u32 cmd) -{ - sdmmc_cmd_t cmdbuf; - cmdbuf.cmd = cmd; - cmdbuf.arg = 0; - cmdbuf.rsp_type = SDMMC_RSP_TYPE_1; - cmdbuf.check_busy = 0; - _sdmmc_parse_cmdbuf(sdmmc, &cmdbuf, 1); -} - -static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) -{ - if (sdmmc->no_sd) - return 0; - if (!_sdmmc_wait_prnsts_type0(sdmmc, 1)) - return 0; - - _sdmmc_setup_read_small_block(sdmmc); - sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY; - sdmmc->regs->norintsts = sdmmc->regs->norintsts; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_parse_cmd_48(sdmmc, cmd); - _sdmmc_get_clkcon(sdmmc); - usleep(1); - _sdmmc_reset(sdmmc); - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_us() + 5000; - while (get_tmr_us() < timeout) - { - if (sdmmc->regs->norintsts & 0x20) - { - sdmmc->regs->norintsts = 0x20; - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); - return 1; - } - } - _sdmmc_reset(sdmmc); - sdmmc->regs->norintstsen &= 0xFFDF; - _sdmmc_get_clkcon(sdmmc); - usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); - return 0; -} - -int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) -{ - u32 max = 0, flag = 0; - - sdmmc->regs->field_1C4 = 0; - switch (type) - { - case 3: - case 4: - case 11: - max = 0x80; - flag = 0x4000; - break; - case 10: - case 13: - case 14: - max = 0x100; - flag = 0x8000; - break; - default: - return 0; - } - - sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag; - sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40; - sdmmc->regs->field_1C0 |= 0x20000; - sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; - - for (u32 i = 0; i < max; i++) - { - _sdmmc_config_tuning_once(sdmmc, cmd); - if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) - break; - } - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) - return 1; - return 0; -} - -static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) -{ - //Enable internal clock and wait till it is stable. - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) - { - if (get_tmr_ms() > timeout) - return 0; - } - - sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT; - sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; - - if (!(sdmmc->regs->capareg & 0x10000000)) - return 0; - - sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; - sdmmc->regs->hostctl &= 0xE7; - sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE; - - return 1; -} - -static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) -{ - u32 off_pd = 0; - u32 off_pu = 0; - - switch (sdmmc->id) - { - case SDMMC_2: - case SDMMC_4: - if (power != SDMMC_POWER_1_8) - return 0; - off_pd = 5; - off_pu = 5; - break; - case SDMMC_1: - case SDMMC_3: - if (power == SDMMC_POWER_1_8) - { - off_pd = 123; - off_pu = 123; - } - else if (power == SDMMC_POWER_3_3) - { - off_pd = 125; - off_pu = 0; - } - else - return 0; - break; - } - - sdmmc->regs->autocalcfg = (((sdmmc->regs->autocalcfg & 0xFFFF80FF) | (off_pd << 8)) >> 7 << 7) | off_pu; - return 1; -} - -static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) -{ - int should_enable_sd_clock = 0; - if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) - { - should_enable_sd_clock = 1; - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - } - - if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000)) - { - sdmmc->regs->sdmemcmppadctl |= 0x80000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - } - - sdmmc->regs->autocalcfg |= 0xA0000000; - _sdmmc_get_clkcon(sdmmc); - usleep(1); - - u32 timeout = get_tmr_ms() + 10; - while (sdmmc->regs->autocalcfg & 0x80000000) - { - if (get_tmr_ms() > timeout) - { - //In case autocalibration fails, we load suggested standard values. - _sdmmc_pad_config_fallback(sdmmc, power); - sdmmc->regs->autocalcfg &= 0xDFFFFFFF; - break; - } - } - - sdmmc->regs->sdmemcmppadctl &= 0x7FFFFFFF; - - if(should_enable_sd_clock) - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; -} - -static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) -{ - sdmmc->regs->norintstsen |= 0xB; - sdmmc->regs->errintstsen |= 0x17F; - sdmmc->regs->norintsts = sdmmc->regs->norintsts; - sdmmc->regs->errintsts = sdmmc->regs->errintsts; -} - -static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) -{ - sdmmc->regs->errintstsen &= 0xFE80; - sdmmc->regs->norintstsen &= 0xFFF4; -} - -static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) -{ - u16 norintsts = sdmmc->regs->norintsts; - u16 errintsts = sdmmc->regs->errintsts; - - DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts); - - if (pout) - *pout = norintsts; - - //Check for error interrupt. - if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) - { - sdmmc->regs->errintsts = errintsts; - return SDMMC_MASKINT_ERROR; - } - else if (norintsts & mask) - { - sdmmc->regs->norintsts = norintsts & mask; - return SDMMC_MASKINT_MASKED; - } - - return SDMMC_MASKINT_NOERROR; -} - -static int _sdmmc_wait_request(sdmmc_t *sdmmc) -{ - _sdmmc_get_clkcon(sdmmc); - - u32 timeout = get_tmr_ms() + 2000; - while (1) - { - int res = _sdmmc_check_mask_interrupt(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE); - if (res == SDMMC_MASKINT_MASKED) - break; - if (res != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) - { - _sdmmc_reset(sdmmc); - return 0; - } - } - - return 1; -} - -static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) -{ - sdmmc_cmd_t cmd; - - if (!_sdmmc_wait_prnsts_type0(sdmmc, 0)) - return 0; - - _sdmmc_enable_interrupts(sdmmc); - cmd.cmd = MMC_STOP_TRANSMISSION; - cmd.arg = 0; - cmd.rsp_type = SDMMC_RSP_TYPE_1; - cmd.check_busy = 1; - _sdmmc_parse_cmdbuf(sdmmc, &cmd, 0); - int res = _sdmmc_wait_request(sdmmc); - _sdmmc_mask_interrupts(sdmmc); - - if (!res) - return 0; - - _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); - return _sdmmc_wait_prnsts_type1(sdmmc); -} - -int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) -{ - if (!sdmmc->sd_clock_enabled) - return 0; - - int should_disable_sd_clock = 0; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - { - should_disable_sd_clock = 1; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - - return res; -} - -static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) -{ - if (!req->blksize || !req->num_sectors) - return 0; - - u32 blkcnt = req->num_sectors; - if (blkcnt >= 0xFFFF) - blkcnt = 0xFFFF; - u32 admaaddr = (u32)req->buf; - - //Check alignment. - if (admaaddr << 29) - return 0; - - sdmmc->regs->admaaddr = admaaddr; - sdmmc->regs->admaaddr_hi = 0; - - sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000; - - sdmmc->regs->blksize = req->blksize | 0x7000; - sdmmc->regs->blkcnt = blkcnt; - - if (blkcnt_out) - *blkcnt_out = blkcnt; - - u32 trnmode = TEGRA_MMC_TRNMOD_DMA_ENABLE; - if (req->is_multi_block) - trnmode = TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT | - TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE | - TEGRA_MMC_TRNMOD_DMA_ENABLE; - if (!req->is_write) - trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; - if (req->is_auto_cmd12) - trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; - - sdmmc->regs->trnmod = trnmode; - - return 1; -} - -static int _sdmmc_update_dma(sdmmc_t *sdmmc) -{ - u16 blkcnt = 0; - do - { - blkcnt = sdmmc->regs->blkcnt; - u32 timeout = get_tmr_ms() + 1500; - do - { - int res = 0; - while (1) - { - u16 intr = 0; - res = _sdmmc_check_mask_interrupt(sdmmc, &intr, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT); - if (res < 0) - break; - if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) - return 1; //Transfer complete. - if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) - { - //Update DMA. - sdmmc->regs->admaaddr = sdmmc->dma_addr_next; - sdmmc->regs->admaaddr_hi = 0; - sdmmc->dma_addr_next += 0x80000; - } - } - if (res != SDMMC_MASKINT_NOERROR) - { - _sdmmc_reset(sdmmc); - return 0; - } - } while (get_tmr_ms() < timeout); - } while (sdmmc->regs->blkcnt != blkcnt); - - _sdmmc_reset(sdmmc); - return 0; -} - -static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) -{ - int has_req_or_check_busy = req || cmd->check_busy; - if (!_sdmmc_wait_prnsts_type0(sdmmc, has_req_or_check_busy)) - return 0; - - u32 blkcnt = 0; - int is_data_present = 0; - if (req) - { - _sdmmc_config_dma(sdmmc, &blkcnt, req); - _sdmmc_enable_interrupts(sdmmc); - is_data_present = 1; - } - else - { - _sdmmc_enable_interrupts(sdmmc); - is_data_present = 0; - } - - _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); - - int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, - sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); - if (res) - { - if (cmd->rsp_type) - { - sdmmc->expected_rsp_type = cmd->rsp_type; - _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); - } - if (req) - _sdmmc_update_dma(sdmmc); - } - - _sdmmc_mask_interrupts(sdmmc); - - if (res) - { - if (req) - { - if (blkcnt_out) - *blkcnt_out = blkcnt; - if (req->is_auto_cmd12) - sdmmc->rsp3 = sdmmc->regs->rspreg3; - } - - if (cmd->check_busy || req) - return _sdmmc_wait_prnsts_type1(sdmmc); - } - - return res; -} - -static void _sdmmc1_config_pads(u32 padMode) //0 for disabled, 1 for 3.3v, higher for 1.8v (schmitt on) -{ - /* - * Pinmux config: - * DRV_TYPE = DRIVE_2X - * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) - * E_INPUT = ENABLE - * TRISTATE = PASSTHROUGH - * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK - */ - - APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = padMode ? 1 : 0; - u32 config = PINMUX_DRIVE_2X | PINMUX_PARKED; - if (padMode) - config |= PINMUX_INPUT_ENABLE; - else - config |= PINMUX_TRISTATE; - - if (padMode > 1) - config |= PINMUX_SCHMT; - - pinmux_set_config(PINMUX_SDMMC1_CLK_INDEX, config | PINMUX_SDMMC1_CLK_FUNC_SDMMC1); - if (padMode) - config |= PINMUX_PULL_UP; //needed for all except CLK - - pinmux_set_config(PINMUX_SDMMC1_CMD_INDEX, config | PINMUX_SDMMC1_CMD_FUNC_SDMMC1); - pinmux_set_config(PINMUX_SDMMC1_DAT3_INDEX, config | PINMUX_SDMMC1_DAT3_FUNC_SDMMC1); - pinmux_set_config(PINMUX_SDMMC1_DAT2_INDEX, config | PINMUX_SDMMC1_DAT2_FUNC_SDMMC1); - pinmux_set_config(PINMUX_SDMMC1_DAT1_INDEX, config | PINMUX_SDMMC1_DAT1_FUNC_SDMMC1); - pinmux_set_config(PINMUX_SDMMC1_DAT0_INDEX, config | PINMUX_SDMMC1_DAT0_FUNC_SDMMC1); -} - -static int _sdmmc_config_sdmmc1() -{ - usleep(100); //let the card detect stabilize - if(!!gpio_read(GPIO_DECOMPOSE(GPIO_Z1_INDEX))) - return 0; - - //Set SDMMC1 IO clamps to default value before changing voltage - PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); - - //Reset the SDMMC1 IO voltage back to normal - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - - //Configure SDMMC1 pinmux to enabled, 3.3v mode - _sdmmc1_config_pads(1); - - //Let the power to the SD card flow - gpio_write(GPIO_BY_NAME(DMIC3_CLK), GPIO_HIGH); - usleep(1000); - - //For good measure. - APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; - - usleep(1000); - - return 1; -} - -int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd) -{ - if (id > SDMMC_4) - return 0; - - if (id == SDMMC_1) - if (!_sdmmc_config_sdmmc1()) - return 0; - - memset(sdmmc, 0, sizeof(sdmmc_t)); - - sdmmc->regs = (t210_sdmmc_t *)_sdmmc_bases[id]; - sdmmc->id = id; - sdmmc->clock_stopped = 1; - - if (clock_sdmmc_is_not_reset_and_enabled(id)) - { - _sdmmc_sd_clock_disable(sdmmc); - _sdmmc_get_clkcon(sdmmc); - } - - u32 clock; - u16 divisor; - clock_sdmmc_get_params(&clock, &divisor, type); - clock_sdmmc_enable(id, clock); - - sdmmc->clock_stopped = 0; - - //TODO: make this skip-able. - sdmmc->regs->field_1F0 |= 0x80000; - sdmmc->regs->field_1AC &= 0xFFFFFFFB; - static const u32 trim_values[] = { 2, 8, 3, 8 }; - sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24); - sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7; - if (!_sdmmc_autocal_config_offset(sdmmc, power)) - return 0; - _sdmmc_autocal_execute(sdmmc, power); - if (_sdmmc_enable_internal_clock(sdmmc)) - { - sdmmc_set_bus_width(sdmmc, bus_width); - _sdmmc_set_voltage(sdmmc, power); - if (sdmmc_setup_clock(sdmmc, type)) - { - sdmmc_sd_clock_ctrl(sdmmc, no_sd); - _sdmmc_sd_clock_enable(sdmmc); - _sdmmc_get_clkcon(sdmmc); - return 1; - } - return 0; - } - return 0; -} - -void sdmmc_end(sdmmc_t *sdmmc, u32 powerOff) -{ - if (!sdmmc->clock_stopped) - { - _sdmmc_sd_clock_disable(sdmmc); - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); - _sdmmc_get_clkcon(sdmmc); - clock_sdmmc_disable(sdmmc->id); - sdmmc->clock_stopped = 1; - } - - //turn off the power completely if applicable - if (powerOff && sdmmc->id == SDMMC_1) - { - //Turn off the pads - _sdmmc1_config_pads(0); - - //Cut the card's power - gpio_write(GPIO_BY_NAME(DMIC3_CLK), GPIO_LOW); - - //Put the clamps back to the safe value before changing voltage - PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); - //Set the SDMMC1 IO rail back to 3.3v - max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); - } -} - -void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy) -{ - cmdbuf->cmd = cmd; - cmdbuf->arg = arg; - cmdbuf->rsp_type = rsp_type; - cmdbuf->check_busy = check_busy; -} - -int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) -{ - if (!sdmmc->sd_clock_enabled) - return 0; - - //Recalibrate periodically for SDMMC1. - if (sdmmc->id == SDMMC_1 && sdmmc->no_sd) - _sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc)); - - int should_disable_sd_clock = 0; - if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)) - { - should_disable_sd_clock = 1; - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - } - - int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); - usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); - if (should_disable_sd_clock) - sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - - return res; -} - -int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) -{ - if(sdmmc->id != SDMMC_1) - return 0; - - if (!sdmmc_setup_clock(sdmmc, 8)) - return 0; - - _sdmmc_get_clkcon(sdmmc); - - max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); - usleep(1000); //wait for regulator to change voltage - PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12); //re-adjust the clamps for 1.8v operation - _sdmmc1_config_pads(2); //enable schmitt on inputs - - _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); - _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); - _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); - _sdmmc_get_clkcon(sdmmc); - msleep(5); - - if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) - { - sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; - _sdmmc_get_clkcon(sdmmc); - usleep(1000); - if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) - return 1; - } - - return 0; -} diff --git a/ariane/src/hwinit/sdmmc_driver.h b/ariane/src/hwinit/sdmmc_driver.h deleted file mode 100644 index 173d3e8..0000000 --- a/ariane/src/hwinit/sdmmc_driver.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _SDMMC_DRIVER_H_ -#define _SDMMC_DRIVER_H_ - -#include "types.h" -#include "sdmmc_t210.h" - -/*! SDMMC controller IDs. */ -#define SDMMC_1 0 -#define SDMMC_2 1 -#define SDMMC_3 2 -#define SDMMC_4 3 - -/*! SDMMC power types. */ -#define SDMMC_POWER_OFF 0 -#define SDMMC_POWER_1_8 1 -#define SDMMC_POWER_3_3 2 - -/*! SDMMC bus widths. */ -#define SDMMC_BUS_WIDTH_1 0 -#define SDMMC_BUS_WIDTH_4 1 -#define SDMMC_BUS_WIDTH_8 2 - -/*! SDMMC response types. */ -#define SDMMC_RSP_TYPE_0 0 -#define SDMMC_RSP_TYPE_1 1 -#define SDMMC_RSP_TYPE_2 2 -#define SDMMC_RSP_TYPE_3 3 -#define SDMMC_RSP_TYPE_4 4 -#define SDMMC_RSP_TYPE_5 5 - -/*! SDMMC mask interrupt status. */ -#define SDMMC_MASKINT_MASKED 0 -#define SDMMC_MASKINT_NOERROR -1 -#define SDMMC_MASKINT_ERROR -2 - -/*! SDMMC host control 2 */ -#define SDHCI_CTRL_UHS_MASK 0xFFF8 -#define SDHCI_CTRL_VDD_330 0xFFF7 -#define SDHCI_CTRL_VDD_180 8 -#define SDHCI_CTRL_EXEC_TUNING 0x40 -#define SDHCI_CTRL_TUNED_CLK 0x80 -#define SDHCI_HOST_VERSION_4_EN 0x1000 -#define SDHCI_ADDRESSING_64BIT_EN 0x2000 -#define SDHCI_CTRL_PRESET_VAL_EN 0x8000 - -/*! SD bus speeds. */ -#define UHS_SDR12_BUS_SPEED 0 -#define HIGH_SPEED_BUS_SPEED 1 -#define UHS_SDR25_BUS_SPEED 1 -#define UHS_SDR50_BUS_SPEED 2 -#define UHS_SDR104_BUS_SPEED 3 -#define UHS_DDR50_BUS_SPEED 4 -#define HS400_BUS_SPEED 5 - -/*! Helper for SWITCH command argument. */ -#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) - -/*! SDMMC controller context. */ -typedef struct _sdmmc_t -{ - t210_sdmmc_t *regs; - u32 id; - u32 divisor; - u32 clock_stopped; - int no_sd; - int sd_clock_enabled; - int venclkctl_set; - u32 venclkctl_tap; - u32 expected_rsp_type; - u32 dma_addr_next; - u32 rsp[4]; - u32 rsp3; -} sdmmc_t; - -/*! SDMMC command. */ -typedef struct _sdmmc_cmd_t -{ - u16 cmd; - u32 arg; - u32 rsp_type; - u32 check_busy; -} sdmmc_cmd_t; - -/*! SDMMC request. */ -typedef struct _sdmmc_req_t -{ - void *buf; - u32 blksize; - u32 num_sectors; - int is_write; - int is_multi_block; - int is_auto_cmd12; -} sdmmc_req_t; - -int sdmmc_get_voltage(sdmmc_t *sdmmc); -u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); -void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); -void sdmmc_get_venclkctl(sdmmc_t *sdmmc); -int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); -void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd); -int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); -int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd); -int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); -int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd); -void sdmmc_end(sdmmc_t *sdmmc, u32 powerOff); -void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy); -int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out); -int sdmmc_enable_low_voltage(sdmmc_t *sdmmc); - -#endif diff --git a/ariane/src/hwinit/sdmmc_t210.h b/ariane/src/hwinit/sdmmc_t210.h deleted file mode 100644 index 80862c2..0000000 --- a/ariane/src/hwinit/sdmmc_t210.h +++ /dev/null @@ -1,132 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _SDMMC_T210_H_ -#define _SDMMC_T210_H_ - -#include "types.h" - -#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1 -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE -#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1 - -#define TEGRA_MMC_HOSTCTL_1BIT 0x00 -#define TEGRA_MMC_HOSTCTL_4BIT 0x02 -#define TEGRA_MMC_HOSTCTL_8BIT 0x20 - -#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1 -#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2 -#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4 -#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20 - -#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1 -#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2 -#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4 - -#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1 -#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2 -#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4 -#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0 -#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10 -#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20 - -#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8 -#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10 -#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20 - -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3 -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0 -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1 -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2 -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3 - -#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1 -#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2 -#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8 -#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000 -#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000 - -#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20 - -typedef struct _t210_sdmmc_t -{ - vu32 sysad; - vu16 blksize; - vu16 blkcnt; - vu32 argument; - vu16 trnmod; - vu16 cmdreg; - vu32 rspreg0; - vu32 rspreg1; - vu32 rspreg2; - vu32 rspreg3; - vu32 bdata; - vu32 prnsts; - vu8 hostctl; - vu8 pwrcon; - vu8 blkgap; - vu8 wakcon; - vu16 clkcon; - vu8 timeoutcon; - vu8 swrst; - vu16 norintsts; - vu16 errintsts; - vu16 norintstsen; - vu16 errintstsen; - vu16 norintsigen; - vu16 errintsigen; - vu16 acmd12errsts; - vu16 hostctl2; - vu32 capareg; - vu32 capareg_1; - vu32 maxcurr; - vu8 res3[4]; - vu16 setacmd12err; - vu16 setinterr; - vu8 admaerr; - vu8 res4[3]; - vu32 admaaddr; - vu32 admaaddr_hi; - vu8 res5[156]; - vu16 slotintstatus; - vu16 hcver; - vu32 venclkctl; - vu32 venspictl; - vu32 venspiintsts; - vu32 venceatactl; - vu32 venbootctl; - vu32 venbootacktout; - vu32 venbootdattout; - vu32 vendebouncecnt; - vu32 venmiscctl; - vu32 res6[34]; - vu32 field_1AC; - vu32 field_1B0; - vu8 res7[8]; - vu32 field_1BC; - vu32 field_1C0; - vu32 field_1C4; - vu8 field_1C8[24]; - vu32 sdmemcmppadctl; - vu32 autocalcfg; - vu32 autocalintval; - vu32 autocalsts; - vu32 field_1F0; -} t210_sdmmc_t; - -#endif diff --git a/ariane/src/hwinit/sdram.c b/ariane/src/hwinit/sdram.c deleted file mode 100644 index e2e328e..0000000 --- a/ariane/src/hwinit/sdram.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "t210.h" -#include "mc_t210.h" -#include "clock.h" -#include "i2c.h" -#include "sdram_param_t210.h" -#include "emc.h" -#include "pmc.h" -#include "timer.h" -#include "fuse.h" -#include "max7762x.h" -#include "max77620.h" -#include "sdram_param_t210.h" -#include "lib/printk.h" - -static void sdram_patch(uintptr_t addr, uint32_t value) -{ - if (addr != 0) - { - volatile uint32_t* volPtr = (void*)addr; - *volPtr = value; - } -} - -static void writebits(uint32_t value, vu32* addr, uint32_t mask) -{ - volatile uint32_t* volPtr = (void*)addr; - *volPtr = (*volPtr & (~mask)) | (value & mask); -} - -static void sdram_trigger_emc_timing_update(struct tegra_emc_regs *regs) -{ - regs->timing_control = EMC_TIMING_CONTROL_TIMING_UPDATE; -} - -/* PMC must be configured before clock-enable and de-reset of MC/EMC. */ -static void sdram_configure_pmc(const struct sdram_params *param, - struct tegra_pmc_regs *regs) -{ - /* VDDP Select */ - regs->vddp_sel = param->PmcVddpSel; - usleep(param->PmcVddpSelWait); - - /* Set DDR pad voltage */ - writebits(param->PmcDdrPwr, ®s->ddr_pwr, PMC_DDR_PWR_VAL_MASK); - - /* Turn on MEM IO Power */ - writebits(param->PmcNoIoPower, ®s->no_iopower, - (PMC_NO_IOPOWER_MEM_MASK | PMC_NO_IOPOWER_MEM_COMP_MASK)); - - regs->reg_short = param->PmcRegShort; - regs->ddr_cntrl = param->PmcDdrCntrl; -} - -static void sdram_set_ddr_control(const struct sdram_params *param, - struct tegra_pmc_regs *regs) -{ - u32 ddrcntrl = regs->ddr_cntrl; - - /* Deassert HOLD_CKE_LOW */ - ddrcntrl &= ~PMC_CMD_HOLD_LOW_BR00_11_MASK; - regs->ddr_cntrl = ddrcntrl; - usleep(param->PmcDdrCntrlWait); -} - -/* Start PLLM for SDRAM. */ -static void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 kvco, u32 kcp, - u32 stable_time, u32 emc_source, u32 same_freq) -{ - u32 misc1 = ((setup << PLLM_MISC1_SETUP_SHIFT)), - misc2 = ((kvco << PLLM_MISC2_KVCO_SHIFT) | - (kcp << PLLM_MISC2_KCP_SHIFT) | - PLLM_EN_LCKDET), - base; - - if (same_freq) - emc_source |= CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; - else - emc_source &= ~CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; - - /* - * Note PLLM_BASE.PLLM_OUT1_RSTN must be in RESET_ENABLE mode, and - * PLLM_BASE.ENABLE must be in DISABLE state (both are the default - * values after coldboot reset). - */ - - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = misc1; - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = misc2; - - /* PLLM.BASE needs BYPASS=0, different from general init_pll */ - base = CLOCK(CLK_RST_CONTROLLER_PLLM_BASE); - base &= ~(PLLCMX_BASE_DIVN_MASK | PLLCMX_BASE_DIVM_MASK | - PLLM_BASE_DIVP_MASK | PLL_BASE_BYPASS); - base |= ((m << PLL_BASE_DIVM_SHIFT) | (n << PLL_BASE_DIVN_SHIFT) | - (p << PLL_BASE_DIVP_SHIFT)); - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = base; - - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) |= PLL_BASE_ENABLE; - /* stable_time is required, before we can start to check lock. */ - usleep(stable_time); - - while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & PLL_BASE_LOCK)) - usleep(1); - - /* - * After PLLM reports being locked, we have to delay 10us before - * enabling PLLM_OUT. - */ - usleep(10); - - /* Enable and start MEM(MC) and EMC. */ - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = CLK_H_MEM | CLK_H_EMC; - /* Give clocks time to stabilize. */ - usleep(IO_STABILIZATION_DELAY); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = CLK_H_MEM | CLK_H_EMC; - - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = emc_source; - usleep(IO_STABILIZATION_DELAY); -} - -static void sdram_start_clocks(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - u32 is_same_freq = (param->McEmemArbMisc0 & - MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_MASK) ? 1 : 0; - u32 clk_source_emc = param->EmcClockSource; - - /* Enable the clocks for EMC and MC */ - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) |= CLK_H_EMC; // ENB_EMC - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) |= CLK_H_MEM; // ENB_MC - - if ((clk_source_emc >> EMC_2X_CLK_SRC_SHIFT) != PLLM_UD) - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) |= CLK_ENB_EMC_DLL; - - /* Remove the EMC and MC controllers from reset */ - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= ~(1 << 25); // SWR_EMC - CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= ~(1 << 0); // SWR_MC - - clk_source_emc |= (is_same_freq << 16); - - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = clk_source_emc; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = param->EmcClockSourceDll; - - clock_sdram(param->PllMInputDivider, param->PllMFeedbackDivider, - param->PllMPostDivider, param->PllMSetupControl, - param->PllMKVCO, param->PllMKCP, param->PllMStableTime, - param->EmcClockSource, is_same_freq); - - if (param->ClkRstControllerPllmMisc2OverrideEnable) - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = param->ClkRstControllerPllmMisc2Override; - - /* Wait for enough time for clk switch to take place */ - usleep(5); - - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = param->ClearClk2Mc1; -} - -static void sdram_set_swizzle(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - regs->swizzle_rank0_byte0 = param->EmcSwizzleRank0Byte0; - regs->swizzle_rank0_byte1 = param->EmcSwizzleRank0Byte1; - regs->swizzle_rank0_byte2 = param->EmcSwizzleRank0Byte2; - regs->swizzle_rank0_byte3 = param->EmcSwizzleRank0Byte3; - - regs->swizzle_rank1_byte0 = param->EmcSwizzleRank1Byte0; - regs->swizzle_rank1_byte1 = param->EmcSwizzleRank1Byte1; - regs->swizzle_rank1_byte2 = param->EmcSwizzleRank1Byte2; - regs->swizzle_rank1_byte3 = param->EmcSwizzleRank1Byte3; -} - -static void sdram_set_pad_controls(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Program the pad controls */ - regs->xm2comppadctrl = param->EmcXm2CompPadCtrl; - regs->xm2comppadctrl2 = param->EmcXm2CompPadCtrl2; - regs->xm2comppadctrl3 = param->EmcXm2CompPadCtrl3; -} - -static void sdram_set_pad_macros(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - u32 rfu_reset, rfu_mask1, rfu_mask2, rfu_step1, rfu_step2; - u32 cpm_reset_settings, cpm_mask1, cpm_step1; - - regs->pmacro_vttgen_ctrl0 = param->EmcPmacroVttgenCtrl0; - regs->pmacro_vttgen_ctrl1 = param->EmcPmacroVttgenCtrl1; - regs->pmacro_vttgen_ctrl2 = param->EmcPmacroVttgenCtrl2; - /* Trigger timing update so above writes take place */ - sdram_trigger_emc_timing_update(regs); - /* Add a wait to ensure the regulators settle */ - usleep(10); - - regs->dbg = param->EmcDbg | (param->EmcDbgWriteMux & WRITE_MUX_ACTIVE); - - rfu_reset = EMC_PMACRO_BRICK_CTRL_RFU1_RESET_VAL; - rfu_mask1 = 0x01120112; - rfu_mask2 = 0x01BF01BF; - - rfu_step1 = rfu_reset & (param->EmcPmacroBrickCtrlRfu1 | ~rfu_mask1); - rfu_step2 = rfu_reset & (param->EmcPmacroBrickCtrlRfu1 | ~rfu_mask2); - - /* common pad macro (cpm) */ - cpm_reset_settings = 0x0000000F; - cpm_mask1 = 0x00000001; - cpm_step1 = cpm_reset_settings; - cpm_step1 &= (param->EmcPmacroCommonPadTxCtrl | ~cpm_mask1); - - /* Patch 2 using BCT spare variables */ - sdram_patch(param->EmcBctSpare2, param->EmcBctSpare3); - - /* - * Program CMD mapping. Required before brick mapping, else - * we can't gaurantee CK will be differential at all times. - */ - regs->fbio_cfg7 = param->EmcFbioCfg7; - - regs->cmd_mapping_cmd0_0 = param->EmcCmdMappingCmd0_0; - regs->cmd_mapping_cmd0_1 = param->EmcCmdMappingCmd0_1; - regs->cmd_mapping_cmd0_2 = param->EmcCmdMappingCmd0_2; - regs->cmd_mapping_cmd1_0 = param->EmcCmdMappingCmd1_0; - regs->cmd_mapping_cmd1_1 = param->EmcCmdMappingCmd1_1; - regs->cmd_mapping_cmd1_2 = param->EmcCmdMappingCmd1_2; - regs->cmd_mapping_cmd2_0 = param->EmcCmdMappingCmd2_0; - regs->cmd_mapping_cmd2_1 = param->EmcCmdMappingCmd2_1; - regs->cmd_mapping_cmd2_2 = param->EmcCmdMappingCmd2_2; - regs->cmd_mapping_cmd3_0 = param->EmcCmdMappingCmd3_0; - regs->cmd_mapping_cmd3_1 = param->EmcCmdMappingCmd3_1; - regs->cmd_mapping_cmd3_2 = param->EmcCmdMappingCmd3_2; - regs->cmd_mapping_byte = param->EmcCmdMappingByte; - - /* Program brick mapping. */ - regs->pmacro_brick_mapping0 = param->EmcPmacroBrickMapping0; - regs->pmacro_brick_mapping1 = param->EmcPmacroBrickMapping1; - regs->pmacro_brick_mapping2 = param->EmcPmacroBrickMapping2; - - regs->pmacro_brick_ctrl_rfu1 = rfu_step1; - - /* This is required to do any reads from the pad macros */ - regs->config_sample_delay = param->EmcConfigSampleDelay; - - regs->fbio_cfg8 = param->EmcFbioCfg8; - - sdram_set_swizzle(param, regs); - - /* Patch 4 using BCT spare variables */ - sdram_patch(param->EmcBctSpare6, param->EmcBctSpare7); - - sdram_set_pad_controls(param, regs); - - /* Program Autocal controls with shadowed register fields */ - regs->auto_cal_config2 = param->EmcAutoCalConfig2; - regs->auto_cal_config3 = param->EmcAutoCalConfig3; - regs->auto_cal_config4 = param->EmcAutoCalConfig4; - regs->auto_cal_config5 = param->EmcAutoCalConfig5; - regs->auto_cal_config6 = param->EmcAutoCalConfig6; - regs->auto_cal_config7 = param->EmcAutoCalConfig7; - regs->auto_cal_config8 = param->EmcAutoCalConfig8; - - regs->pmacro_rx_term = param->EmcPmacroRxTerm; - regs->pmacro_dq_tx_drv = param->EmcPmacroDqTxDrv; - regs->pmacro_ca_tx_drv = param->EmcPmacroCaTxDrv; - regs->pmacro_cmd_tx_drv = param->EmcPmacroCmdTxDrv; - regs->pmacro_autocal_cfg_common = param->EmcPmacroAutocalCfgCommon; - regs->auto_cal_channel = param->EmcAutoCalChannel; - regs->pmacro_zctrl = param->EmcPmacroZctrl; - - regs->dll_cfg0 = param->EmcDllCfg0; - regs->dll_cfg1 = param->EmcDllCfg1; - regs->cfg_dig_dll_1 = param->EmcCfgDigDll_1; - - regs->data_brlshft_0 = param->EmcDataBrlshft0; - regs->data_brlshft_1 = param->EmcDataBrlshft1; - regs->dqs_brlshft_0 = param->EmcDqsBrlshft0; - regs->dqs_brlshft_1 = param->EmcDqsBrlshft1; - regs->cmd_brlshft_0 = param->EmcCmdBrlshft0; - regs->cmd_brlshft_1 = param->EmcCmdBrlshft1; - regs->cmd_brlshft_2 = param->EmcCmdBrlshft2; - regs->cmd_brlshft_3 = param->EmcCmdBrlshft3; - regs->quse_brlshft_0 = param->EmcQuseBrlshft0; - regs->quse_brlshft_1 = param->EmcQuseBrlshft1; - regs->quse_brlshft_2 = param->EmcQuseBrlshft2; - regs->quse_brlshft_3 = param->EmcQuseBrlshft3; - - regs->pmacro_brick_ctrl_rfu1 = rfu_step2; - regs->pmacro_pad_cfg_ctrl = param->EmcPmacroPadCfgCtrl; - - regs->pmacro_pad_cfg_ctrl = param->EmcPmacroPadCfgCtrl; - regs->pmacro_cmd_brick_ctrl_fdpd = param->EmcPmacroCmdBrickCtrlFdpd; - regs->pmacro_brick_ctrl_rfu2 = param->EmcPmacroBrickCtrlRfu2 & 0xFF7FFF7F; - regs->pmacro_data_brick_ctrl_fdpd = param->EmcPmacroDataBrickCtrlFdpd; - regs->pmacro_bg_bias_ctrl_0 = param->EmcPmacroBgBiasCtrl0; - regs->pmacro_data_pad_rx_ctrl = param->EmcPmacroDataPadRxCtrl; - regs->pmacro_cmd_pad_rx_ctrl = param->EmcPmacroCmdPadRxCtrl; - regs->pmacro_data_pad_tx_ctrl = param->EmcPmacroDataPadTxCtrl; - regs->pmacro_data_rx_term_mode = param->EmcPmacroDataRxTermMode; - regs->pmacro_cmd_rx_term_mode = param->EmcPmacroCmdRxTermMode; - regs->pmacro_cmd_pad_tx_ctrl = param->EmcPmacroCmdPadTxCtrl; - - regs->cfg_3 = param->EmcCfg3; - regs->pmacro_tx_pwrd_0 = param->EmcPmacroTxPwrd0; - regs->pmacro_tx_pwrd_1 = param->EmcPmacroTxPwrd1; - regs->pmacro_tx_pwrd_2 = param->EmcPmacroTxPwrd2; - regs->pmacro_tx_pwrd_3 = param->EmcPmacroTxPwrd3; - regs->pmacro_tx_pwrd_4 = param->EmcPmacroTxPwrd4; - regs->pmacro_tx_pwrd_5 = param->EmcPmacroTxPwrd5; - regs->pmacro_tx_sel_clk_src_0 = param->EmcPmacroTxSelClkSrc0; - regs->pmacro_tx_sel_clk_src_1 = param->EmcPmacroTxSelClkSrc1; - regs->pmacro_tx_sel_clk_src_2 = param->EmcPmacroTxSelClkSrc2; - regs->pmacro_tx_sel_clk_src_3 = param->EmcPmacroTxSelClkSrc3; - regs->pmacro_tx_sel_clk_src_4 = param->EmcPmacroTxSelClkSrc4; - regs->pmacro_tx_sel_clk_src_5 = param->EmcPmacroTxSelClkSrc5; - regs->pmacro_ddll_bypass = param->EmcPmacroDdllBypass; - regs->pmacro_ddll_pwrd_0 = param->EmcPmacroDdllPwrd0; - regs->pmacro_ddll_pwrd_1 = param->EmcPmacroDdllPwrd1; - regs->pmacro_ddll_pwrd_2 = param->EmcPmacroDdllPwrd2; - regs->pmacro_cmd_ctrl_0 = param->EmcPmacroCmdCtrl0; - regs->pmacro_cmd_ctrl_1 = param->EmcPmacroCmdCtrl1; - regs->pmacro_cmd_ctrl_2 = param->EmcPmacroCmdCtrl2; - regs->pmacro_ib_vref_dq_0 = param->EmcPmacroIbVrefDq_0; - regs->pmacro_ib_vref_dq_1 = param->EmcPmacroIbVrefDq_1; - regs->pmacro_ib_vref_dqs_0 = param->EmcPmacroIbVrefDqs_0; - regs->pmacro_ib_vref_dqs_1 = param->EmcPmacroIbVrefDqs_1; - regs->pmacro_ib_rxrt = param->EmcPmacroIbRxrt; - regs->pmacro_quse_ddll_rank0_0 = param->EmcPmacroQuseDdllRank0_0; - regs->pmacro_quse_ddll_rank0_1 = param->EmcPmacroQuseDdllRank0_1; - regs->pmacro_quse_ddll_rank0_2 = param->EmcPmacroQuseDdllRank0_2; - regs->pmacro_quse_ddll_rank0_3 = param->EmcPmacroQuseDdllRank0_3; - regs->pmacro_quse_ddll_rank0_4 = param->EmcPmacroQuseDdllRank0_4; - regs->pmacro_quse_ddll_rank0_5 = param->EmcPmacroQuseDdllRank0_5; - regs->pmacro_quse_ddll_rank1_0 = param->EmcPmacroQuseDdllRank1_0; - regs->pmacro_quse_ddll_rank1_1 = param->EmcPmacroQuseDdllRank1_1; - regs->pmacro_quse_ddll_rank1_2 = param->EmcPmacroQuseDdllRank1_2; - regs->pmacro_quse_ddll_rank1_3 = param->EmcPmacroQuseDdllRank1_3; - regs->pmacro_quse_ddll_rank1_4 = param->EmcPmacroQuseDdllRank1_4; - regs->pmacro_quse_ddll_rank1_5 = param->EmcPmacroQuseDdllRank1_5; - regs->pmacro_brick_ctrl_rfu1 = param->EmcPmacroBrickCtrlRfu1; - regs->pmacro_ob_ddll_long_dq_rank0_0 = param->EmcPmacroObDdllLongDqRank0_0; - regs->pmacro_ob_ddll_long_dq_rank0_1 = param->EmcPmacroObDdllLongDqRank0_1; - regs->pmacro_ob_ddll_long_dq_rank0_2 = param->EmcPmacroObDdllLongDqRank0_2; - regs->pmacro_ob_ddll_long_dq_rank0_3 = param->EmcPmacroObDdllLongDqRank0_3; - regs->pmacro_ob_ddll_long_dq_rank0_4 = param->EmcPmacroObDdllLongDqRank0_4; - regs->pmacro_ob_ddll_long_dq_rank0_5 = param->EmcPmacroObDdllLongDqRank0_5; - regs->pmacro_ob_ddll_long_dq_rank1_0 = param->EmcPmacroObDdllLongDqRank1_0; - regs->pmacro_ob_ddll_long_dq_rank1_1 = param->EmcPmacroObDdllLongDqRank1_1; - regs->pmacro_ob_ddll_long_dq_rank1_2 = param->EmcPmacroObDdllLongDqRank1_2; - regs->pmacro_ob_ddll_long_dq_rank1_3 = param->EmcPmacroObDdllLongDqRank1_3; - regs->pmacro_ob_ddll_long_dq_rank1_4 = param->EmcPmacroObDdllLongDqRank1_4; - regs->pmacro_ob_ddll_long_dq_rank1_5 = param->EmcPmacroObDdllLongDqRank1_5; - - regs->pmacro_ob_ddll_long_dqs_rank0_0 = param->EmcPmacroObDdllLongDqsRank0_0; - regs->pmacro_ob_ddll_long_dqs_rank0_1 = param->EmcPmacroObDdllLongDqsRank0_1; - regs->pmacro_ob_ddll_long_dqs_rank0_2 = param->EmcPmacroObDdllLongDqsRank0_2; - regs->pmacro_ob_ddll_long_dqs_rank0_3 = param->EmcPmacroObDdllLongDqsRank0_3; - regs->pmacro_ob_ddll_long_dqs_rank0_4 = param->EmcPmacroObDdllLongDqsRank0_4; - regs->pmacro_ob_ddll_long_dqs_rank0_5 = param->EmcPmacroObDdllLongDqsRank0_5; - regs->pmacro_ob_ddll_long_dqs_rank1_0 = param->EmcPmacroObDdllLongDqsRank1_0; - regs->pmacro_ob_ddll_long_dqs_rank1_1 = param->EmcPmacroObDdllLongDqsRank1_1; - regs->pmacro_ob_ddll_long_dqs_rank1_2 = param->EmcPmacroObDdllLongDqsRank1_2; - regs->pmacro_ob_ddll_long_dqs_rank1_3 = param->EmcPmacroObDdllLongDqsRank1_3; - regs->pmacro_ob_ddll_long_dqs_rank1_4 = param->EmcPmacroObDdllLongDqsRank1_4; - regs->pmacro_ob_ddll_long_dqs_rank1_5 = param->EmcPmacroObDdllLongDqsRank1_5; - regs->pmacro_ib_ddll_long_dqs_rank0_0 = param->EmcPmacroIbDdllLongDqsRank0_0; - regs->pmacro_ib_ddll_long_dqs_rank0_1 = param->EmcPmacroIbDdllLongDqsRank0_1; - regs->pmacro_ib_ddll_long_dqs_rank0_2 = param->EmcPmacroIbDdllLongDqsRank0_2; - regs->pmacro_ib_ddll_long_dqs_rank0_3 = param->EmcPmacroIbDdllLongDqsRank0_3; - regs->pmacro_ib_ddll_long_dqs_rank1_0 = param->EmcPmacroIbDdllLongDqsRank1_0; - regs->pmacro_ib_ddll_long_dqs_rank1_1 = param->EmcPmacroIbDdllLongDqsRank1_1; - regs->pmacro_ib_ddll_long_dqs_rank1_2 = param->EmcPmacroIbDdllLongDqsRank1_2; - regs->pmacro_ib_ddll_long_dqs_rank1_3 = param->EmcPmacroIbDdllLongDqsRank1_3; - regs->pmacro_ddll_long_cmd_0 = param->EmcPmacroDdllLongCmd_0; - regs->pmacro_ddll_long_cmd_1 = param->EmcPmacroDdllLongCmd_1; - regs->pmacro_ddll_long_cmd_2 = param->EmcPmacroDdllLongCmd_2; - regs->pmacro_ddll_long_cmd_3 = param->EmcPmacroDdllLongCmd_3; - regs->pmacro_ddll_long_cmd_4 = param->EmcPmacroDdllLongCmd_4; - regs->pmacro_ddll_short_cmd_0 = param->EmcPmacroDdllShortCmd_0; - regs->pmacro_ddll_short_cmd_1 = param->EmcPmacroDdllShortCmd_1; - regs->pmacro_ddll_short_cmd_2 = param->EmcPmacroDdllShortCmd_2; - regs->pmacro_common_pad_tx_ctrl = cpm_step1; -} - -static void sdram_setup_wpr_carveouts(const struct sdram_params *param, - struct tegra_mc_regs *regs) -{ - /* Program the 5 WPR carveouts with initial BCT settings. */ - regs->security_carveout1_bom = param->McGeneralizedCarveout1Bom; - regs->security_carveout1_bom_hi = param->McGeneralizedCarveout1BomHi; - regs->security_carveout1_size_128kb = param->McGeneralizedCarveout1Size128kb; - regs->security_carveout1_ca0 = param->McGeneralizedCarveout1Access0; - regs->security_carveout1_ca1 = param->McGeneralizedCarveout1Access1; - regs->security_carveout1_ca2 = param->McGeneralizedCarveout1Access2; - regs->security_carveout1_ca3 = param->McGeneralizedCarveout1Access3; - regs->security_carveout1_ca4 = param->McGeneralizedCarveout1Access4; - regs->security_carveout1_cfia0 = param->McGeneralizedCarveout1ForceInternalAccess0; - regs->security_carveout1_cfia1 = param->McGeneralizedCarveout1ForceInternalAccess1; - regs->security_carveout1_cfia2 = param->McGeneralizedCarveout1ForceInternalAccess2; - regs->security_carveout1_cfia3 = param->McGeneralizedCarveout1ForceInternalAccess3; - regs->security_carveout1_cfia4 = param->McGeneralizedCarveout1ForceInternalAccess4; - regs->security_carveout1_cfg0 = param->McGeneralizedCarveout1Cfg0; - - regs->security_carveout2_bom = param->McGeneralizedCarveout2Bom; - regs->security_carveout2_bom_hi = param->McGeneralizedCarveout2BomHi; - regs->security_carveout2_size_128kb = param->McGeneralizedCarveout2Size128kb; - regs->security_carveout2_ca0 = param->McGeneralizedCarveout2Access0; - regs->security_carveout2_ca1 = param->McGeneralizedCarveout2Access1; - regs->security_carveout2_ca2 = param->McGeneralizedCarveout2Access2; - regs->security_carveout2_ca3 = param->McGeneralizedCarveout2Access3; - regs->security_carveout2_ca4 = param->McGeneralizedCarveout2Access4; - regs->security_carveout2_cfia0 = param->McGeneralizedCarveout2ForceInternalAccess0; - regs->security_carveout2_cfia1 = param->McGeneralizedCarveout2ForceInternalAccess1; - regs->security_carveout2_cfia2 = param->McGeneralizedCarveout2ForceInternalAccess2; - regs->security_carveout2_cfia3 = param->McGeneralizedCarveout2ForceInternalAccess3; - regs->security_carveout2_cfia4 = param->McGeneralizedCarveout2ForceInternalAccess4; - regs->security_carveout2_cfg0 = param->McGeneralizedCarveout2Cfg0; - - regs->security_carveout3_bom = param->McGeneralizedCarveout3Bom; - regs->security_carveout3_bom_hi = param->McGeneralizedCarveout3BomHi; - regs->security_carveout3_size_128kb = param->McGeneralizedCarveout3Size128kb; - regs->security_carveout3_ca0 = param->McGeneralizedCarveout3Access0; - regs->security_carveout3_ca1 = param->McGeneralizedCarveout3Access1; - regs->security_carveout3_ca2 = param->McGeneralizedCarveout3Access2; - regs->security_carveout3_ca3 = param->McGeneralizedCarveout3Access3; - regs->security_carveout3_ca4 = param->McGeneralizedCarveout3Access4; - regs->security_carveout3_cfia0 = param->McGeneralizedCarveout3ForceInternalAccess0; - regs->security_carveout3_cfia1 = param->McGeneralizedCarveout3ForceInternalAccess1; - regs->security_carveout3_cfia2 = param->McGeneralizedCarveout3ForceInternalAccess2; - regs->security_carveout3_cfia3 = param->McGeneralizedCarveout3ForceInternalAccess3; - regs->security_carveout3_cfia4 = param->McGeneralizedCarveout3ForceInternalAccess4; - regs->security_carveout3_cfg0 = param->McGeneralizedCarveout3Cfg0; - - regs->security_carveout4_bom = param->McGeneralizedCarveout4Bom; - regs->security_carveout4_bom_hi = param->McGeneralizedCarveout4BomHi; - regs->security_carveout4_size_128kb = param->McGeneralizedCarveout4Size128kb; - regs->security_carveout4_ca0 = param->McGeneralizedCarveout4Access0; - regs->security_carveout4_ca1 = param->McGeneralizedCarveout4Access1; - regs->security_carveout4_ca2 = param->McGeneralizedCarveout4Access2; - regs->security_carveout4_ca3 = param->McGeneralizedCarveout4Access3; - regs->security_carveout4_ca4 = param->McGeneralizedCarveout4Access4; - regs->security_carveout4_cfia0 = param->McGeneralizedCarveout4ForceInternalAccess0; - regs->security_carveout4_cfia1 = param->McGeneralizedCarveout4ForceInternalAccess1; - regs->security_carveout4_cfia2 = param->McGeneralizedCarveout4ForceInternalAccess2; - regs->security_carveout4_cfia3 = param->McGeneralizedCarveout4ForceInternalAccess3; - regs->security_carveout4_cfia4 = param->McGeneralizedCarveout4ForceInternalAccess4; - regs->security_carveout4_cfg0 = param->McGeneralizedCarveout4Cfg0; - - regs->security_carveout5_bom = param->McGeneralizedCarveout5Bom; - regs->security_carveout5_bom_hi = param->McGeneralizedCarveout5BomHi; - regs->security_carveout5_size_128kb = param->McGeneralizedCarveout5Size128kb; - regs->security_carveout5_ca0 = param->McGeneralizedCarveout5Access0; - regs->security_carveout5_ca1 = param->McGeneralizedCarveout5Access1; - regs->security_carveout5_ca2 = param->McGeneralizedCarveout5Access2; - regs->security_carveout5_ca3 = param->McGeneralizedCarveout5Access3; - regs->security_carveout5_ca4 = param->McGeneralizedCarveout5Access4; - regs->security_carveout5_cfia0 = param->McGeneralizedCarveout5ForceInternalAccess0; - regs->security_carveout5_cfia1 = param->McGeneralizedCarveout5ForceInternalAccess1; - regs->security_carveout5_cfia2 = param->McGeneralizedCarveout5ForceInternalAccess2; - regs->security_carveout5_cfia3 = param->McGeneralizedCarveout5ForceInternalAccess3; - regs->security_carveout5_cfia4 = param->McGeneralizedCarveout5ForceInternalAccess4; - regs->security_carveout5_cfg0 = param->McGeneralizedCarveout5Cfg0; -} - -static void sdram_init_mc(const struct sdram_params *param, - struct tegra_mc_regs *regs) -{ - /* Initialize MC VPR settings */ - regs->video_protect_bom = param->McVideoProtectBom; - regs->video_protect_bom_adr_hi = param->McVideoProtectBomAdrHi; - regs->video_protect_size_mb = param->McVideoProtectSizeMb; - regs->video_protect_vpr_override = param->McVideoProtectVprOverride; - regs->video_protect_vpr_override1 = param->McVideoProtectVprOverride1; - regs->video_protect_gpu_override_0 = param->McVideoProtectGpuOverride0; - regs->video_protect_gpu_override_1 = param->McVideoProtectGpuOverride1; - - /* Program SDRAM geometry paarameters */ - regs->emem_adr_cfg = param->McEmemAdrCfg; - regs->emem_adr_cfg_dev0 = param->McEmemAdrCfgDev0; - regs->emem_adr_cfg_dev1 = param->McEmemAdrCfgDev1; - regs->emem_adr_cfg_channel_mask = param->McEmemAdrCfgChannelMask; - - /* Program bank swizzling */ - regs->emem_adr_cfg_bank_mask_0 = param->McEmemAdrCfgBankMask0; - regs->emem_adr_cfg_bank_mask_1 = param->McEmemAdrCfgBankMask1; - regs->emem_adr_cfg_bank_mask_2 = param->McEmemAdrCfgBankMask2; - - /* Program external memory aperature (base and size) */ - regs->emem_cfg = param->McEmemCfg; - - /* Program SEC carveout (base and size) */ - regs->sec_carveout_bom = param->McSecCarveoutBom; - regs->sec_carveout_adr_hi = param->McSecCarveoutAdrHi; - regs->sec_carveout_size_mb = param->McSecCarveoutSizeMb; - - /* Program MTS carveout (base and size) */ - regs->mts_carveout_bom = param->McMtsCarveoutBom; - regs->mts_carveout_adr_hi = param->McMtsCarveoutAdrHi; - regs->mts_carveout_size_mb = param->McMtsCarveoutSizeMb; - - /* Initialize the WPR carveouts */ - sdram_setup_wpr_carveouts(param, regs); - - /* Program the memory arbiter */ - regs->emem_arb_cfg = param->McEmemArbCfg; - regs->emem_arb_outstanding_req = param->McEmemArbOutstandingReq; - regs->emem_arb_refpb_hp_ctrl = param->McEmemArbRefpbHpCtrl; - regs->emem_arb_refpb_bank_ctrl = param->McEmemArbRefpbBankCtrl; - regs->emem_arb_timing_rcd = param->McEmemArbTimingRcd; - regs->emem_arb_timing_rp = param->McEmemArbTimingRp; - regs->emem_arb_timing_rc = param->McEmemArbTimingRc; - regs->emem_arb_timing_ras = param->McEmemArbTimingRas; - regs->emem_arb_timing_faw = param->McEmemArbTimingFaw; - regs->emem_arb_timing_rrd = param->McEmemArbTimingRrd; - regs->emem_arb_timing_rap2pre = param->McEmemArbTimingRap2Pre; - regs->emem_arb_timing_wap2pre = param->McEmemArbTimingWap2Pre; - regs->emem_arb_timing_r2r = param->McEmemArbTimingR2R; - regs->emem_arb_timing_w2w = param->McEmemArbTimingW2W; - regs->emem_arb_timing_ccdmw = param->McEmemArbTimingCcdmw; - regs->emem_arb_timing_r2w = param->McEmemArbTimingR2W; - regs->emem_arb_timing_w2r = param->McEmemArbTimingW2R; - regs->emem_arb_timing_rfcpb = param->McEmemArbTimingRFCPB; - regs->emem_arb_da_turns = param->McEmemArbDaTurns; - regs->emem_arb_da_covers = param->McEmemArbDaCovers; - regs->emem_arb_misc0 = param->McEmemArbMisc0; - regs->emem_arb_misc1 = param->McEmemArbMisc1; - regs->emem_arb_misc2 = param->McEmemArbMisc2; - regs->emem_arb_ring1_throttle = param->McEmemArbRing1Throttle; - regs->emem_arb_override = param->McEmemArbOverride; - regs->emem_arb_override_1 = param->McEmemArbOverride1; - regs->emem_arb_rsv = param->McEmemArbRsv; - regs->da_config0 = param->McDaCfg0; - - /* Trigger MC timing update */ - regs->timing_control = EMC_TIMING_CONTROL_TIMING_UPDATE; - - /* Program second-level clock enable overrides */ - regs->clken_override = param->McClkenOverride; - - /* Program statistics gathering */ - regs->stat_control = param->McStatControl; -} - -static void sdram_init_emc(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Program SDRAM geometry parameters */ - regs->adr_cfg = param->EmcAdrCfg; - - /* Program second-level clock enable overrides */ - regs->clken_override = param->EmcClkenOverride; - - /* Program EMC pad auto calibration */ - regs->pmacro_autocal_cfg0 = param->EmcPmacroAutocalCfg0; - regs->pmacro_autocal_cfg1 = param->EmcPmacroAutocalCfg1; - regs->pmacro_autocal_cfg2 = param->EmcPmacroAutocalCfg2; - - regs->auto_cal_vref_sel0 = param->EmcAutoCalVrefSel0; - regs->auto_cal_vref_sel1 = param->EmcAutoCalVrefSel1; - - regs->auto_cal_interval = param->EmcAutoCalInterval; - regs->auto_cal_config = param->EmcAutoCalConfig; - usleep(param->EmcAutoCalWait); -} - -static void sdram_set_emc_timing(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Program EMC timing configuration */ - regs->cfg_2 = param->EmcCfg2; - regs->cfg_pipe = param->EmcCfgPipe; - regs->cfg_pipe1 = param->EmcCfgPipe1; - regs->cfg_pipe2 = param->EmcCfgPipe2; - regs->cmdq = param->EmcCmdQ; - regs->mc2emcq = param->EmcMc2EmcQ; - regs->mrs_wait_cnt = param->EmcMrsWaitCnt; - regs->mrs_wait_cnt2 = param->EmcMrsWaitCnt2; - regs->fbio_cfg5 = param->EmcFbioCfg5; - regs->rc = param->EmcRc; - regs->rfc = param->EmcRfc; - regs->rfcpb = param->EmcRfcPb; - regs->refctrl2 = param->EmcRefctrl2; - regs->rfc_slr = param->EmcRfcSlr; - regs->ras = param->EmcRas; - regs->rp = param->EmcRp; - regs->tppd = param->EmcTppd; - regs->r2r = param->EmcR2r; - regs->w2w = param->EmcW2w; - regs->r2w = param->EmcR2w; - regs->w2r = param->EmcW2r; - regs->r2p = param->EmcR2p; - regs->w2p = param->EmcW2p; - regs->ccdmw = param->EmcCcdmw; - regs->rd_rcd = param->EmcRdRcd; - regs->wr_rcd = param->EmcWrRcd; - regs->rrd = param->EmcRrd; - regs->rext = param->EmcRext; - regs->wext = param->EmcWext; - regs->wdv = param->EmcWdv; - regs->wdv_chk = param->EmcWdvChk; - regs->wsv = param->EmcWsv; - regs->wev = param->EmcWev; - regs->wdv_mask = param->EmcWdvMask; - regs->ws_duration = param->EmcWsDuration; - regs->we_duration = param->EmcWeDuration; - regs->quse = param->EmcQUse; - regs->quse_width = param->EmcQuseWidth; - regs->ibdly = param->EmcIbdly; - regs->obdly = param->EmcObdly; - regs->einput = param->EmcEInput; - regs->einput_duration = param->EmcEInputDuration; - regs->puterm_extra = param->EmcPutermExtra; - regs->puterm_width = param->EmcPutermWidth; - - regs->pmacro_common_pad_tx_ctrl = param->EmcPmacroCommonPadTxCtrl; - regs->dbg = param->EmcDbg; - regs->qrst = param->EmcQRst; - regs->issue_qrst = 1; - regs->issue_qrst = 0; - regs->qsafe = param->EmcQSafe; - regs->rdv = param->EmcRdv; - regs->rdv_mask = param->EmcRdvMask; - regs->rdv_early = param->EmcRdvEarly; - regs->rdv_early_mask = param->EmcRdvEarlyMask; - regs->qpop = param->EmcQpop; - regs->refresh = param->EmcRefresh; - regs->burst_refresh_num = param->EmcBurstRefreshNum; - regs->pre_refresh_req_cnt = param->EmcPreRefreshReqCnt; - regs->pdex2wr = param->EmcPdEx2Wr; - regs->pdex2rd = param->EmcPdEx2Rd; - regs->pchg2pden = param->EmcPChg2Pden; - regs->act2pden = param->EmcAct2Pden; - regs->ar2pden = param->EmcAr2Pden; - regs->rw2pden = param->EmcRw2Pden; - regs->cke2pden = param->EmcCke2Pden; - regs->pdex2cke = param->EmcPdex2Cke; - regs->pdex2mrr = param->EmcPdex2Mrr; - regs->txsr = param->EmcTxsr; - regs->txsrdll = param->EmcTxsrDll; - regs->tcke = param->EmcTcke; - regs->tckesr = param->EmcTckesr; - regs->tpd = param->EmcTpd; - regs->tfaw = param->EmcTfaw; - regs->trpab = param->EmcTrpab; - regs->tclkstable = param->EmcTClkStable; - regs->tclkstop = param->EmcTClkStop; - regs->trefbw = param->EmcTRefBw; - regs->odt_write = param->EmcOdtWrite; - regs->cfg_dig_dll = param->EmcCfgDigDll; - regs->cfg_dig_dll_period = param->EmcCfgDigDllPeriod; - - /* Don't write CFG_ADR_EN (bit 1) here - lock bit written later */ - regs->fbio_spare = param->EmcFbioSpare & ~CFG_ADR_EN_LOCKED; - regs->cfg_rsv = param->EmcCfgRsv; - regs->pmc_scratch1 = param->EmcPmcScratch1; - regs->pmc_scratch2 = param->EmcPmcScratch2; - regs->pmc_scratch3 = param->EmcPmcScratch3; - regs->acpd_control = param->EmcAcpdControl; - regs->txdsrvttgen = param->EmcTxdsrvttgen; - - /* - * Set pipe bypass enable bits before sending any DRAM commands. - * Note other bits in EMC_CFG must be set AFTER REFCTRL is configured. - */ - writebits(param->EmcCfg, ®s->cfg, - (EMC_CFG_EMC2PMACRO_CFG_BYPASS_ADDRPIPE_MASK | - EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE1_MASK | - EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE2_MASK)); -} - -static void sdram_patch_bootrom(const struct sdram_params *param, - struct tegra_mc_regs *regs) -{ - if (param->BootRomPatchControl & BOOT_ROM_PATCH_CONTROL_ENABLE_MASK) { - uintptr_t addr = ((param->BootRomPatchControl & - BOOT_ROM_PATCH_CONTROL_OFFSET_MASK) >> - BOOT_ROM_PATCH_CONTROL_OFFSET_SHIFT); - addr = BOOT_ROM_PATCH_CONTROL_BASE_ADDRESS + (addr << 2); - *(volatile uint32_t *)(addr) = param->BootRomPatchData; - regs->timing_control = EMC_TIMING_CONTROL_TIMING_UPDATE; - } -} - -static void sdram_rel_dpd(const struct sdram_params *param, - struct tegra_pmc_regs *regs) -{ - u32 dpd3_val, dpd3_val_sel_dpd; - - /* Release SEL_DPD_CMD */ - dpd3_val = (param->EmcPmcScratch1 & 0x3FFFFFFF) | DPD_OFF; - dpd3_val_sel_dpd = dpd3_val & 0xCFFF0000; - regs->io_dpd3_req = dpd3_val_sel_dpd; - usleep(param->PmcIoDpd3ReqWait); -} - -/* Program DPD3/DPD4 regs (coldboot path) */ -static void sdram_set_dpd(const struct sdram_params *param, - struct tegra_pmc_regs *regs) -{ - u32 dpd3_val, dpd3_val_sel_dpd; - u32 dpd4_val, dpd4_val_e_dpd, dpd4_val_e_dpd_vttgen; - - /* Enable sel_dpd on unused pins */ - dpd3_val = (param->EmcPmcScratch1 & 0x3FFFFFFF) | DPD_ON; - dpd3_val_sel_dpd = (dpd3_val ^ 0x0000FFFF) & 0xC000FFFF; - regs->io_dpd3_req = dpd3_val_sel_dpd; - usleep(param->PmcIoDpd3ReqWait); - - dpd4_val = dpd3_val; - /* Disable e_dpd_vttgen */ - dpd4_val_e_dpd_vttgen = (dpd4_val ^ 0x3FFF0000) & 0xFFFF0000; - regs->io_dpd4_req = dpd4_val_e_dpd_vttgen; - usleep(param->PmcIoDpd4ReqWait); - - /* Disable e_dpd_bg */ - dpd4_val_e_dpd = (dpd4_val ^ 0x0000FFFF) & 0xC000FFFF; - regs->io_dpd4_req = dpd4_val_e_dpd; - usleep(param->PmcIoDpd4ReqWait); - - regs->weak_bias = 0; - /* Add a wait to make sure clock switch takes place */ - usleep(1); -} - -static void sdram_set_clock_enable_signal(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - volatile uint32_t dummy = 0; - uint32_t val = 0; - - if (param->MemoryType == NvBootMemoryType_LpDdr4) { - - val = (param->EmcPinGpioEn << EMC_PIN_GPIOEN_SHIFT) | - (param->EmcPinGpio << EMC_PIN_GPIO_SHIFT); - regs->pin = val; - - regs->pin &= ~(EMC_PIN_RESET_MASK | EMC_PIN_DQM_MASK | EMC_PIN_CKE_MASK); - /* - * Assert dummy read of PIN register to ensure above write goes - * through. Wait an additional 200us here as per NVIDIA. - */ - dummy |= regs->pin; - usleep(param->EmcPinExtraWait + 200); - - /* Deassert reset */ - regs->pin |= EMC_PIN_RESET_INACTIVE; - - /* - * Assert dummy read of PIN register to ensure above write goes - * through. Wait an additional 2000us here as per NVIDIA. - */ - dummy |= regs->pin; - usleep(param->EmcPinExtraWait + 2000); - } - - /* Enable clock enable signal */ - regs->pin |= EMC_PIN_CKE_NORMAL; - - /* Dummy read of PIN register to ensure final write goes through */ - dummy |= regs->pin; - usleep(param->EmcPinProgramWait); - - if (!dummy) - { - dbg_print("Failed to program EMC pin.\n!!!!"); - while (1) {} - } - - if (param->MemoryType != NvBootMemoryType_LpDdr4) { - - /* Send NOP (trigger just needs to be non-zero) */ - writebits(((1 << EMC_NOP_CMD_SHIFT) | - (param->EmcDevSelect << EMC_NOP_DEV_SELECTN_SHIFT)), - ®s->nop, - EMC_NOP_CMD_MASK | EMC_NOP_DEV_SELECTN_MASK); - } - - /* On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high */ - if (param->MemoryType == NvBootMemoryType_LpDdr2) - usleep(param->EmcPinExtraWait + 200); -} - -static void sdram_init_lpddr3(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Precharge all banks. DEV_SELECTN = 0 => Select all devices */ - regs->pre = (param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT) | 1; - - /* Send Reset MRW command */ - regs->mrw = param->EmcMrwResetCommand; - usleep(param->EmcMrwResetNInitWait); - - regs->mrw = param->EmcZcalInitDev0; - usleep(param->EmcZcalInitWait); - - if ((param->EmcDevSelect & 2) == 0) { - regs->mrw = param->EmcZcalInitDev1; - usleep(param->EmcZcalInitWait); - } - - /* Write mode registers */ - regs->mrw2 = param->EmcMrw2; - regs->mrw = param->EmcMrw1; - regs->mrw3 = param->EmcMrw3; - regs->mrw4 = param->EmcMrw4; - - /* Patch 6 using BCT spare variables */ - sdram_patch(param->EmcBctSpare10, param->EmcBctSpare11); - - if (param->EmcExtraModeRegWriteEnable) - regs->mrw =param->EmcMrwExtra; -} - -static void sdram_init_lpddr4(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Patch 6 using BCT spare variables */ - sdram_patch(param->EmcBctSpare10, param->EmcBctSpare11); - - /* Write mode registers */ - regs->mrw2 = param->EmcMrw2; - regs->mrw = param->EmcMrw1; - regs->mrw3 = param->EmcMrw3; - regs->mrw4 = param->EmcMrw4; - regs->mrw6 = param->EmcMrw6; - regs->mrw14 = param->EmcMrw14; - - regs->mrw8 = param->EmcMrw8; - regs->mrw12 = param->EmcMrw12; - regs->mrw9 = param->EmcMrw9; - regs->mrw13 = param->EmcMrw13; - - /* Issue ZQCAL start, device 0 */ - regs->zq_cal = param->EmcZcalInitDev0; - usleep(param->EmcZcalInitWait); - /* Issue ZQCAL latch */ - regs->zq_cal = param->EmcZcalInitDev0 ^ 0x3; - - if ((param->EmcDevSelect & 2) == 0) { - /* Same for device 1 */ - regs->zq_cal = param->EmcZcalInitDev1; - usleep(param->EmcZcalInitWait); - regs->zq_cal = param->EmcZcalInitDev1 ^ 0x3; - } -} - -static void sdram_init_zq_calibration(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - if (param->MemoryType == NvBootMemoryType_LpDdr2) - sdram_init_lpddr3(param, regs); - else if (param->MemoryType == NvBootMemoryType_LpDdr4) - sdram_init_lpddr4(param, regs); -} - -static void sdram_set_zq_calibration(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - if (param->EmcAutoCalInterval == 0) - regs->auto_cal_config = param->EmcAutoCalConfig | AUTOCAL_MEASURE_STALL_ENABLE; - - regs->pmacro_brick_ctrl_rfu2 = param->EmcPmacroBrickCtrlRfu2; - - /* ZQ CAL setup (not actually issuing ZQ CAL now) */ - if (param->MemoryType == NvBootMemoryType_LpDdr4) { - regs->zcal_wait_cnt = param->EmcZcalWaitCnt; - regs->zcal_mrw_cmd = param->EmcZcalMrwCmd; - } - - sdram_trigger_emc_timing_update(regs); - usleep(param->EmcTimingControlWait); -} - -static void sdram_set_refresh(const struct sdram_params *param, - struct tegra_emc_regs *regs) -{ - /* Insert burst refresh */ - if (param->EmcExtraRefreshNum > 0) { - uint32_t refresh_num = (1 << param->EmcExtraRefreshNum) - 1; - - writebits((EMC_REF_CMD_REFRESH | EMC_REF_NORMAL_ENABLED | - (refresh_num << EMC_REF_NUM_SHIFT) | - (param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT)), - ®s->ref, (EMC_REF_CMD_MASK | EMC_REF_NORMAL_MASK | - EMC_REF_NUM_MASK | - EMC_REF_DEV_SELECTN_MASK)); - } - - /* Enable refresh */ - regs->refctrl = param->EmcDevSelect | EMC_REFCTRL_REF_VALID_ENABLED; - - /* - * NOTE: Programming CFG must happen after REFCTRL to delay - * active power-down to after init (DDR2 constraint). - */ - regs->dyn_self_ref_control = param->EmcDynSelfRefControl; - regs->cfg_update = param->EmcCfgUpdate; - regs->cfg = param->EmcCfg; - regs->fdpd_ctrl_dq = param->EmcFdpdCtrlDq; - regs->fdpd_ctrl_cmd = param->EmcFdpdCtrlCmd; - regs->sel_dpd_ctrl = param->EmcSelDpdCtrl; - - /* Write addr swizzle lock bit */ - regs->fbio_spare = param->EmcFbioSpare | CFG_ADR_EN_LOCKED; - - /* Re-trigger timing to latch power saving functions */ - sdram_trigger_emc_timing_update(regs); - - /* Enable EMC pipe clock gating */ - regs->cfg_pipe_clk = param->EmcCfgPipeClk; - /* Depending on freqency, enable CMD/CLK fdpd */ - regs->fdpd_ctrl_cmd_no_ramp = param->EmcFdpdCtrlCmdNoRamp; -} - -#define AHB_ARB_XBAR_CTRL 0x6000C0E0 -static void sdram_enable_arbiter(const struct sdram_params *param) -{ - - /* TODO(hungte) Move values here to standalone header file. */ - volatile uint32_t *ahb_arbitration_xbar_ctrl = (void*)(AHB_ARB_XBAR_CTRL); - - *ahb_arbitration_xbar_ctrl |= param->AhbArbitrationXbarCtrlMemInitDone << 16; - -} - -static void sdram_lock_carveouts(const struct sdram_params *param, - struct tegra_mc_regs *regs) -{ - /* Lock carveouts, and emem_cfg registers */ - regs->video_protect_reg_ctrl = param->McVideoProtectWriteAccess; - regs->sec_carveout_reg_ctrl = param->McSecCarveoutProtectWriteAccess; - regs->mts_carveout_reg_ctrl = param->McMtsCarveoutRegCtrl; - - /* Write this last, locks access */ - regs->emem_cfg_access_ctrl = MC_EMEM_CFG_ACCESS_CTRL_WRITE_ACCESS_DISABLED; -} - - -//static void _sdram_config(const struct sdram_params *param) -void _sdram_config(const struct sdram_params *param) -{ - struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; - struct tegra_mc_regs *mc = (struct tegra_mc_regs *)MC_BASE; - struct tegra_emc_regs *emc = (struct tegra_emc_regs *)EMC_BASE; - - if (param->MemoryType != NvBootMemoryType_LpDdr4 && - param->MemoryType != NvBootMemoryType_LpDdr2) - { - dbg_print("Invalid memory type!!!\n"); - while (1) {} - } - - sdram_configure_pmc(param, pmc); - sdram_patch(param->EmcBctSpare0, param->EmcBctSpare1); - - sdram_set_dpd(param, pmc); - sdram_start_clocks(param, emc); - sdram_set_pad_macros(param, emc); - sdram_patch(param->EmcBctSpare4, param->EmcBctSpare5); - - sdram_trigger_emc_timing_update(emc); - sdram_init_mc(param, mc); - sdram_init_emc(param, emc); - sdram_patch(param->EmcBctSpare8, param->EmcBctSpare9); - - sdram_set_emc_timing(param, emc); - sdram_patch_bootrom(param, mc); - sdram_rel_dpd(param, pmc); - sdram_set_zq_calibration(param, emc); - sdram_set_ddr_control(param, pmc); - sdram_set_clock_enable_signal(param, emc); - - sdram_init_zq_calibration(param, emc); - - /* Set package and DPD pad control */ - pmc->ddr_cfg = param->PmcDdrCfg; - - /* Start periodic ZQ calibration (LPDDRx only) */ - if (param->MemoryType == NvBootMemoryType_LpDdr4 || - param->MemoryType == NvBootMemoryType_LpDdr2) { - emc->zcal_interval = param->EmcZcalInterval; - emc->zcal_wait_cnt = param->EmcZcalWaitCnt; - emc->zcal_mrw_cmd = param->EmcZcalMrwCmd; - } - sdram_patch(param->EmcBctSpare12, param->EmcBctSpare13); - - sdram_trigger_emc_timing_update(emc); - sdram_set_refresh(param, emc); - - sdram_enable_arbiter(param); - sdram_lock_carveouts(param, mc); -} - -u32 get_sdram_id() -{ - return (fuse_read_odm(4) & 0x38) >> 3; -} - -#ifdef GET_SDRAM_FROM_BOOT0 -#include "mc.h" -#include "sdmmc.h" -#include "sdmmc_driver.h" -#include "lib/crc32.h" -#else -#include "lib/decomp.h" -#include "sdram_lz4.inl" -#endif - -const struct sdram_params* sdram_get_params() -{ - void* retVal = NULL; - u32 board_sdram_id = get_sdram_id(); //TODO: sdram_id should be in [0,4]. - if (board_sdram_id >= 4) - { - dbg_print("ERROR: fuse-read board_sdram_id is %u (valid values 0..4)\n", board_sdram_id); - return retVal; - } - u8* IRAM_BCT_LOCATION = (void*)0x40030000; - u8* iram_sdram_params_ptr = &IRAM_BCT_LOCATION[0x58C]; - -#ifdef GET_SDRAM_FROM_BOOT0 - sdmmc_storage_t mmcPart; - sdmmc_t mmcDev; - -#ifndef CONFIG_ENABLE_AHB_REDIRECT //otherwise already enabled - mc_enable_ahb_redirect(); -#endif - if (!sdmmc_storage_init_mmc(&mmcPart, &mmcDev, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) - { - dbg_print("ERROR initializing eMMC for BCT read!\n"); - goto ending_redirect; - } - if (!sdmmc_storage_set_mmc_partition(&mmcPart, 1)) - { - dbg_print("ERROR switching eMMC to BOOT0 for BCT read!\n"); - goto ending_sdmmc; - } - - if (!sdmmc_storage_read(&mmcPart, 0, 0x2800/512, IRAM_BCT_LOCATION)) - { - dbg_print("ERROR reading BCT from eMMC BOOT0!\n"); - goto ending_sdmmc; - } - - static const u32 BOOTDATA_VERSION_T210 = 0x00210001; - u32* boot_data_version_ptr = &IRAM_BCT_LOCATION[0x530]; - if (*boot_data_version_ptr != BOOTDATA_VERSION_T210) - { - dbg_print("ERROR: boot_data_version in BCT not correct! (expecting 0x%08X, read 0x%08X)\n", BOOTDATA_VERSION_T210, *boot_data_version_ptr); - goto ending_sdmmc; - } - - retVal = &iram_sdram_params_ptr[board_sdram_id*0x768]; - dbg_print("GOT sdram params for device %u (crc32: 0x%08x)\n", board_sdram_id, crc32b((u8*)retVal, 0x768)); -ending_sdmmc: - sdmmc_storage_end(&mmcPart); -ending_redirect: -#ifndef CONFIG_ENABLE_AHB_REDIRECT //otherwise already enabled - mc_disable_ahb_redirect(); -#endif -#else - size_t compResult = ulz4fn(_dram_cfg_lz4, sizeof(_dram_cfg_lz4), iram_sdram_params_ptr, 0x774*4); - if (compResult != 0) - retVal = &iram_sdram_params_ptr[board_sdram_id*0x774]; -#endif - return retVal; -} - -void sdram_init(const struct sdram_params* param) -{ - const sdram_params_t *params = (const sdram_params_t *)param; - /* - max77620_send_byte(MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); //1.1V - - - */ - // Set DRAM voltage. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); - - // VDDP Select. - PMC(APBDEV_PMC_VDDP_SEL) = params->PmcVddpSel; - usleep(params->PmcVddpSelWait); - - // Set DDR pad voltage. - PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); - - // Turn on MEM IO Power. - PMC(APBDEV_PMC_NO_IOPOWER) = params->PmcRegShort; - PMC(APBDEV_PMC_REG_SHORT) = params->PmcNoIoPower; - - PMC(APBDEV_PMC_DDR_CNTRL) = params->PmcDdrCntrlWait; - - // Patch 1 using BCT spare variables - if (params->EmcBctSpare0) - *(vu32 *)params->EmcBctSpare0 = params->EmcBctSpare1; - - _sdram_config(params); -} diff --git a/ariane/src/hwinit/sdram.h b/ariane/src/hwinit/sdram.h deleted file mode 100644 index cabcba4..0000000 --- a/ariane/src/hwinit/sdram.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _SDRAM_H_ -#define _SDRAM_H_ - -u32 get_sdram_id(); -struct sdram_params; -void sdram_init(const struct sdram_params* params); -const struct sdram_params* sdram_get_params(); -void sdram_lp0_save_params(const struct sdram_params* params); -void _sdram_config(const struct sdram_params *param); - - -#endif diff --git a/ariane/src/hwinit/sdram_lz4.inl b/ariane/src/hwinit/sdram_lz4.inl deleted file mode 100644 index 1ae6401..0000000 --- a/ariane/src/hwinit/sdram_lz4.inl +++ /dev/null @@ -1,67 +0,0 @@ -static const u8 _dram_cfg_lz4[1023] = -{ - 0x04, 0x22, 0x4D, 0x18, 0x64, 0x40, 0xA7, 0xEC, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x01, 0x00, 0x0E, 0xFC, - 0x05, 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00, 0x00, 0x04, 0xB4, 0x01, 0x70, 0x01, 0x32, 0x54, - 0x76, 0xC8, 0xE6, 0x00, 0x70, 0x24, 0x00, 0xC8, 0x34, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, - 0x00, 0x00, 0x00, 0x40, 0x18, 0x00, 0xFF, 0x01, 0xFF, 0xFF, 0x1F, 0x00, 0xD8, 0x51, 0x1A, 0xA0, - 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x77, 0x00, 0x04, 0x00, 0x01, 0xD3, 0xA6, 0xA6, 0xAF, 0xB3, - 0x3C, 0x9E, 0x00, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x04, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x19, 0x1F, - 0x01, 0x00, 0x42, 0x00, 0x00, 0x04, 0x08, 0x46, 0x00, 0x57, 0xA1, 0x01, 0x00, 0x00, 0x32, 0x64, - 0x00, 0x00, 0xC3, 0x00, 0x13, 0x02, 0x0C, 0x00, 0x13, 0x03, 0x04, 0x00, 0xD7, 0x1E, 0x00, 0x00, - 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, 0x2C, 0x00, 0x10, 0x09, 0xC8, 0x00, - 0x07, 0x10, 0x00, 0x13, 0x0B, 0x28, 0x00, 0x13, 0x08, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x57, 0x20, - 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x13, 0x03, 0x2C, 0x00, 0x13, 0x04, 0x10, 0x00, 0x17, 0x02, - 0x10, 0x00, 0x13, 0x08, 0x40, 0x00, 0x13, 0x05, 0x1C, 0x00, 0x04, 0x58, 0x00, 0x13, 0x02, 0x18, - 0x00, 0x04, 0x64, 0x00, 0x04, 0xAA, 0x00, 0xB5, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x5C, 0x01, 0x03, 0x65, 0x00, 0x13, 0xC1, 0x54, 0x00, 0x17, - 0x08, 0xCC, 0x00, 0x13, 0x03, 0x28, 0x00, 0x17, 0x05, 0x58, 0x00, 0x13, 0x27, 0x04, 0x00, 0x13, - 0x05, 0x04, 0x00, 0x13, 0x04, 0xDC, 0x00, 0x08, 0x0C, 0x00, 0xA0, 0x1C, 0x03, 0x00, 0x00, 0x0D, - 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x5A, 0x00, 0xF1, 0x28, 0xF3, 0x0C, 0x04, 0x05, 0x1B, 0x06, 0x02, - 0x03, 0x07, 0x1C, 0x23, 0x25, 0x25, 0x05, 0x08, 0x1D, 0x09, 0x0A, 0x24, 0x0B, 0x1E, 0x0D, 0x0C, - 0x26, 0x26, 0x03, 0x02, 0x1B, 0x1C, 0x23, 0x03, 0x04, 0x07, 0x05, 0x06, 0x25, 0x25, 0x02, 0x0A, - 0x0B, 0x1D, 0x0D, 0x08, 0x0C, 0x09, 0x1E, 0x24, 0x26, 0x26, 0x08, 0x24, 0x06, 0x07, 0x9A, 0x12, - 0xC5, 0x01, 0x2C, 0x00, 0xFF, 0xF0, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x00, 0x0D, 0xAB, 0x00, 0xD0, 0xC0, 0x71, 0x71, 0x03, 0x08, 0x00, 0x00, 0x0B, 0x08, 0x72, - 0x72, 0x0E, 0x0C, 0x20, 0x00, 0xC2, 0x08, 0x08, 0x0D, 0x0C, 0x00, 0x00, 0x0D, 0x0C, 0x14, 0x14, - 0x16, 0x08, 0x2C, 0x00, 0x2C, 0x11, 0x08, 0x6B, 0x02, 0x70, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, - 0x33, 0x72, 0x01, 0x94, 0xF3, 0x05, 0x08, 0x11, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xD0, 0x01, 0x80, - 0x01, 0x03, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x0C, 0x00, 0xC0, 0x08, 0x44, 0x00, 0x10, 0x04, - 0x04, 0x00, 0x06, 0x13, 0x07, 0x00, 0x80, 0x10, 0x00, 0xA2, 0xA0, 0x00, 0x2C, 0x00, 0x01, 0x37, - 0x00, 0x00, 0x00, 0x80, 0x48, 0x00, 0xD3, 0x08, 0x00, 0x04, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, - 0xF4, 0x20, 0x02, 0x28, 0x01, 0x00, 0x13, 0x11, 0x01, 0x00, 0x10, 0xBE, 0xBF, 0x00, 0x12, 0x0F, - 0x02, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x2C, 0x7F, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x18, - 0x00, 0x06, 0xF3, 0x02, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, - 0x30, 0x00, 0x32, 0x00, 0x05, 0x20, 0x00, 0x0F, 0x18, 0x00, 0x05, 0x1F, 0x28, 0x02, 0x00, 0x0C, - 0x11, 0x14, 0x5A, 0x00, 0x00, 0x5C, 0x00, 0x11, 0x10, 0x0C, 0x00, 0x0C, 0x7A, 0x00, 0x05, 0x50, - 0x01, 0xA4, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x4F, 0x00, 0x51, 0x18, 0x00, 0x00, 0x28, - 0x01, 0x23, 0x40, 0x01, 0x3C, 0x02, 0x54, 0xAB, 0x00, 0x0A, 0x04, 0x11, 0x58, 0x01, 0x03, 0x04, - 0x00, 0x0F, 0xEC, 0x00, 0x0D, 0x17, 0x02, 0x0C, 0x00, 0x17, 0x03, 0x64, 0x03, 0x02, 0xA1, 0x01, - 0x68, 0x22, 0x04, 0xFF, 0xFF, 0xAF, 0x4F, 0x78, 0x03, 0x04, 0x38, 0x00, 0x36, 0x8B, 0xFF, 0x07, - 0xA0, 0x00, 0xF1, 0x00, 0x32, 0x54, 0x76, 0x10, 0x47, 0x32, 0x65, 0x10, 0x34, 0x76, 0x25, 0x01, - 0x34, 0x67, 0x25, 0x14, 0x00, 0xF0, 0x00, 0x75, 0x64, 0x32, 0x01, 0x72, 0x56, 0x34, 0x10, 0x23, - 0x74, 0x56, 0x01, 0x45, 0x32, 0x67, 0x14, 0x00, 0x31, 0x49, 0x92, 0x24, 0x04, 0x00, 0x0C, 0x01, - 0x00, 0x13, 0x1B, 0x04, 0x00, 0x0C, 0x9C, 0x00, 0x80, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, - 0x00, 0x84, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0xD7, 0x06, 0x40, 0x8A, 0x00, 0xB2, 0x08, - 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x61, 0x03, 0x0B, 0xA0, 0x04, 0x13, - 0x37, 0x7A, 0x01, 0x12, 0x10, 0x95, 0x01, 0x31, 0x00, 0x11, 0x01, 0xC1, 0x02, 0x00, 0x1F, 0x00, - 0x13, 0x0A, 0xB5, 0x04, 0x17, 0x10, 0x7F, 0x03, 0x05, 0x12, 0x00, 0x00, 0x10, 0x04, 0xCF, 0x81, - 0x10, 0x09, 0x28, 0x93, 0x32, 0xA5, 0x44, 0x5B, 0x8A, 0x67, 0x76, 0x34, 0x01, 0x05, 0x53, 0xFF, - 0xEF, 0xFF, 0xEF, 0xC0, 0x01, 0x00, 0x57, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x01, 0x00, 0x01, 0x2C, - 0x01, 0x21, 0x03, 0x07, 0x04, 0x00, 0xF1, 0x03, 0x00, 0x24, 0xFF, 0xFF, 0x00, 0x44, 0x57, 0x6E, - 0x00, 0x28, 0x72, 0x39, 0x00, 0x10, 0x9C, 0x4B, 0x00, 0x10, 0x60, 0x01, 0xB2, 0x08, 0x4C, 0x00, - 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0xE8, 0x02, 0x0C, 0x7C, 0x01, 0x04, 0x08, 0x00, - 0x17, 0x05, 0x10, 0x00, 0x17, 0x04, 0xF4, 0x03, 0xE4, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, - 0x00, 0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0xA4, 0x05, 0x15, 0x1F, 0xF3, 0x00, 0x00, 0xC8, 0x03, - 0x14, 0x01, 0xDD, 0x00, 0x14, 0x80, 0xB6, 0x00, 0x15, 0xF0, 0xDC, 0x03, 0x68, 0x43, 0xC3, 0xBA, - 0xE4, 0xD3, 0x1E, 0xD2, 0x00, 0x2F, 0xF0, 0xFF, 0xEC, 0x00, 0x05, 0x19, 0x08, 0x0E, 0x00, 0x14, - 0x30, 0xAB, 0x00, 0x0F, 0x2C, 0x00, 0x02, 0x4F, 0x75, 0x0C, 0x00, 0x04, 0x58, 0x02, 0x01, 0x05, - 0x34, 0x00, 0x0F, 0x3A, 0x00, 0x04, 0x38, 0x7C, 0x16, 0x40, 0xAB, 0x05, 0x0F, 0x38, 0x00, 0x17, - 0x3F, 0x1E, 0x40, 0x04, 0xA8, 0x00, 0x04, 0x0F, 0xF4, 0x02, 0x0A, 0x3F, 0x42, 0x24, 0x00, 0x38, - 0x00, 0x23, 0x12, 0x2C, 0x38, 0x00, 0x2F, 0xEC, 0x00, 0x3C, 0x01, 0x07, 0x0F, 0x74, 0x07, 0xF9, - 0x1F, 0x0D, 0x74, 0x07, 0x4C, 0x03, 0x5F, 0x01, 0x1F, 0x80, 0x74, 0x07, 0xFF, 0xFF, 0xFF, 0x7D, - 0x1F, 0x02, 0x74, 0x07, 0xB7, 0x1F, 0x05, 0x74, 0x07, 0xFF, 0x95, 0x0F, 0xE8, 0x0E, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x75, 0x0F, 0x74, 0x07, 0x95, 0x1F, 0x12, 0x74, 0x07, 0x18, - 0x1F, 0x03, 0x74, 0x07, 0xFF, 0xFF, 0xB6, 0x13, 0x12, 0x04, 0x00, 0x0F, 0x74, 0x07, 0xFF, 0xFF, - 0xAE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x52, 0xE1, 0xE3 -}; diff --git a/ariane/src/hwinit/sdram_param_t210.h b/ariane/src/hwinit/sdram_param_t210.h deleted file mode 100644 index ac7b49d..0000000 --- a/ariane/src/hwinit/sdram_param_t210.h +++ /dev/null @@ -1,971 +0,0 @@ -/* - * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. - * Copyright 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -/** - * Defines the SDRAM parameter structure. - * - * Note that PLLM is used by EMC. The field names are in camel case to ease - * directly converting BCT config files (*.cfg) into C structure. - */ - -#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ -#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ - -#include -#include - -enum { - /* Specifies the memory type to be undefined */ - NvBootMemoryType_None = 0, - - /* Specifies the memory type to be DDR SDRAM */ - NvBootMemoryType_Ddr = 0, - - /* Specifies the memory type to be LPDDR SDRAM */ - NvBootMemoryType_LpDdr = 0, - - /* Specifies the memory type to be DDR2 SDRAM */ - NvBootMemoryType_Ddr2 = 0, - - /* Specifies the memory type to be LPDDR2 SDRAM */ - NvBootMemoryType_LpDdr2, - - /* Specifies the memory type to be DDR3 SDRAM */ - NvBootMemoryType_Ddr3, - - /* Specifies the memory type to be LPDDR4 SDRAM */ - NvBootMemoryType_LpDdr4, - - NvBootMemoryType_Num, - - /* Specifies an entry in the ram_code table that's not in use */ - NvBootMemoryType_Unused = 0X7FFFFFF, -}; - -enum { - BOOT_ROM_PATCH_CONTROL_ENABLE_MASK = 0x1 << 31, - BOOT_ROM_PATCH_CONTROL_OFFSET_SHIFT = 0, - BOOT_ROM_PATCH_CONTROL_OFFSET_MASK = 0x7FFFFFFF << 0, - BOOT_ROM_PATCH_CONTROL_BASE_ADDRESS = 0x70000000, - - EMC_ZCAL_WARM_COLD_BOOT_ENABLES_COLDBOOT_MASK = 1 << 0, -}; - -/** - * Defines the SDRAM parameter structure - */ -typedef struct sdram_params { - - /* Specifies the type of memory device */ - uint32_t MemoryType; - - /* MC/EMC clock source configuration */ - - /* Specifies the M value for PllM */ - uint32_t PllMInputDivider; - /* Specifies the N value for PllM */ - uint32_t PllMFeedbackDivider; - /* Specifies the time to wait for PLLM to lock (in microseconds) */ - uint32_t PllMStableTime; - /* Specifies misc. control bits */ - uint32_t PllMSetupControl; - /* Specifies the P value for PLLM */ - uint32_t PllMPostDivider; - /* Specifies value for Charge Pump Gain Control */ - uint32_t PllMKCP; - /* Specifies VCO gain */ - uint32_t PllMKVCO; - /* Spare BCT param */ - uint32_t EmcBctSpare0; - /* Spare BCT param */ - uint32_t EmcBctSpare1; - /* Spare BCT param */ - uint32_t EmcBctSpare2; - /* Spare BCT param */ - uint32_t EmcBctSpare3; - /* Spare BCT param */ - uint32_t EmcBctSpare4; - /* Spare BCT param */ - uint32_t EmcBctSpare5; - /* Spare BCT param */ - uint32_t EmcBctSpare6; - /* Spare BCT param */ - uint32_t EmcBctSpare7; - /* Spare BCT param */ - uint32_t EmcBctSpare8; - /* Spare BCT param */ - uint32_t EmcBctSpare9; - /* Spare BCT param */ - uint32_t EmcBctSpare10; - /* Spare BCT param */ - uint32_t EmcBctSpare11; - /* Spare BCT param */ - uint32_t EmcBctSpare12; - /* Spare BCT param */ - uint32_t EmcBctSpare13; - - /* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */ - uint32_t EmcClockSource; - uint32_t EmcClockSourceDll; - - /* Defines possible override for PLLLM_MISC2 */ - uint32_t ClkRstControllerPllmMisc2Override; - /* enables override for PLLLM_MISC2 */ - uint32_t ClkRstControllerPllmMisc2OverrideEnable; - /* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */ - uint32_t ClearClk2Mc1; - - /* Auto-calibration of EMC pads */ - - /* Specifies the value for EMC_AUTO_CAL_INTERVAL */ - uint32_t EmcAutoCalInterval; - /* - * Specifies the value for EMC_AUTO_CAL_CONFIG - * Note: Trigger bits are set by the SDRAM code. - */ - uint32_t EmcAutoCalConfig; - - /* Specifies the value for EMC_AUTO_CAL_CONFIG2 */ - uint32_t EmcAutoCalConfig2; - - /* Specifies the value for EMC_AUTO_CAL_CONFIG3 */ - uint32_t EmcAutoCalConfig3; - - /* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */ - uint32_t EmcAutoCalConfig4; - uint32_t EmcAutoCalConfig5; - uint32_t EmcAutoCalConfig6; - uint32_t EmcAutoCalConfig7; - uint32_t EmcAutoCalConfig8; - - /* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */ - uint32_t EmcAutoCalVrefSel0; - uint32_t EmcAutoCalVrefSel1; - - /* Specifies the value for EMC_AUTO_CAL_CHANNEL */ - uint32_t EmcAutoCalChannel; - - /* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */ - uint32_t EmcPmacroAutocalCfg0; - uint32_t EmcPmacroAutocalCfg1; - uint32_t EmcPmacroAutocalCfg2; - uint32_t EmcPmacroRxTerm; - uint32_t EmcPmacroDqTxDrv; - uint32_t EmcPmacroCaTxDrv; - uint32_t EmcPmacroCmdTxDrv; - uint32_t EmcPmacroAutocalCfgCommon; - uint32_t EmcPmacroZctrl; - - /* - * Specifies the time for the calibration - * to stabilize (in microseconds) - */ - uint32_t EmcAutoCalWait; - - uint32_t EmcXm2CompPadCtrl; - uint32_t EmcXm2CompPadCtrl2; - uint32_t EmcXm2CompPadCtrl3; - - /* - * DRAM size information - * Specifies the value for EMC_ADR_CFG - */ - uint32_t EmcAdrCfg; - - /* - * Specifies the time to wait after asserting pin - * CKE (in microseconds) - */ - uint32_t EmcPinProgramWait; - /* Specifies the extra delay before/after pin RESET/CKE command */ - uint32_t EmcPinExtraWait; - - uint32_t EmcPinGpioEn; - uint32_t EmcPinGpio; - - /* - * Specifies the extra delay after the first writing - * of EMC_TIMING_CONTROL - */ - uint32_t EmcTimingControlWait; - - /* Timing parameters required for the SDRAM */ - - /* Specifies the value for EMC_RC */ - uint32_t EmcRc; - /* Specifies the value for EMC_RFC */ - uint32_t EmcRfc; - /* Specifies the value for EMC_RFC_PB */ - uint32_t EmcRfcPb; - /* Specifies the value for EMC_RFC_CTRL2 */ - uint32_t EmcRefctrl2; - /* Specifies the value for EMC_RFC_SLR */ - uint32_t EmcRfcSlr; - /* Specifies the value for EMC_RAS */ - uint32_t EmcRas; - /* Specifies the value for EMC_RP */ - uint32_t EmcRp; - /* Specifies the value for EMC_R2R */ - uint32_t EmcR2r; - /* Specifies the value for EMC_W2W */ - uint32_t EmcW2w; - /* Specifies the value for EMC_R2W */ - uint32_t EmcR2w; - /* Specifies the value for EMC_W2R */ - uint32_t EmcW2r; - /* Specifies the value for EMC_R2P */ - uint32_t EmcR2p; - /* Specifies the value for EMC_W2P */ - uint32_t EmcW2p; - - uint32_t EmcTppd; - uint32_t EmcCcdmw; - - /* Specifies the value for EMC_RD_RCD */ - uint32_t EmcRdRcd; - /* Specifies the value for EMC_WR_RCD */ - uint32_t EmcWrRcd; - /* Specifies the value for EMC_RRD */ - uint32_t EmcRrd; - /* Specifies the value for EMC_REXT */ - uint32_t EmcRext; - /* Specifies the value for EMC_WEXT */ - uint32_t EmcWext; - /* Specifies the value for EMC_WDV */ - uint32_t EmcWdv; - - uint32_t EmcWdvChk; - uint32_t EmcWsv; - uint32_t EmcWev; - - /* Specifies the value for EMC_WDV_MASK */ - uint32_t EmcWdvMask; - - uint32_t EmcWsDuration; - uint32_t EmcWeDuration; - - /* Specifies the value for EMC_QUSE */ - uint32_t EmcQUse; - /* Specifies the value for EMC_QUSE_WIDTH */ - uint32_t EmcQuseWidth; - /* Specifies the value for EMC_IBDLY */ - uint32_t EmcIbdly; - /* Specifies the value for EMC_OBDLY */ - uint32_t EmcObdly; - /* Specifies the value for EMC_EINPUT */ - uint32_t EmcEInput; - /* Specifies the value for EMC_EINPUT_DURATION */ - uint32_t EmcEInputDuration; - /* Specifies the value for EMC_PUTERM_EXTRA */ - uint32_t EmcPutermExtra; - /* Specifies the value for EMC_PUTERM_WIDTH */ - uint32_t EmcPutermWidth; - /* Specifies the value for EMC_PUTERM_ADJ */ - uint32_t EmcPutermAdj; - - /* Specifies the value for EMC_QRST */ - uint32_t EmcQRst; - /* Specifies the value for EMC_QSAFE */ - uint32_t EmcQSafe; - /* Specifies the value for EMC_RDV */ - uint32_t EmcRdv; - /* Specifies the value for EMC_RDV_MASK */ - uint32_t EmcRdvMask; - /* Specifies the value for EMC_RDV_EARLY */ - uint32_t EmcRdvEarly; - /* Specifies the value for EMC_RDV_EARLY_MASK */ - uint32_t EmcRdvEarlyMask; - /* Specifies the value for EMC_QPOP */ - uint32_t EmcQpop; - - /* Specifies the value for EMC_REFRESH */ - uint32_t EmcRefresh; - /* Specifies the value for EMC_BURST_REFRESH_NUM */ - uint32_t EmcBurstRefreshNum; - /* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */ - uint32_t EmcPreRefreshReqCnt; - /* Specifies the value for EMC_PDEX2WR */ - uint32_t EmcPdEx2Wr; - /* Specifies the value for EMC_PDEX2RD */ - uint32_t EmcPdEx2Rd; - /* Specifies the value for EMC_PCHG2PDEN */ - uint32_t EmcPChg2Pden; - /* Specifies the value for EMC_ACT2PDEN */ - uint32_t EmcAct2Pden; - /* Specifies the value for EMC_AR2PDEN */ - uint32_t EmcAr2Pden; - /* Specifies the value for EMC_RW2PDEN */ - uint32_t EmcRw2Pden; - /* Specifies the value for EMC_CKE2PDEN */ - uint32_t EmcCke2Pden; - /* Specifies the value for EMC_PDEX2CKE */ - uint32_t EmcPdex2Cke; - /* Specifies the value for EMC_PDEX2MRR */ - uint32_t EmcPdex2Mrr; - /* Specifies the value for EMC_TXSR */ - uint32_t EmcTxsr; - /* Specifies the value for EMC_TXSRDLL */ - uint32_t EmcTxsrDll; - /* Specifies the value for EMC_TCKE */ - uint32_t EmcTcke; - /* Specifies the value for EMC_TCKESR */ - uint32_t EmcTckesr; - /* Specifies the value for EMC_TPD */ - uint32_t EmcTpd; - /* Specifies the value for EMC_TFAW */ - uint32_t EmcTfaw; - /* Specifies the value for EMC_TRPAB */ - uint32_t EmcTrpab; - /* Specifies the value for EMC_TCLKSTABLE */ - uint32_t EmcTClkStable; - /* Specifies the value for EMC_TCLKSTOP */ - uint32_t EmcTClkStop; - /* Specifies the value for EMC_TREFBW */ - uint32_t EmcTRefBw; - - /* FBIO configuration values */ - - /* Specifies the value for EMC_FBIO_CFG5 */ - uint32_t EmcFbioCfg5; - /* Specifies the value for EMC_FBIO_CFG7 */ - uint32_t EmcFbioCfg7; - /* Specifies the value for EMC_FBIO_CFG8 */ - uint32_t EmcFbioCfg8; - - /* Command mapping for CMD brick 0 */ - uint32_t EmcCmdMappingCmd0_0; - uint32_t EmcCmdMappingCmd0_1; - uint32_t EmcCmdMappingCmd0_2; - uint32_t EmcCmdMappingCmd1_0; - uint32_t EmcCmdMappingCmd1_1; - uint32_t EmcCmdMappingCmd1_2; - uint32_t EmcCmdMappingCmd2_0; - uint32_t EmcCmdMappingCmd2_1; - uint32_t EmcCmdMappingCmd2_2; - uint32_t EmcCmdMappingCmd3_0; - uint32_t EmcCmdMappingCmd3_1; - uint32_t EmcCmdMappingCmd3_2; - uint32_t EmcCmdMappingByte; - - /* Specifies the value for EMC_FBIO_SPARE */ - uint32_t EmcFbioSpare; - - /* Specifies the value for EMC_CFG_RSV */ - uint32_t EmcCfgRsv; - - /* MRS command values */ - - /* Specifies the value for EMC_MRS */ - uint32_t EmcMrs; - /* Specifies the MP0 command to initialize mode registers */ - uint32_t EmcEmrs; - /* Specifies the MP2 command to initialize mode registers */ - uint32_t EmcEmrs2; - /* Specifies the MP3 command to initialize mode registers */ - uint32_t EmcEmrs3; - /* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */ - uint32_t EmcMrw1; - /* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */ - uint32_t EmcMrw2; - /* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */ - uint32_t EmcMrw3; - /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ - uint32_t EmcMrw4; - /* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */ - uint32_t EmcMrw6; - /* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */ - uint32_t EmcMrw8; - /* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */ - uint32_t EmcMrw9; - /* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */ - uint32_t EmcMrw10; - /* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */ - uint32_t EmcMrw12; - /* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */ - uint32_t EmcMrw13; - /* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */ - uint32_t EmcMrw14; - /* - * Specifies the programming to extra LPDDR2 Mode Register - * at cold boot - */ - uint32_t EmcMrwExtra; - /* - * Specifies the programming to extra LPDDR2 Mode Register - * at warm boot - */ - uint32_t EmcWarmBootMrwExtra; - /* - * Specify the enable of extra Mode Register programming at - * warm boot - */ - uint32_t EmcWarmBootExtraModeRegWriteEnable; - /* - * Specify the enable of extra Mode Register programming at - * cold boot - */ - uint32_t EmcExtraModeRegWriteEnable; - - /* Specifies the EMC_MRW reset command value */ - uint32_t EmcMrwResetCommand; - /* Specifies the EMC Reset wait time (in microseconds) */ - uint32_t EmcMrwResetNInitWait; - /* Specifies the value for EMC_MRS_WAIT_CNT */ - uint32_t EmcMrsWaitCnt; - /* Specifies the value for EMC_MRS_WAIT_CNT2 */ - uint32_t EmcMrsWaitCnt2; - - /* EMC miscellaneous configurations */ - - /* Specifies the value for EMC_CFG */ - uint32_t EmcCfg; - /* Specifies the value for EMC_CFG_2 */ - uint32_t EmcCfg2; - /* Specifies the pipe bypass controls */ - uint32_t EmcCfgPipe; - uint32_t EmcCfgPipeClk; - uint32_t EmcFdpdCtrlCmdNoRamp; - uint32_t EmcCfgUpdate; - - /* Specifies the value for EMC_DBG */ - uint32_t EmcDbg; - uint32_t EmcDbgWriteMux; - - /* Specifies the value for EMC_CMDQ */ - uint32_t EmcCmdQ; - /* Specifies the value for EMC_MC2EMCQ */ - uint32_t EmcMc2EmcQ; - /* Specifies the value for EMC_DYN_SELF_REF_CONTROL */ - uint32_t EmcDynSelfRefControl; - - /* Specifies the value for MEM_INIT_DONE */ - uint32_t AhbArbitrationXbarCtrlMemInitDone; - - /* Specifies the value for EMC_CFG_DIG_DLL */ - uint32_t EmcCfgDigDll; - uint32_t EmcCfgDigDll_1; - /* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */ - uint32_t EmcCfgDigDllPeriod; - /* Specifies the value of *DEV_SELECTN of various EMC registers */ - uint32_t EmcDevSelect; - - /* Specifies the value for EMC_SEL_DPD_CTRL */ - uint32_t EmcSelDpdCtrl; - - /* Pads trimmer delays */ - uint32_t EmcFdpdCtrlDq; - uint32_t EmcFdpdCtrlCmd; - uint32_t EmcPmacroIbVrefDq_0; - uint32_t EmcPmacroIbVrefDq_1; - uint32_t EmcPmacroIbVrefDqs_0; - uint32_t EmcPmacroIbVrefDqs_1; - uint32_t EmcPmacroIbRxrt; - uint32_t EmcCfgPipe1; - uint32_t EmcCfgPipe2; - - /* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */ - uint32_t EmcPmacroQuseDdllRank0_0; - uint32_t EmcPmacroQuseDdllRank0_1; - uint32_t EmcPmacroQuseDdllRank0_2; - uint32_t EmcPmacroQuseDdllRank0_3; - uint32_t EmcPmacroQuseDdllRank0_4; - uint32_t EmcPmacroQuseDdllRank0_5; - uint32_t EmcPmacroQuseDdllRank1_0; - uint32_t EmcPmacroQuseDdllRank1_1; - uint32_t EmcPmacroQuseDdllRank1_2; - uint32_t EmcPmacroQuseDdllRank1_3; - uint32_t EmcPmacroQuseDdllRank1_4; - uint32_t EmcPmacroQuseDdllRank1_5; - - uint32_t EmcPmacroObDdllLongDqRank0_0; - uint32_t EmcPmacroObDdllLongDqRank0_1; - uint32_t EmcPmacroObDdllLongDqRank0_2; - uint32_t EmcPmacroObDdllLongDqRank0_3; - uint32_t EmcPmacroObDdllLongDqRank0_4; - uint32_t EmcPmacroObDdllLongDqRank0_5; - uint32_t EmcPmacroObDdllLongDqRank1_0; - uint32_t EmcPmacroObDdllLongDqRank1_1; - uint32_t EmcPmacroObDdllLongDqRank1_2; - uint32_t EmcPmacroObDdllLongDqRank1_3; - uint32_t EmcPmacroObDdllLongDqRank1_4; - uint32_t EmcPmacroObDdllLongDqRank1_5; - - uint32_t EmcPmacroObDdllLongDqsRank0_0; - uint32_t EmcPmacroObDdllLongDqsRank0_1; - uint32_t EmcPmacroObDdllLongDqsRank0_2; - uint32_t EmcPmacroObDdllLongDqsRank0_3; - uint32_t EmcPmacroObDdllLongDqsRank0_4; - uint32_t EmcPmacroObDdllLongDqsRank0_5; - uint32_t EmcPmacroObDdllLongDqsRank1_0; - uint32_t EmcPmacroObDdllLongDqsRank1_1; - uint32_t EmcPmacroObDdllLongDqsRank1_2; - uint32_t EmcPmacroObDdllLongDqsRank1_3; - uint32_t EmcPmacroObDdllLongDqsRank1_4; - uint32_t EmcPmacroObDdllLongDqsRank1_5; - - uint32_t EmcPmacroIbDdllLongDqsRank0_0; - uint32_t EmcPmacroIbDdllLongDqsRank0_1; - uint32_t EmcPmacroIbDdllLongDqsRank0_2; - uint32_t EmcPmacroIbDdllLongDqsRank0_3; - uint32_t EmcPmacroIbDdllLongDqsRank1_0; - uint32_t EmcPmacroIbDdllLongDqsRank1_1; - uint32_t EmcPmacroIbDdllLongDqsRank1_2; - uint32_t EmcPmacroIbDdllLongDqsRank1_3; - - uint32_t EmcPmacroDdllLongCmd_0; - uint32_t EmcPmacroDdllLongCmd_1; - uint32_t EmcPmacroDdllLongCmd_2; - uint32_t EmcPmacroDdllLongCmd_3; - uint32_t EmcPmacroDdllLongCmd_4; - uint32_t EmcPmacroDdllShortCmd_0; - uint32_t EmcPmacroDdllShortCmd_1; - uint32_t EmcPmacroDdllShortCmd_2; - - /* - * Specifies the delay after asserting CKE pin during a WarmBoot0 - * sequence (in microseconds) - */ - uint32_t WarmBootWait; - - /* Specifies the value for EMC_ODT_WRITE */ - uint32_t EmcOdtWrite; - - /* Periodic ZQ calibration */ - - /* - * Specifies the value for EMC_ZCAL_INTERVAL - * Value 0 disables ZQ calibration - */ - uint32_t EmcZcalInterval; - /* Specifies the value for EMC_ZCAL_WAIT_CNT */ - uint32_t EmcZcalWaitCnt; - /* Specifies the value for EMC_ZCAL_MRW_CMD */ - uint32_t EmcZcalMrwCmd; - - /* DRAM initialization sequence flow control */ - - /* Specifies the MRS command value for resetting DLL */ - uint32_t EmcMrsResetDll; - /* Specifies the command for ZQ initialization of device 0 */ - uint32_t EmcZcalInitDev0; - /* Specifies the command for ZQ initialization of device 1 */ - uint32_t EmcZcalInitDev1; - /* - * Specifies the wait time after programming a ZQ initialization - * command (in microseconds) - */ - uint32_t EmcZcalInitWait; - /* - * Specifies the enable for ZQ calibration at cold boot [bit 0] - * and warm boot [bit 1] - */ - uint32_t EmcZcalWarmColdBootEnables; - - /* - * Specifies the MRW command to LPDDR2 for ZQ calibration - * on warmboot - */ - /* Is issued to both devices separately */ - uint32_t EmcMrwLpddr2ZcalWarmBoot; - /* - * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot - * Is issued to both devices separately - */ - uint32_t EmcZqCalDdr3WarmBoot; - uint32_t EmcZqCalLpDdr4WarmBoot; - /* - * Specifies the wait time for ZQ calibration on warmboot - * (in microseconds) - */ - uint32_t EmcZcalWarmBootWait; - /* - * Specifies the enable for DRAM Mode Register programming - * at warm boot - */ - uint32_t EmcMrsWarmBootEnable; - /* - * Specifies the wait time after sending an MRS DLL reset command - * in microseconds) - */ - uint32_t EmcMrsResetDllWait; - /* Specifies the extra MRS command to initialize mode registers */ - uint32_t EmcMrsExtra; - /* Specifies the extra MRS command at warm boot */ - uint32_t EmcWarmBootMrsExtra; - /* Specifies the EMRS command to enable the DDR2 DLL */ - uint32_t EmcEmrsDdr2DllEnable; - /* Specifies the MRS command to reset the DDR2 DLL */ - uint32_t EmcMrsDdr2DllReset; - /* Specifies the EMRS command to set OCD calibration */ - uint32_t EmcEmrsDdr2OcdCalib; - /* - * Specifies the wait between initializing DDR and setting OCD - * calibration (in microseconds) - */ - uint32_t EmcDdr2Wait; - /* Specifies the value for EMC_CLKEN_OVERRIDE */ - uint32_t EmcClkenOverride; - - /* - * Specifies LOG2 of the extra refresh numbers after booting - * Program 0 to disable - */ - uint32_t EmcExtraRefreshNum; - /* Specifies the master override for all EMC clocks */ - uint32_t EmcClkenOverrideAllWarmBoot; - /* Specifies the master override for all MC clocks */ - uint32_t McClkenOverrideAllWarmBoot; - /* Specifies digital dll period, choosing between 4 to 64 ms */ - uint32_t EmcCfgDigDllPeriodWarmBoot; - - /* Pad controls */ - - /* Specifies the value for PMC_VDDP_SEL */ - uint32_t PmcVddpSel; - /* Specifies the wait time after programming PMC_VDDP_SEL */ - uint32_t PmcVddpSelWait; - /* Specifies the value for PMC_DDR_PWR */ - uint32_t PmcDdrPwr; - /* Specifies the value for PMC_DDR_CFG */ - uint32_t PmcDdrCfg; - /* Specifies the value for PMC_IO_DPD3_REQ */ - uint32_t PmcIoDpd3Req; - /* Specifies the wait time after programming PMC_IO_DPD3_REQ */ - uint32_t PmcIoDpd3ReqWait; - uint32_t PmcIoDpd4ReqWait; - - /* Specifies the value for PMC_REG_SHORT */ - uint32_t PmcRegShort; - /* Specifies the value for PMC_NO_IOPOWER */ - uint32_t PmcNoIoPower; - - uint32_t PmcDdrCntrlWait; - uint32_t PmcDdrCntrl; - - /* Specifies the value for EMC_ACPD_CONTROL */ - uint32_t EmcAcpdControl; - - /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */ - uint32_t EmcSwizzleRank0ByteCfg; - /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */ - uint32_t EmcSwizzleRank0Byte0; - /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */ - uint32_t EmcSwizzleRank0Byte1; - /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */ - uint32_t EmcSwizzleRank0Byte2; - /* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */ - uint32_t EmcSwizzleRank0Byte3; - /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */ - uint32_t EmcSwizzleRank1ByteCfg; - /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */ - uint32_t EmcSwizzleRank1Byte0; - /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */ - uint32_t EmcSwizzleRank1Byte1; - /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */ - uint32_t EmcSwizzleRank1Byte2; - /* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */ - uint32_t EmcSwizzleRank1Byte3; - - /* Specifies the value for EMC_TXDSRVTTGEN */ - uint32_t EmcTxdsrvttgen; - - /* Specifies the value for EMC_DATA_BRLSHFT_0 */ - uint32_t EmcDataBrlshft0; - uint32_t EmcDataBrlshft1; - - uint32_t EmcDqsBrlshft0; - uint32_t EmcDqsBrlshft1; - - uint32_t EmcCmdBrlshft0; - uint32_t EmcCmdBrlshft1; - uint32_t EmcCmdBrlshft2; - uint32_t EmcCmdBrlshft3; - - uint32_t EmcQuseBrlshft0; - uint32_t EmcQuseBrlshft1; - uint32_t EmcQuseBrlshft2; - uint32_t EmcQuseBrlshft3; - - uint32_t EmcDllCfg0; - uint32_t EmcDllCfg1; - - uint32_t EmcPmcScratch1; - uint32_t EmcPmcScratch2; - uint32_t EmcPmcScratch3; - - uint32_t EmcPmacroPadCfgCtrl; - - uint32_t EmcPmacroVttgenCtrl0; - uint32_t EmcPmacroVttgenCtrl1; - uint32_t EmcPmacroVttgenCtrl2; - - uint32_t EmcPmacroBrickCtrlRfu1; - uint32_t EmcPmacroCmdBrickCtrlFdpd; - uint32_t EmcPmacroBrickCtrlRfu2; - uint32_t EmcPmacroDataBrickCtrlFdpd; - uint32_t EmcPmacroBgBiasCtrl0; - uint32_t EmcPmacroDataPadRxCtrl; - uint32_t EmcPmacroCmdPadRxCtrl; - uint32_t EmcPmacroDataRxTermMode; - uint32_t EmcPmacroCmdRxTermMode; - uint32_t EmcPmacroDataPadTxCtrl; - uint32_t EmcPmacroCommonPadTxCtrl; - uint32_t EmcPmacroCmdPadTxCtrl; - uint32_t EmcCfg3; - - uint32_t EmcPmacroTxPwrd0; - uint32_t EmcPmacroTxPwrd1; - uint32_t EmcPmacroTxPwrd2; - uint32_t EmcPmacroTxPwrd3; - uint32_t EmcPmacroTxPwrd4; - uint32_t EmcPmacroTxPwrd5; - - uint32_t EmcConfigSampleDelay; - - uint32_t EmcPmacroBrickMapping0; - uint32_t EmcPmacroBrickMapping1; - uint32_t EmcPmacroBrickMapping2; - - uint32_t EmcPmacroTxSelClkSrc0; - uint32_t EmcPmacroTxSelClkSrc1; - uint32_t EmcPmacroTxSelClkSrc2; - uint32_t EmcPmacroTxSelClkSrc3; - uint32_t EmcPmacroTxSelClkSrc4; - uint32_t EmcPmacroTxSelClkSrc5; - - uint32_t EmcPmacroDdllBypass; - - uint32_t EmcPmacroDdllPwrd0; - uint32_t EmcPmacroDdllPwrd1; - uint32_t EmcPmacroDdllPwrd2; - - uint32_t EmcPmacroCmdCtrl0; - uint32_t EmcPmacroCmdCtrl1; - uint32_t EmcPmacroCmdCtrl2; - - /* DRAM size information */ - - /* Specifies the value for MC_EMEM_ADR_CFG */ - uint32_t McEmemAdrCfg; - /* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */ - uint32_t McEmemAdrCfgDev0; - /* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */ - uint32_t McEmemAdrCfgDev1; - uint32_t McEmemAdrCfgChannelMask; - - /* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */ - uint32_t McEmemAdrCfgBankMask0; - /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */ - uint32_t McEmemAdrCfgBankMask1; - /* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */ - uint32_t McEmemAdrCfgBankMask2; - - /* - * Specifies the value for MC_EMEM_CFG which holds the external memory - * size (in KBytes) - */ - uint32_t McEmemCfg; - - /* MC arbitration configuration */ - - /* Specifies the value for MC_EMEM_ARB_CFG */ - uint32_t McEmemArbCfg; - /* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */ - uint32_t McEmemArbOutstandingReq; - - uint32_t McEmemArbRefpbHpCtrl; - uint32_t McEmemArbRefpbBankCtrl; - - /* Specifies the value for MC_EMEM_ARB_TIMING_RCD */ - uint32_t McEmemArbTimingRcd; - /* Specifies the value for MC_EMEM_ARB_TIMING_RP */ - uint32_t McEmemArbTimingRp; - /* Specifies the value for MC_EMEM_ARB_TIMING_RC */ - uint32_t McEmemArbTimingRc; - /* Specifies the value for MC_EMEM_ARB_TIMING_RAS */ - uint32_t McEmemArbTimingRas; - /* Specifies the value for MC_EMEM_ARB_TIMING_FAW */ - uint32_t McEmemArbTimingFaw; - /* Specifies the value for MC_EMEM_ARB_TIMING_RRD */ - uint32_t McEmemArbTimingRrd; - /* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */ - uint32_t McEmemArbTimingRap2Pre; - /* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */ - uint32_t McEmemArbTimingWap2Pre; - /* Specifies the value for MC_EMEM_ARB_TIMING_R2R */ - uint32_t McEmemArbTimingR2R; - /* Specifies the value for MC_EMEM_ARB_TIMING_W2W */ - uint32_t McEmemArbTimingW2W; - /* Specifies the value for MC_EMEM_ARB_TIMING_R2W */ - uint32_t McEmemArbTimingR2W; - /* Specifies the value for MC_EMEM_ARB_TIMING_W2R */ - uint32_t McEmemArbTimingW2R; - - uint32_t McEmemArbTimingRFCPB; - - /* Specifies the value for MC_EMEM_ARB_DA_TURNS */ - uint32_t McEmemArbDaTurns; - /* Specifies the value for MC_EMEM_ARB_DA_COVERS */ - uint32_t McEmemArbDaCovers; - /* Specifies the value for MC_EMEM_ARB_MISC0 */ - uint32_t McEmemArbMisc0; - /* Specifies the value for MC_EMEM_ARB_MISC1 */ - uint32_t McEmemArbMisc1; - uint32_t McEmemArbMisc2; - - /* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */ - uint32_t McEmemArbRing1Throttle; - /* Specifies the value for MC_EMEM_ARB_OVERRIDE */ - uint32_t McEmemArbOverride; - /* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */ - uint32_t McEmemArbOverride1; - /* Specifies the value for MC_EMEM_ARB_RSV */ - uint32_t McEmemArbRsv; - - uint32_t McDaCfg0; - uint32_t McEmemArbTimingCcdmw; - - /* Specifies the value for MC_CLKEN_OVERRIDE */ - uint32_t McClkenOverride; - - /* Specifies the value for MC_STAT_CONTROL */ - uint32_t McStatControl; - - /* Specifies the value for MC_VIDEO_PROTECT_BOM */ - uint32_t McVideoProtectBom; - /* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */ - uint32_t McVideoProtectBomAdrHi; - /* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */ - uint32_t McVideoProtectSizeMb; - /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */ - uint32_t McVideoProtectVprOverride; - /* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */ - uint32_t McVideoProtectVprOverride1; - /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */ - uint32_t McVideoProtectGpuOverride0; - /* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */ - uint32_t McVideoProtectGpuOverride1; - /* Specifies the value for MC_SEC_CARVEOUT_BOM */ - uint32_t McSecCarveoutBom; - /* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */ - uint32_t McSecCarveoutAdrHi; - /* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */ - uint32_t McSecCarveoutSizeMb; - /* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL. - VIDEO_PROTECT_WRITEAccess */ - uint32_t McVideoProtectWriteAccess; - /* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL. - SEC_CARVEOUT_WRITEAccess */ - uint32_t McSecCarveoutProtectWriteAccess; - - /* Write-Protect Regions (WPR) */ - uint32_t McGeneralizedCarveout1Bom; - uint32_t McGeneralizedCarveout1BomHi; - uint32_t McGeneralizedCarveout1Size128kb; - uint32_t McGeneralizedCarveout1Access0; - uint32_t McGeneralizedCarveout1Access1; - uint32_t McGeneralizedCarveout1Access2; - uint32_t McGeneralizedCarveout1Access3; - uint32_t McGeneralizedCarveout1Access4; - uint32_t McGeneralizedCarveout1ForceInternalAccess0; - uint32_t McGeneralizedCarveout1ForceInternalAccess1; - uint32_t McGeneralizedCarveout1ForceInternalAccess2; - uint32_t McGeneralizedCarveout1ForceInternalAccess3; - uint32_t McGeneralizedCarveout1ForceInternalAccess4; - uint32_t McGeneralizedCarveout1Cfg0; - - uint32_t McGeneralizedCarveout2Bom; - uint32_t McGeneralizedCarveout2BomHi; - uint32_t McGeneralizedCarveout2Size128kb; - uint32_t McGeneralizedCarveout2Access0; - uint32_t McGeneralizedCarveout2Access1; - uint32_t McGeneralizedCarveout2Access2; - uint32_t McGeneralizedCarveout2Access3; - uint32_t McGeneralizedCarveout2Access4; - uint32_t McGeneralizedCarveout2ForceInternalAccess0; - uint32_t McGeneralizedCarveout2ForceInternalAccess1; - uint32_t McGeneralizedCarveout2ForceInternalAccess2; - uint32_t McGeneralizedCarveout2ForceInternalAccess3; - uint32_t McGeneralizedCarveout2ForceInternalAccess4; - uint32_t McGeneralizedCarveout2Cfg0; - - uint32_t McGeneralizedCarveout3Bom; - uint32_t McGeneralizedCarveout3BomHi; - uint32_t McGeneralizedCarveout3Size128kb; - uint32_t McGeneralizedCarveout3Access0; - uint32_t McGeneralizedCarveout3Access1; - uint32_t McGeneralizedCarveout3Access2; - uint32_t McGeneralizedCarveout3Access3; - uint32_t McGeneralizedCarveout3Access4; - uint32_t McGeneralizedCarveout3ForceInternalAccess0; - uint32_t McGeneralizedCarveout3ForceInternalAccess1; - uint32_t McGeneralizedCarveout3ForceInternalAccess2; - uint32_t McGeneralizedCarveout3ForceInternalAccess3; - uint32_t McGeneralizedCarveout3ForceInternalAccess4; - uint32_t McGeneralizedCarveout3Cfg0; - - uint32_t McGeneralizedCarveout4Bom; - uint32_t McGeneralizedCarveout4BomHi; - uint32_t McGeneralizedCarveout4Size128kb; - uint32_t McGeneralizedCarveout4Access0; - uint32_t McGeneralizedCarveout4Access1; - uint32_t McGeneralizedCarveout4Access2; - uint32_t McGeneralizedCarveout4Access3; - uint32_t McGeneralizedCarveout4Access4; - uint32_t McGeneralizedCarveout4ForceInternalAccess0; - uint32_t McGeneralizedCarveout4ForceInternalAccess1; - uint32_t McGeneralizedCarveout4ForceInternalAccess2; - uint32_t McGeneralizedCarveout4ForceInternalAccess3; - uint32_t McGeneralizedCarveout4ForceInternalAccess4; - uint32_t McGeneralizedCarveout4Cfg0; - - uint32_t McGeneralizedCarveout5Bom; - uint32_t McGeneralizedCarveout5BomHi; - uint32_t McGeneralizedCarveout5Size128kb; - uint32_t McGeneralizedCarveout5Access0; - uint32_t McGeneralizedCarveout5Access1; - uint32_t McGeneralizedCarveout5Access2; - uint32_t McGeneralizedCarveout5Access3; - uint32_t McGeneralizedCarveout5Access4; - uint32_t McGeneralizedCarveout5ForceInternalAccess0; - uint32_t McGeneralizedCarveout5ForceInternalAccess1; - uint32_t McGeneralizedCarveout5ForceInternalAccess2; - uint32_t McGeneralizedCarveout5ForceInternalAccess3; - uint32_t McGeneralizedCarveout5ForceInternalAccess4; - uint32_t McGeneralizedCarveout5Cfg0; - - /* Specifies enable for CA training */ - uint32_t EmcCaTrainingEnable; - - /* Set if bit 6 select is greater than bit 7 select; uses aremc. - spec packet SWIZZLE_BIT6_GT_BIT7 */ - uint32_t SwizzleRankByteEncode; - /* Specifies enable and offset for patched boot ROM write */ - uint32_t BootRomPatchControl; - /* Specifies data for patched boot ROM write */ - uint32_t BootRomPatchData; - - /* Specifies the value for MC_MTS_CARVEOUT_BOM */ - uint32_t McMtsCarveoutBom; - /* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */ - uint32_t McMtsCarveoutAdrHi; - /* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */ - uint32_t McMtsCarveoutSizeMb; - /* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */ - uint32_t McMtsCarveoutRegCtrl; - - /* End */ -} sdram_params_t; - -#endif diff --git a/ariane/src/hwinit/t210.h b/ariane/src/hwinit/t210.h deleted file mode 100644 index 782c216..0000000 --- a/ariane/src/hwinit/t210.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _T210_H_ -#define _T210_H_ - -#include "types.h" - -#define HOST1X_BASE 0x50000000 -#define DISPLAY_A_BASE 0x54200000 -#define DSI_BASE 0x54300000 -#define VIC_BASE 0x54340000 -#define TSEC_BASE 0x54500000 -#define SOR1_BASE 0x54580000 -#define PG_UP_BASE 0x60000000 -#define TMR_BASE 0x60005000 -#define CLOCK_BASE 0x60006000 -#define FLOW_CTLR_BASE 0x60007000 -#define SYSREG_BASE 0x6000C000 -#define SB_BASE (SYSREG_BASE + 0x200) -#define GPIO_BASE 0x6000D000 -#define GPIO_1_BASE (GPIO_BASE) -#define GPIO_2_BASE (GPIO_BASE + 0x100) -#define GPIO_3_BASE (GPIO_BASE + 0x200) -#define GPIO_4_BASE (GPIO_BASE + 0x300) -#define GPIO_5_BASE (GPIO_BASE + 0x400) -#define GPIO_6_BASE (GPIO_BASE + 0x500) -#define GPIO_7_BASE (GPIO_BASE + 0x600) -#define GPIO_8_BASE (GPIO_BASE + 0x700) -#define EXCP_VEC_BASE 0x6000F000 -#define APB_MISC_BASE 0x70000000 -#define PINMUX_AUX_BASE 0x70003000 -#define UART_BASE 0x70006000 -#define RTC_BASE 0x7000E000 -#define PMC_BASE 0x7000E400 -#define SYSCTR0_BASE 0x7000F000 -#define FUSE_BASE 0x7000F800 -#define KFUSE_BASE 0x7000FC00 -#define SE_BASE 0x70012000 -#define MC_BASE 0x70019000 -#define EMC_BASE 0x7001B000 -#define MIPI_CAL_BASE 0x700E3000 -#define I2S_BASE 0x702D1000 -#define TZRAM_BASE 0x7C010000 - - -#define _REG(base, off) *(vu32 *)((base) + (off)) - -#define HOST1X(off) _REG(HOST1X_BASE, off) -#define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off) -#define DSI(off) _REG(DSI_BASE, off) -#define VIC(off) _REG(VIC_BASE, off) -#define TSEC(off) _REG(TSEC_BASE, off) -#define SOR1(off) _REG(SOR1_BASE, off) -#define TMR(off) _REG(TMR_BASE, off) -#define CLOCK(off) _REG(CLOCK_BASE, off) -#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) -#define SYSREG(off) _REG(SYSREG_BASE, off) -#define SB(off) _REG(SB_BASE, off) -#define GPIO(off) _REG(GPIO_BASE, off) -#define GPIO_1(off) _REG(GPIO_1_BASE, off) -#define GPIO_2(off) _REG(GPIO_2_BASE, off) -#define GPIO_3(off) _REG(GPIO_3_BASE, off) -#define GPIO_4(off) _REG(GPIO_4_BASE, off) -#define GPIO_5(off) _REG(GPIO_5_BASE, off) -#define GPIO_6(off) _REG(GPIO_6_BASE, off) -#define GPIO_7(off) _REG(GPIO_7_BASE, off) -#define GPIO_8(off) _REG(GPIO_8_BASE, off) -#define EXCP_VEC(off) _REG(EXCP_VEC_BASE, off) -#define APB_MISC(off) _REG(APB_MISC_BASE, off) -#define PINMUX_AUX(off) _REG(PINMUX_AUX_BASE, off) -#define RTC(off) _REG(RTC_BASE, off) -#define PMC(off) _REG(PMC_BASE, off) -#define SYSCTR0(off) _REG(SYSCTR0_BASE, off) -#define FUSE(off) _REG(FUSE_BASE, off) -#define KFUSE(off) _REG(KFUSE_BASE, off) -#define SE(off) _REG(SE_BASE, off) -#define MC(off) _REG(MC_BASE, off) -#define EMC(off) _REG(EMC_BASE, off) -#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) -#define I2S(off) _REG(I2S_BASE, off) - -/*! Misc registers. */ -#define APB_MISC_PP_PINMUX_GLOBAL 0x40 - -/*! System registers. */ -#define AHB_ARBITRATION_XBAR_CTRL 0xE0 -#define AHB_AHB_SPARE_REG 0x110 - -/*! APB MISC registers. */ -#define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 -#define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8 -#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 -#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 - -/*! Secure boot registers. */ -#define SB_CSR 0x0 -#define SB_PIROM_START 0x4 -#define SB_AA64_RESET_LOW 0x30 -#define SB_AA64_RESET_HIGH 0x34 - -/*! SYSCTR0 registers. */ -#define SYSCTR0_CNTFID0 0x20 - -#endif diff --git a/ariane/src/hwinit/timer.c b/ariane/src/hwinit/timer.c deleted file mode 100644 index 8a7c27f..0000000 --- a/ariane/src/hwinit/timer.c +++ /dev/null @@ -1,49 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "timer.h" -#include "t210.h" - -u32 get_tmr_s() -{ - return RTC(RTC_SECONDS); -} - -u32 get_tmr_ms() -{ - //reading RTC_MILLI_SECONDS updates RTC_SHADOW_SECONDS value to match - u32 millis = RTC(RTC_MILLI_SECONDS); - u32 seconds = RTC(RTC_SHADOW_SECONDS); - - return (millis | (seconds << 10)); -} - -u32 get_tmr_us() -{ - return TMR(TMR_US_OFFS); -} - -void msleep(u32 milliseconds) -{ - u32 start = RTC(RTC_MILLI_SECONDS) | (RTC(RTC_SHADOW_SECONDS) << 10); - while (((RTC(RTC_MILLI_SECONDS) | (RTC(RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds) {} -} - -void usleep(u32 microseconds) -{ - u32 start = TMR(TMR_US_OFFS); - while ((TMR(TMR_US_OFFS) - start) <= microseconds) {} -} \ No newline at end of file diff --git a/ariane/src/hwinit/timer.h b/ariane/src/hwinit/timer.h deleted file mode 100644 index 86a3d6f..0000000 --- a/ariane/src/hwinit/timer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include "types.h" - -#define TMR_US_OFFS 0x10 -#define TMR_US_CFG_OFFS 0x14 - -#define RTC_SECONDS 0x8 -#define RTC_SHADOW_SECONDS 0xC -#define RTC_MILLI_SECONDS 0x10 - -u32 get_tmr_s(); -u32 get_tmr_ms(); -u32 get_tmr_us(); - -void msleep(u32 milliseconds); -void usleep(u32 microseconds); - -#endif diff --git a/ariane/src/hwinit/tsec.c b/ariane/src/hwinit/tsec.c deleted file mode 100644 index 8772262..0000000 --- a/ariane/src/hwinit/tsec.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include -#include "tsec.h" -#include "clock.h" -#include "t210.h" -#include "timer.h" - -static int _tsec_dma_wait_idle() -{ - u32 timeout = get_tmr_ms() + 10000; - - while (!(TSEC(0x1118) & 2)) - if (get_tmr_ms() > timeout) - return 0; - - return 1; -} - -static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offset) -{ - u32 cmd; - - if (not_imem) - cmd = 0x600; // DMA 0x100 bytes - else - cmd = 0x10; // dma imem - - TSEC(0x1114) = i_offset; // tsec_dmatrfmoffs_r - TSEC(0x111C) = pa_offset; // tsec_dmatrffboffs_r - TSEC(0x1118) = cmd; // tsec_dmatrfcmd_r - - return _tsec_dma_wait_idle(); -} - -int tsec_query(u32 carveout, u8 *dst, u32 rev) -{ - int res = 0; - - //Enable clocks. - clock_enable_host1x(); - clock_enable_tsec(); - clock_enable_sor_safe(); - clock_enable_sor0(); - clock_enable_sor1(); - clock_enable_kfuse(); - - //Configure Falcon. - TSEC(0x110C) = 0; // tsec_dmactl_r - TSEC(0x1010) = 0xFFF2; // tsec_irqmset_r - TSEC(0x101C) = 0xFFF0; // tsec_irqdest_r - TSEC(0x1048) = 3; // tsec_itfen_r - if (!_tsec_dma_wait_idle()) - { - res = -1; - goto out; - } - - //Load firmware. -#ifdef TEST_TSEC_RESET - static const u32 bit5_CPU_STOPPED = 1u << 5; - static const u32 bit4_CPU_HALTED = 1u << 4; - static const u32 bit3_HARD_RESET = 1u << 3; - static const u32 bit2_SOFT_RESET = 1u << 2; - static const u32 bit1_START_CPU = 1u << 1; - static const u32 bit0_IINVAL = 1u << 0; - - u32 cpuState = TSEC(0x1100); - printk("TSEC CPU STATE: STOPPED: %02x HALTED: %02x HRESET: %02x SRESET: %02x START: %02x IINVAL: %02x\n", - (cpuState & bit5_CPU_STOPPED) ? 1 : 0, - (cpuState & bit4_CPU_HALTED) ? 1 : 0, - (cpuState & bit3_HARD_RESET) ? 1 : 0, - (cpuState & bit2_SOFT_RESET) ? 1 : 0, - (cpuState & bit1_START_CPU) ? 1 : 0, - (cpuState & bit0_IINVAL) ? 1 : 0); - - cpuState |= bit3_HARD_RESET; - TSEC(0x1100) = cpuState; - while (cpuState & bit3_HARD_RESET) - { - cpuState = TSEC(0x1100); - printk("TSEC CPU STATE: STOPPED: %02x HALTED: %02x HRESET: %02x SRESET: %02x START: %02x IINVAL: %02x\n", - (cpuState & bit5_CPU_STOPPED) ? 1 : 0, - (cpuState & bit4_CPU_HALTED) ? 1 : 0, - (cpuState & bit3_HARD_RESET) ? 1 : 0, - (cpuState & bit2_SOFT_RESET) ? 1 : 0, - (cpuState & bit1_START_CPU) ? 1 : 0, - (cpuState & bit0_IINVAL) ? 1 : 0); - } -#endif - TSEC(0x1110) = carveout >> 8;// tsec_dmatrfbase_r - for (u32 addr = 0; addr < 0xF00; addr += 0x100) - { - if (!_tsec_dma_pa_to_internal_100(0, addr, addr)) - { - res = -2; - goto out; - } - } - - //Execute firmware. - HOST1X(0x3300) = 0x34C2E1DA; - TSEC(0x1044) = 0; - TSEC(0x1040) = rev; - TSEC(0x1104) = 0; // tsec_bootvec_r - TSEC(0x1100) = 2; // tsec_cpuctl_r - if (!_tsec_dma_wait_idle()) - { - res = -3; - goto out; - } - u32 timeout = get_tmr_ms() + 2000; - while (!TSEC(0x1044)) - { - if (get_tmr_ms() > timeout) - { - res = -4; - goto out; - } - } - if (TSEC(0x1044) != 0xB0B0B0B0) - { - res = -5; - goto out; - } - - //Fetch result. - HOST1X(0x3300) = 0; - u32 buf[4]; - buf[0] = SOR1(0x1E8); - buf[1] = SOR1(0x21C); - buf[2] = SOR1(0x208); - buf[3] = SOR1(0x20C); - SOR1(0x1E8) = 0; - SOR1(0x21C) = 0; - SOR1(0x208) = 0; - SOR1(0x20C) = 0; - memcpy(dst, &buf, 0x10); - -out:; - - //Disable clocks. - clock_disable_kfuse(); - clock_disable_sor1(); - clock_disable_sor0(); - clock_disable_sor_safe(); - clock_disable_tsec(); - clock_disable_host1x(); - - return res; -} diff --git a/ariane/src/hwinit/types.h b/ariane/src/hwinit/types.h deleted file mode 100644 index 2ee396c..0000000 --- a/ariane/src/hwinit/types.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _TYPES_H_ -#define _TYPES_H_ - -#define NULL ((void *)0) - -#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ALIGN_UP(x,a) ALIGN((x),(a)) -#define ALIGN_DOWN(x,a) ((x) & ~((typeof(x))(a)-1UL)) -#define IS_ALIGNED(x,a) (((x) & ((typeof(x))(a)-1UL)) == 0) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define ABS(a) (((a) < 0) ? (-(a)) : (a)) -#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b)) -#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) -#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) - -#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) -#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long int s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long int u64; - -typedef volatile unsigned char vu8; -typedef volatile unsigned short vu16; -typedef volatile unsigned int vu32; - -#endif diff --git a/ariane/src/hwinit/uart.c b/ariane/src/hwinit/uart.c deleted file mode 100644 index 8888869..0000000 --- a/ariane/src/hwinit/uart.c +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "uart.h" -#include "t210.h" -#include "timer.h" - -/* UART A, B, C, D and E. */ -static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 }; - -void uart_init(u32 idx, u32 baud) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - //Set baud rate. - u32 rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_LCR = 0x80; //Enable DLAB. - uart->UART_THR_DLAB = (u8)rate; //Divisor latch LSB. - uart->UART_IER_DLAB = (u8)(rate >> 8); //Divisor latch MSB. - uart->UART_LCR = 0; //Diable DLAB. - - //Setup UART in fifo mode. - uart->UART_IER_DLAB = 0; - uart->UART_IIR_FCR = 7; //Enable and clear TX and RX FIFOs. - (void)uart->UART_LSR; - usleep(3 * ((baud + 999999) / baud)); - uart->UART_LCR = 3; //Set word length 8. - uart->UART_MCR = 0; - uart->UART_MSR = 0; - uart->UART_IRDA_CSR = 0; - uart->UART_RX_FIFO_CFG = 1; - uart->UART_MIE = 0; - uart->UART_ASR = 0; -} - -void uart_wait_idle(u32 idx, u32 which) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - while (!(uart->UART_VENDOR_STATUS & which)) {} -} - -void uart_send(u32 idx, u8 *buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - for (u32 i = 0; i != len; i++) - { - while (uart->UART_LSR & UART_TX_FIFO_FULL) {} - uart->UART_THR_DLAB = buf[i]; - }; -} - -void uart_print(u32 idx, const char* buf, u32 len) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - - for (u32 i = 0; i != len; i++) - { - while (uart->UART_LSR & UART_TX_FIFO_FULL) {} - - if (buf[i] == '\n') - { - uart->UART_THR_DLAB = '\r'; - while (uart->UART_LSR & UART_TX_FIFO_FULL) {} - } - uart->UART_THR_DLAB = buf[i]; - }; -} - -u32 uart_has_bytes(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - return (uart->UART_LSR & UART_RX_FIFO_EMPTY) == 0; -} - -u8 uart_recv(u32 idx) -{ - uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]); - while (uart->UART_LSR & UART_RX_FIFO_EMPTY) {} - return uart->UART_THR_DLAB; -} diff --git a/ariane/src/hwinit/util.c b/ariane/src/hwinit/util.c deleted file mode 100644 index 356ca7f..0000000 --- a/ariane/src/hwinit/util.c +++ /dev/null @@ -1,41 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include "util.h" -#include "t210.h" -#include "max7762x.h" -#include "max77620.h" - -void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) -{ - for(u32 i = 0; i < num_ops; i++) - base[ops[i].off] = ops[i].val; -} - -int running_on_bpmp(void) -{ - static const u32 avp_id = 0xaaaaaaaa; - static volatile u32* uptag_ptr = (void *)PG_UP_BASE; - - return (*uptag_ptr) == avp_id; -} - -void shutdown_using_pmic() -{ - u8 regVal = max77620_recv_byte(MAX77620_REG_ONOFFCNFG1); - regVal |= MAX77620_ONOFFCNFG1_PWR_OFF; - max77620_send_byte(MAX77620_REG_ONOFFCNFG1, regVal); -} diff --git a/ariane/src/lib/crc32.c b/ariane/src/lib/crc32.c deleted file mode 100644 index 225d8a0..0000000 --- a/ariane/src/lib/crc32.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "crc32.h" - -/* This is the basic CRC-32 calculation with some optimization but no -table lookup. The the byte reversal is avoided by shifting the crc reg -right instead of left and by using a reversed 32-bit word to represent -the polynomial. - When compiled to Cyclops with GCC, this function executes in 8 + 72n -instructions, where n is the number of bytes in the input message. It -should be doable in 4 + 61n instructions. - If the inner loop is strung out (approx. 5*8 = 40 instructions), -it would take about 6 + 46n instructions. */ - -unsigned int crc32b(unsigned char* message, unsigned int msgLen) -{ - unsigned int byte, crc, mask; - crc = 0xFFFFFFFF; - for (unsigned int i=0; i= 0; j--) // Do eight times. - { - mask = -(crc & 1); - crc = (crc >> 1) ^ (0xEDB88320 & mask); - } - } - return ~crc; -} \ No newline at end of file diff --git a/ariane/src/lib/crc32.h b/ariane/src/lib/crc32.h deleted file mode 100644 index 2dd60a2..0000000 --- a/ariane/src/lib/crc32.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRC32_H_ -#define _CRC32_H_ - -unsigned int crc32b(unsigned char* message, unsigned int msgLen); - -#endif \ No newline at end of file diff --git a/ariane/src/lib/decomp.h b/ariane/src/lib/decomp.h deleted file mode 100644 index 5122357..0000000 --- a/ariane/src/lib/decomp.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2016 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _DECOMP_H_ -#define _DECOMP_H_ - -#include - -/* Decompresses an LZ4F image (multiple LZ4 blocks with frame header) from src - * to dst, ensuring that it doesn't read more than srcn bytes and doesn't write - * more than dstn. Buffer sizes must stay below 2GB. Can decompress files loaded - * to the end of a buffer in-place, as long as buffer is larger than the final - * output size. (Usually just a few bytes, but may be up to (8 + dstn/255) in - * worst case. Will reliably return an error if buffer was too small.) - * Returns amount of decompressed bytes, or 0 on error. - */ -size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn); - -/* Defined in src/lib/lzma.c. Returns decompressed size or 0 on error. */ -size_t ulzman(const void *src, size_t srcn, void *dst, size_t dstn); -int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize); - -#endif /* _DECOMP_H_ */ diff --git a/ariane/src/lib/diskio.c b/ariane/src/lib/diskio.c deleted file mode 100644 index ee318bf..0000000 --- a/ariane/src/lib/diskio.c +++ /dev/null @@ -1,55 +0,0 @@ -/*-----------------------------------------------------------------------*/ -/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ -/*-----------------------------------------------------------------------*/ -/* If a working storage control module is available, it should be */ -/* attached to the FatFs via a glue function rather than modifying it. */ -/* This is an example of glue functions to attach various exsisting */ -/* storage control modules to the FatFs module with a defined API. */ -/*-----------------------------------------------------------------------*/ - -#include -#include "diskio.h" /* FatFs lower layer API */ -#include "storage.h" - -DSTATUS disk_status ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - return 0; -} - -DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - return 0; -} - -DRESULT disk_read ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to read */ -) -{ - return sdmmc_storage_read(get_storage_for_index(pdrv), sector, count, buff) ? RES_OK : RES_ERROR; -} - -DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ -) -{ - return sdmmc_storage_write(get_storage_for_index(pdrv), sector, count, (void *)buff) ? RES_OK : RES_ERROR; -} - -DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive nmuber (0..) */ - BYTE cmd, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) -{ - return RES_OK; -} diff --git a/ariane/src/lib/heap.c b/ariane/src/lib/heap.c deleted file mode 100644 index 12bfb44..0000000 --- a/ariane/src/lib/heap.c +++ /dev/null @@ -1,136 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include -#include "heap.h" - -typedef struct _hnode -{ - int used; - u32 size; - struct _hnode *prev; - struct _hnode *next; -} hnode_t; - -typedef struct _heap -{ - u32 start; - hnode_t *first; -} heap_t; - -static void _heap_create(heap_t *heap, u32 start) -{ - heap->start = start; - heap->first = NULL; -} - -static u32 _heap_alloc(heap_t *heap, u32 size) -{ - hnode_t *node, *new; - int search = 1; - - size = ALIGN(size, 0x10); - - if (!heap->first) - { - node = (hnode_t *)heap->start; - node->used = 1; - node->size = size; - node->prev = NULL; - node->next = NULL; - heap->first = node; - - return (u32)node + sizeof(hnode_t); - } - - node = heap->first; - while (search) - { - if (!node->used && size + sizeof(hnode_t) < node->size) - { - new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); - - new->size = node->size - sizeof(hnode_t) - size; - node->size = size; - node->used = 1; - new->used = 0; - new->next = node->next; - new->prev = node; - node->next = new; - - return (u32)node + sizeof(hnode_t); - } - if (node->next) - node = node->next; - else - search = 0; - } - - new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); - new->used = 1; - new->size = size; - new->prev = node; - new->next = NULL; - node->next = new; - - return (u32)new + sizeof(hnode_t); -} - -static void _heap_free(heap_t *heap, u32 addr) -{ - hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t)); - node->used = 0; - node = heap->first; - while (node) - { - if (!node->used) - { - if (node->prev && !node->prev->used) - { - node->prev->size += node->size + sizeof(hnode_t); - node->prev->next = node->next; - if (node->next) - node->next->prev = node->prev; - } - } - node = node->next; - } -} - -static heap_t _heap; - -void heap_init(u32 base) -{ - _heap_create(&_heap, base); -} - -void *malloc(u32 size) -{ - return (void *)_heap_alloc(&_heap, size); -} - -void *calloc(u32 num, u32 size) -{ - void *res = (void *)_heap_alloc(&_heap, num * size); - memset(res, 0, num * size); - return res; -} - -void free(void *buf) -{ - if (buf != NULL) - _heap_free(&_heap, (u32)buf); -} diff --git a/ariane/src/lib/heap.h b/ariane/src/lib/heap.h deleted file mode 100644 index 6266a09..0000000 --- a/ariane/src/lib/heap.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -* Copyright (c) 2018 naehrwert -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#ifndef _HEAP_H_ -#define _HEAP_H_ - -#include "hwinit/types.h" - -void heap_init(u32 base); -void *malloc(u32 size); -void *calloc(u32 num, u32 size); -void free(void *buf); - -#endif diff --git a/ariane/src/lib/integer.h b/ariane/src/lib/integer.h deleted file mode 100644 index 4fcf5c4..0000000 --- a/ariane/src/lib/integer.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-------------------------------------------*/ -/* Integer type definitions for FatFs module */ -/*-------------------------------------------*/ - -#ifndef FF_INTEGER -#define FF_INTEGER - -#ifdef _WIN32 /* FatFs development platform */ - -#include -#include -typedef unsigned __int64 QWORD; - - -#else /* Embedded platform */ - -/* These types MUST be 16-bit or 32-bit */ -typedef int INT; -typedef unsigned int UINT; - -/* This type MUST be 8-bit */ -typedef unsigned char BYTE; - -/* These types MUST be 16-bit */ -typedef short SHORT; -typedef unsigned short WORD; -typedef unsigned short WCHAR; - -/* These types MUST be 32-bit */ -typedef long LONG; -typedef unsigned long DWORD; - -/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ -typedef unsigned long long QWORD; - -#endif - -#endif diff --git a/ariane/src/lib/lz4.c.inc b/ariane/src/lib/lz4.c.inc deleted file mode 100644 index b3be4e5..0000000 --- a/ariane/src/lib/lz4.c.inc +++ /dev/null @@ -1,280 +0,0 @@ -/* - LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2015, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - - -/************************************** -* Reading and writing into memory -**************************************/ - -/* customized variant of memcpy, which can overwrite up to 7 bytes beyond dstEnd */ -static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) -{ - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; - -#if 0 - const size_t l2 = 8 - (((size_t)d) & (sizeof(void*)-1)); - LZ4_copy8(d,s); if (d>e-9) return; - d+=l2; s+=l2; -#endif /* join to align */ - - do { LZ4_copy8(d,s); d+=8; s+=8; } while (d= op) && (ip < oend)); - - - /* Special cases */ - if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - - - /* Main Loop */ - while (1) - { - unsigned token; - size_t length; - const BYTE* match; - size_t offset; - - if (unlikely((inPlaceDecode) && (op + WILDCOPYLENGTH > ip))) goto _output_error; /* output stream ran over input stream */ - - /* get literal length */ - token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) - { - unsigned s; - do - { - s = *ip++; - length += s; - } - while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH))) - { - if (partialDecoding) - { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } - else - { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - memmove(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; op = cpy; - - /* get offset */ - offset = LZ4_readLE16(ip); ip+=2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) - { - unsigned s; - do - { - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; - s = *ip++; - length += s; - } while (s==255); - if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) - { - if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix-match)) - { - /* match can be copied as a single segment from external dictionary */ - match = dictEnd - (lowPrefix-match); - memmove(op, match, length); op += length; - } - else - { - /* match encompass external dictionary and current block */ - size_t copySize = (size_t)(lowPrefix-match); - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - copySize = length - copySize; - if (copySize > (size_t)(op-lowPrefix)) /* overlap copy */ - { - BYTE* const endOfMatch = op + copySize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; - } - else - { - memcpy(op, lowPrefix, copySize); - op += copySize; - } - } - continue; - } - - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) - { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { LZ4_copy8(op, match); match+=8; } - op += 8; - - if (unlikely(cpy>oend-12)) - { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - if (op < oCopyLimit) - { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op -#include -#include "hwinit/types.h" - -static inline uint16_t read_le16(const void *src) -{ - const uint8_t *s = src; - return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0); -} - -static inline uint32_t read_le32(const void *src) -{ - const uint8_t *s = src; - return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) | - (((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0); -} - -/* LZ4 comes with its own supposedly portable memory access functions, but they - * seem to be very inefficient in practice (at least on ARM64). Since coreboot - * knows about endinaness and allows some basic assumptions (such as unaligned - * access support), we can easily write the ones we need ourselves. */ -static uint16_t LZ4_readLE16(const void *src) -{ - return read_le16(src); -} -static void LZ4_copy8(void *dst, const void *src) -{ -/* ARM32 needs to be a special snowflake to prevent GCC from coalescing the - * access into LDRD/STRD (which don't support unaligned accesses). */ -#ifdef __arm__ /* ARMv < 6 doesn't support unaligned accesses at all. */ - int i; - for (i = 0; i < 8; i++) - ((uint8_t *)dst)[i] = ((uint8_t *)src)[i]; -#elif defined(__riscv) - /* RISC-V implementations may trap on any unaligned access. */ - int i; - for (i = 0; i < 8; i++) - ((uint8_t *)dst)[i] = ((uint8_t *)src)[i]; -#else - *(uint64_t *)dst = *(const uint64_t *)src; -#endif -} - -typedef uint8_t BYTE; -typedef uint16_t U16; -typedef uint32_t U32; -typedef int32_t S32; -typedef uint64_t U64; - -#define FORCE_INLINE static inline __attribute__((always_inline)) -#define likely(expr) __builtin_expect((expr) != 0, 1) -#define unlikely(expr) __builtin_expect((expr) != 0, 0) - -/* Unaltered (just removed unrelated code) from github.com/Cyan4973/lz4/dev. */ -#include "lz4.c.inc" /* #include for inlining, do not link! */ - -int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, - endOnInputSize, 0, 0, noDict, - (BYTE*)dest, NULL, 0); -} - -#define LZ4F_MAGICNUMBER 0x184D2204 - -struct lz4_frame_header { - uint32_t magic; - union { - uint8_t flags; - struct { - uint8_t reserved0 : 2; - uint8_t has_content_checksum : 1; - uint8_t has_content_size : 1; - uint8_t has_block_checksum : 1; - uint8_t independent_blocks : 1; - uint8_t version : 2; - }; - }; - union { - uint8_t block_descriptor; - struct { - uint8_t reserved1 : 4; - uint8_t max_block_size : 3; - uint8_t reserved2 : 1; - }; - }; - /* + uint64_t content_size iff has_content_size is set */ - /* + uint8_t header_checksum */ -} __packed; - -struct lz4_block_header { - union { - uint32_t raw; - struct { - uint32_t size : 31; - uint32_t not_compressed : 1; - }; - }; - /* + size bytes of data */ - /* + uint32_t block_checksum iff has_block_checksum is set */ -} __packed; - -size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn) -{ - const void *in = src; - void *out = dst; - size_t out_size = 0; - int has_block_checksum; - - { /* With in-place decompression the header may become invalid later. */ - const struct lz4_frame_header *h = in; - - if (srcn < sizeof(*h) + sizeof(uint64_t) + sizeof(uint8_t)) - return 0; /* input overrun */ - - /* We assume there's always only a single, standard frame. */ - if (read_le32(&h->magic) != LZ4F_MAGICNUMBER || h->version != 1) - return 0; /* unknown format */ - - if (h->reserved0 || h->reserved1 || h->reserved2) - return 0; /* reserved must be zero */ - - if (!h->independent_blocks) - return 0; /* we don't support block dependency */ - - has_block_checksum = h->has_block_checksum; - - in += sizeof(*h); - - if (h->has_content_size) - { - const size_t content_size = read_le32(in); - if (content_size > dstn) - return content_size; - - in += sizeof(uint64_t); - } - in += sizeof(uint8_t); - } - - while (1) { - struct lz4_block_header b = { { .raw = read_le32(in) } }; - in += sizeof(struct lz4_block_header); - - if ((size_t)(in - src) + b.size > srcn) - break; /* input overrun */ - - if (!b.size) { - out_size = out - dst; - break; /* decompression successful */ - } - - if (b.not_compressed) { - size_t size = MIN((uintptr_t)b.size, (uintptr_t)dst - + dstn - (uintptr_t)out); - memcpy(out, in, size); - if (size < b.size) - break; /* output overrun */ - out += size; - } else { - /* constant folding essential, do not touch params! */ - int ret = LZ4_decompress_generic(in, out, b.size, - dst + dstn - out, endOnInputSize, - full, 0, noDict, out, NULL, 0); - if (ret < 0) - break; /* decompression error */ - - out += ret; - } - - in += b.size; - if (has_block_checksum) - in += sizeof(uint32_t); - } - - return out_size; -} \ No newline at end of file diff --git a/ariane/src/lib/lzma.c b/ariane/src/lib/lzma.c deleted file mode 100644 index 718d69a..0000000 --- a/ariane/src/lib/lzma.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * coreboot interface to memory-saving variant of LZMA decoder - * - * Copyright (C) 2006 Carl-Daniel Hailfinger - * Released under the GNU GPL v2 or later - * - * Parts of this file are based on C/7zip/Compress/LZMA_C/LzmaTest.c from the - * LZMA SDK 4.42, which is written and distributed to public domain by Igor - * Pavlov. - * - */ - -#include "printk.h" -#include - -#include "lzmadecode.h" - -size_t ulzman(const void *src, size_t srcn, void *dst, size_t dstn) -{ - unsigned char properties[LZMA_PROPERTIES_SIZE]; - const int data_offset = LZMA_PROPERTIES_SIZE + 8; - UInt32 outSize; - SizeT inProcessed; - SizeT outProcessed; - int res; - CLzmaDecoderState state; - SizeT mallocneeds; - unsigned char scratchpad[15980]; - const unsigned char *cp; - - memcpy(properties, src, LZMA_PROPERTIES_SIZE); - /* The outSize in LZMA stream is a 64bit integer stored in little-endian - * (ref: lzma.cc@LZMACompress: put_64). To prevent accessing by - * unaligned memory address and to load in correct endianness, read each - * byte and re-construct. */ - cp = src + LZMA_PROPERTIES_SIZE; - outSize = cp[3] << 24 | cp[2] << 16 | cp[1] << 8 | cp[0]; - if (LzmaDecodeProperties(&state.Properties, properties, - LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) { - printk("lzma: Incorrect stream properties.\n"); - return 0; - } - mallocneeds = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); - if (mallocneeds > sizeof(scratchpad)) { - printk("lzma: Decoder scratchpad too small, needs %u bytes!\n", (UInt32)mallocneeds); - return 0; - } - if (outSize > dstn) - return outSize; - - state.Probs = (CProb *)scratchpad; - res = LzmaDecode(&state, src + data_offset, srcn - data_offset, - &inProcessed, dst, outSize, &outProcessed); - if (res != 0) { - printk("lzma: Decoding error = %d\n", res); - return 0; - } - return outProcessed; -} diff --git a/ariane/src/lib/lzmadecode.c b/ariane/src/lib/lzmadecode.c deleted file mode 100644 index 85db931..0000000 --- a/ariane/src/lib/lzmadecode.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - LzmaDecode.c - LZMA Decoder (optimized for Speed version) - - LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) - http://www.7-zip.org/ - - LZMA SDK is licensed under two licenses: - 1) GNU Lesser General Public License (GNU LGPL) - 2) Common Public License (CPL) - It means that you can select one of these two licenses and - follow rules of that license. - - SPECIAL EXCEPTION: - Igor Pavlov, as the author of this Code, expressly permits you to - statically or dynamically link your Code (or bind by name) to the - interfaces of this file without subjecting your linked Code to the - terms of the CPL or GNU LGPL. Any modifications or additions - to this file, however, are subject to the LGPL or CPL terms. -*/ - -#include "lzmadecode.h" -#include - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -/* Use 32-bit reads whenever possible to avoid bad flash performance. Fall back - * to byte reads for last 4 bytes since RC_TEST returns an error when BufferLim - * is *reached* (not surpassed!), meaning we can't allow that to happen while - * there are still bytes to decode from the algorithm's point of view. */ -#define RC_READ_BYTE \ - (look_ahead_ptr < 4 ? look_ahead.raw[look_ahead_ptr++] \ - : ((((uintptr_t) Buffer & 3) \ - || ((SizeT) (BufferLim - Buffer) <= 4)) ? (*Buffer++) \ - : ((look_ahead.dw = *(UInt32 *)Buffer), (Buffer += 4), \ - (look_ahead_ptr = 1), look_ahead.raw[0]))) - -#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ -{ \ - int i; \ - \ - for (i = 0; i < 5; i++) { \ - RC_TEST; \ - Code = (Code << 8) | RC_READ_BYTE; \ - } \ -} - - -#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } - -#define RC_INIT(buffer, bufferSize) Buffer = buffer; \ - BufferLim = buffer + bufferSize; RC_INIT2 - - -#define RC_NORMALIZE \ - if (Range < kTopValue) { \ - RC_TEST; \ - Range <<= 8; \ - Code = (Code << 8) | RC_READ_BYTE; \ - } - -#define IfBit0(p) \ - RC_NORMALIZE; \ - bound = (Range >> kNumBitModelTotalBits) * *(p); \ - if (Code < bound) - -#define UpdateBit0(p) \ - Range = bound; \ - *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits - -#define UpdateBit1(p) \ - Range -= bound; \ - Code -= bound; \ - *(p) -= (*(p)) >> kNumMoveBits - -#define RC_GET_BIT2(p, mi, A0, A1) \ - IfBit0(p) { \ - UpdateBit0(p); \ - mi <<= 1; \ - A0; \ - } else { \ - UpdateBit1(p); \ - mi = (mi + mi) + 1; \ - A1; \ - } - -#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ;, ;) - -#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ -{ \ - int i = numLevels; \ - \ - res = 1; \ - do { \ - CProb *cp = probs + res; \ - RC_GET_BIT(cp, res) \ - } while (--i != 0); \ - res -= (1 << numLevels); \ -} - - -#define kNumPosBitsMax 4 -#define kNumPosStatesMax (1 << kNumPosBitsMax) - -#define kLenNumLowBits 3 -#define kLenNumLowSymbols (1 << kLenNumLowBits) -#define kLenNumMidBits 3 -#define kLenNumMidSymbols (1 << kLenNumMidBits) -#define kLenNumHighBits 8 -#define kLenNumHighSymbols (1 << kLenNumHighBits) - -#define LenChoice 0 -#define LenChoice2 (LenChoice + 1) -#define LenLow (LenChoice2 + 1) -#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) -#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) -#define kNumLenProbs (LenHigh + kLenNumHighSymbols) - - -#define kNumStates 12 -#define kNumLitStates 7 - -#define kStartPosModelIndex 4 -#define kEndPosModelIndex 14 -#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) - -#define kNumPosSlotBits 6 -#define kNumLenToPosStates 4 - -#define kNumAlignBits 4 -#define kAlignTableSize (1 << kNumAlignBits) - -#define kMatchMinLen 2 - -#define IsMatch 0 -#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) -#define IsRepG0 (IsRep + kNumStates) -#define IsRepG1 (IsRepG0 + kNumStates) -#define IsRepG2 (IsRepG1 + kNumStates) -#define IsRep0Long (IsRepG2 + kNumStates) -#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) -#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) -#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) -#define LenCoder (Align + kAlignTableSize) -#define RepLenCoder (LenCoder + kNumLenProbs) -#define Literal (RepLenCoder + kNumLenProbs) - -#if Literal != LZMA_BASE_SIZE -StopCompilingDueBUG -#endif - -int LzmaDecodeProperties(CLzmaProperties *propsRes, - const unsigned char *propsData, int size) -{ - unsigned char prop0; - if (size < LZMA_PROPERTIES_SIZE) - return LZMA_RESULT_DATA_ERROR; - prop0 = propsData[0]; - if (prop0 >= (9 * 5 * 5)) - return LZMA_RESULT_DATA_ERROR; - { - for (propsRes->pb = 0; prop0 >= (9 * 5); - propsRes->pb++, prop0 -= (9 * 5)) - ; - for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9) - ; - propsRes->lc = prop0; - /* - * unsigned char remainder = (unsigned char)(prop0 / 9); - * propsRes->lc = prop0 % 9; - * propsRes->pb = remainder / 5; - * propsRes->lp = remainder % 5; - */ - } - - return LZMA_RESULT_OK; -} - -#define kLzmaStreamWasFinishedId (-1) - -int LzmaDecode(CLzmaDecoderState *vs, - const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, - unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) -{ - CProb *p = vs->Probs; - SizeT nowPos = 0; - Byte previousByte = 0; - UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; - UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; - int lc = vs->Properties.lc; - - - int state = 0; - UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; - int len = 0; - const Byte *Buffer; - const Byte *BufferLim; - int look_ahead_ptr = 4; - union { - Byte raw[4]; - UInt32 dw; - } look_ahead; - UInt32 Range; - UInt32 Code; - - *inSizeProcessed = 0; - *outSizeProcessed = 0; - - { - UInt32 i; - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc - + vs->Properties.lp)); - for (i = 0; i < numProbs; i++) - p[i] = kBitModelTotal >> 1; - } - - RC_INIT(inStream, inSize); - - - while (nowPos < outSize) { - CProb *prob; - UInt32 bound; - int posState = (int)((nowPos)&posStateMask); - - prob = p + IsMatch + (state << kNumPosBitsMax) + posState; - IfBit0(prob) { - int symbol = 1; - UpdateBit0(prob); - prob = p + Literal + (LZMA_LIT_SIZE * - ((((nowPos) & literalPosMask) << lc) - + (previousByte >> (8 - lc)))); - - if (state >= kNumLitStates) { - int matchByte; - matchByte = outStream[nowPos - rep0]; - do { - int bit; - CProb *probLit; - matchByte <<= 1; - bit = (matchByte & 0x100); - probLit = prob + 0x100 + bit + symbol; - RC_GET_BIT2(probLit, symbol, - if (bit != 0) - break, - if (bit == 0) - break) - } while (symbol < 0x100); - } - while (symbol < 0x100) { - CProb *probLit = prob + symbol; - RC_GET_BIT(probLit, symbol) - } - previousByte = (Byte)symbol; - - outStream[nowPos++] = previousByte; - if (state < 4) - state = 0; - else if (state < 10) - state -= 3; - else - state -= 6; - } else { - UpdateBit1(prob); - prob = p + IsRep + state; - IfBit0(prob) { - UpdateBit0(prob); - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - state = state < kNumLitStates ? 0 : 3; - prob = p + LenCoder; - } else { - UpdateBit1(prob); - prob = p + IsRepG0 + state; - IfBit0(prob) { - UpdateBit0(prob); - prob = p + IsRep0Long - + (state << kNumPosBitsMax) - + posState; - IfBit0(prob) { - UpdateBit0(prob); - - if (nowPos == 0) - return LZMA_RESULT_DATA_ERROR; - - state = state < kNumLitStates - ? 9 : 11; - previousByte = outStream[nowPos - - rep0]; - outStream[nowPos++] = - previousByte; - - continue; - } else - { - UpdateBit1(prob); - } - } else { - UInt32 distance; - UpdateBit1(prob); - prob = p + IsRepG1 + state; - IfBit0(prob) { - UpdateBit0(prob); - distance = rep1; - } else { - UpdateBit1(prob); - prob = p + IsRepG2 + state; - IfBit0(prob) { - UpdateBit0(prob); - distance = rep2; - } else { - UpdateBit1(prob); - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < kNumLitStates ? 8 : 11; - prob = p + RepLenCoder; - } - { - int numBits, offset; - CProb *probLen = prob + LenChoice; - IfBit0(probLen) { - UpdateBit0(probLen); - probLen = prob + LenLow - + (posState << kLenNumLowBits); - offset = 0; - numBits = kLenNumLowBits; - } else { - UpdateBit1(probLen); - probLen = prob + LenChoice2; - IfBit0(probLen) { - UpdateBit0(probLen); - probLen = prob + LenMid - + (posState << - kLenNumMidBits); - offset = kLenNumLowSymbols; - numBits = kLenNumMidBits; - } else { - UpdateBit1(probLen); - probLen = prob + LenHigh; - offset = kLenNumLowSymbols - + kLenNumMidSymbols; - numBits = kLenNumHighBits; - } - } - RangeDecoderBitTreeDecode(probLen, numBits, - len); - len += offset; - } - - if (state < 4) { - int posSlot; - state += kNumLitStates; - prob = p + PosSlot + - ((len < kNumLenToPosStates ? len : - kNumLenToPosStates - 1) << - kNumPosSlotBits); - RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, - posSlot); - if (posSlot >= kStartPosModelIndex) { - int numDirectBits = ((posSlot >> 1) - - 1); - rep0 = (2 | ((UInt32)posSlot & 1)); - if (posSlot < kEndPosModelIndex) { - rep0 <<= numDirectBits; - prob = p + SpecPos + rep0 - - posSlot - 1; - } else { - numDirectBits -= kNumAlignBits; - do { - RC_NORMALIZE - Range >>= 1; - rep0 <<= 1; - if (Code >= Range) { - Code -= Range; - rep0 |= 1; - } - } while (--numDirectBits != 0); - prob = p + Align; - rep0 <<= kNumAlignBits; - numDirectBits = kNumAlignBits; - } - { - int i = 1; - int mi = 1; - do { - CProb *prob3 = prob - + mi; - RC_GET_BIT2(prob3, mi, - ;, rep0 |= i); - i <<= 1; - } while (--numDirectBits != 0); - } - } else - rep0 = posSlot; - if (++rep0 == (UInt32)(0)) { - /* it's for stream version */ - len = kLzmaStreamWasFinishedId; - break; - } - } - - len += kMatchMinLen; - if (rep0 > nowPos) - return LZMA_RESULT_DATA_ERROR; - - - do { - previousByte = outStream[nowPos - rep0]; - len--; - outStream[nowPos++] = previousByte; - } while (len != 0 && nowPos < outSize); - } - } - RC_NORMALIZE; - - - *inSizeProcessed = (SizeT)(Buffer - inStream); - *outSizeProcessed = nowPos; - return LZMA_RESULT_OK; -} diff --git a/ariane/src/lib/lzmadecode.h b/ariane/src/lib/lzmadecode.h deleted file mode 100644 index 9ed352a..0000000 --- a/ariane/src/lib/lzmadecode.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - LzmaDecode.h - LZMA Decoder interface - - LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) - http://www.7-zip.org/ - - LZMA SDK is licensed under two licenses: - 1) GNU Lesser General Public License (GNU LGPL) - 2) Common Public License (CPL) - It means that you can select one of these two licenses and - follow rules of that license. - - SPECIAL EXCEPTION: - Igor Pavlov, as the author of this code, expressly permits you to - statically or dynamically link your code (or bind by name) to the - interfaces of this file without subjecting your linked code to the - terms of the CPL or GNU LGPL. Any modifications or additions - to this file, however, are subject to the LGPL or CPL terms. -*/ - -#ifndef __LZMADECODE_H -#define __LZMADECODE_H - -typedef unsigned char Byte; -typedef unsigned short UInt16; -typedef unsigned int UInt32; -typedef UInt32 SizeT; - -#define CProb UInt16 - -#define LZMA_RESULT_OK 0 -#define LZMA_RESULT_DATA_ERROR 1 - - -#define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LZMA_PROPERTIES_SIZE 5 - -typedef struct _CLzmaProperties { - int lc; - int lp; - int pb; -} CLzmaProperties; - -int LzmaDecodeProperties(CLzmaProperties *propsRes, - const unsigned char *propsData, int size); - -#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE \ - << ((Properties)->lc + (Properties)->lp))) - -#define kLzmaNeedInitId (-2) - -typedef struct _CLzmaDecoderState { - CLzmaProperties Properties; - CProb *Probs; -} CLzmaDecoderState; - - -int LzmaDecode(CLzmaDecoderState *vs, - const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, - unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); - -#endif diff --git a/ariane/src/lib/printk.c b/ariane/src/lib/printk.c deleted file mode 100644 index d7b47ae..0000000 --- a/ariane/src/lib/printk.c +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Kernel print functions. - */ - -#include "printk.h" - -#include "vsprintf.h" -#include "../display/video_fb.h" -#ifdef DEBUG_UART_PORT -#include "../hwinit/uart.h" -#endif - -/** - * Temporary stand-in main printk. - * - * TODO: This should print via UART, console framebuffer, and to a ring for - * consumption by Horizon - */ -void printk(char *fmt, ...) -{ - va_list list; - va_start(list, fmt); - vprintk(fmt, list); - va_end(list); -} - -void vprintk(char *fmt, va_list args) -{ - char buf[512]; - vsnprintf(buf, sizeof(buf), fmt, args); - video_puts(buf); -} - -void dbg_print(char *fmt, ...) -{ - va_list list; - va_start(list, fmt); - dbg_vprint(fmt, list); - va_end(list); -} - -void dbg_vprint(char *fmt, va_list args) -{ - char buf[512]; - int numChars = vsnprintf(buf, sizeof(buf), fmt, args); -#ifdef DEBUG_UART_PORT - uart_print(DEBUG_UART_PORT, buf, numChars); -#else - (void)numChars; - video_puts(buf); -#endif -} - -int snprintfk(char *buf, unsigned int bufSize, const char* fmt, ...) -{ - va_list list; - va_start(list, fmt); - int outVal = vsnprintf(buf, bufSize, fmt, list); - va_end(list); - - return outVal; -} diff --git a/ariane/src/lib/printk.h b/ariane/src/lib/printk.h deleted file mode 100644 index 46c13af..0000000 --- a/ariane/src/lib/printk.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __PRINTK_H__ -#define __PRINTK_H__ - -#include - -void printk(char *fmt, ...); -void vprintk(char *fmt, va_list args); -void dbg_print(char* fmt, ...); -void dbg_vprint(char* fmt, va_list args); -int snprintfk(char *buf, unsigned int bufSize, const char* fmt, ...); - -#endif diff --git a/ariane/src/lib/vsprintf.c b/ariane/src/lib/vsprintf.c deleted file mode 100644 index d934144..0000000 --- a/ariane/src/lib/vsprintf.c +++ /dev/null @@ -1,1676 +0,0 @@ -/* - * Copyright (C) 2011 Andrei Warkentin - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * linux/lib/vsprintf.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ -/* - * Wirzenius wrote this portably, Torvalds fucked it up :-) - */ - -/* - * Fri Jul 13 2001 Crutcher Dunnavant - * - changed to provide snprintf and vsnprintf functions - * So Feb 1 16:51:32 CET 2004 Juergen Quade - * - scnprintf and vscnprintf - */ - -#include -#include -#include -#include -#include - -#include "vsprintf.h" - -#define USHRT_MAX ((uint16_t)(~0U)) -#define SHRT_MAX ((int16_t)(USHRT_MAX>>1)) -#define SHRT_MIN ((int16_t)(-SHRT_MAX - 1)) -#define INT_MAX ((int)(~0U>>1)) -#define INT_MIN (-INT_MAX - 1) -#define UINT_MAX (~0U) -#define LONG_MAX ((long)(~0UL>>1)) -#define LONG_MIN (-LONG_MAX - 1) -#define ULONG_MAX (~0UL) - -typedef _Bool bool_t; - -#define do_div(n,base) ({\ - uint32_t __base = (base);\ - uint32_t __rem;\ - __rem = ((uint64_t)(n)) % __base;\ - (n) = ((uint64_t)(n)) / __base;\ - __rem;\ - }) - -const char hex_asc[] = "0123456789abcdef"; -#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] -#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] - -static inline char *pack_hex_byte(char *buf, uint8_t byte) -{ - *buf++ = hex_asc_hi(byte); - *buf++ = hex_asc_lo(byte); - return buf; -} - -/** - * skip_spaces - Removes leading whitespace from @str. - * @str: The string to be stripped. - * - * Returns a pointer to the first non-whitespace character in @str. - */ -static char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} - - -/* Works only for digits and letters, but small and fast */ -#define TOLOWER(x) ((x) | 0x20) - -static unsigned int simple_guess_base(const char *cp) -{ - if (cp[0] == '0') { - if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) - return 16; - else - return 8; - } else { - return 10; - } -} - -/** - * simple_strtoull - convert a string to an unsigned long long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - */ -unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) -{ - unsigned long long result = 0; - - if (!base) - base = simple_guess_base(cp); - - if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') - cp += 2; - - while (isxdigit(*cp)) { - unsigned int value; - - value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; - if (value >= base) - break; - result = result * base + value; - cp++; - } - if (endp) - *endp = (char *)cp; - - return result; -} - -/** - * simple_strtoul - convert a string to an unsigned long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - */ -unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) -{ - return simple_strtoull(cp, endp, base); -} - -/** - * simple_strtol - convert a string to a signed long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - */ -long simple_strtol(const char *cp, char **endp, unsigned int base) -{ - if (*cp == '-') - return -simple_strtoul(cp + 1, endp, base); - - return simple_strtoul(cp, endp, base); -} - -/** - * simple_strtoll - convert a string to a signed long long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - */ -long long simple_strtoll(const char *cp, char **endp, unsigned int base) -{ - if (*cp == '-') - return -simple_strtoull(cp + 1, endp, base); - - return simple_strtoull(cp, endp, base); -} - -static -int skip_atoi(const char **s) -{ - int i = 0; - - while (isdigit(**s)) - i = i*10 + *((*s)++) - '0'; - - return i; -} - -/* Decimal conversion is by far the most typical, and is used - * for /proc and /sys data. This directly impacts e.g. top performance - * with many processes running. We optimize it for speed - * using code from - * http://www.cs.uiowa.edu/~jones/bcd/decimal.html - * (with permission from the author, Douglas W. Jones). */ - -/* Formats correctly any integer in [0,99999]. - * Outputs from one to five digits depending on input. - * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ -static -char *put_dec_trunc(char *buf, unsigned q) -{ - unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); - - d0 = 6*(d3 + d2 + d1) + (q & 0xf); - q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; - *buf++ = d0 + '0'; /* least significant digit */ - d1 = q + 9*d3 + 5*d2 + d1; - if (d1 != 0) { - q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; /* next digit */ - - d2 = q + 2*d2; - if ((d2 != 0) || (d3 != 0)) { - q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; /* next digit */ - - d3 = q + 4*d3; - if (d3 != 0) { - q = (d3 * 0xcd) >> 11; - d3 = d3 - 10*q; - *buf++ = d3 + '0'; /* next digit */ - if (q != 0) - *buf++ = q + '0'; /* most sign. digit */ - } - } - } - - return buf; -} -/* Same with if's removed. Always emits five digits */ -static -char *put_dec_full(char *buf, unsigned q) -{ - /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ - /* but anyway, gcc produces better code with full-sized ints */ - unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); - - /* - * Possible ways to approx. divide by 10 - * gcc -O2 replaces multiply with shifts and adds - * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) - * (x * 0x67) >> 10: 1100111 - * (x * 0x34) >> 9: 110100 - same - * (x * 0x1a) >> 8: 11010 - same - * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) - */ - d0 = 6*(d3 + d2 + d1) + (q & 0xf); - q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; - *buf++ = d0 + '0'; - d1 = q + 9*d3 + 5*d2 + d1; - q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; - - d2 = q + 2*d2; - q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; - - d3 = q + 4*d3; - q = (d3 * 0xcd) >> 11; /* - shorter code */ - /* q = (d3 * 0x67) >> 10; - would also work */ - d3 = d3 - 10*q; - *buf++ = d3 + '0'; - *buf++ = q + '0'; - - return buf; -} -/* No inlining helps gcc to use registers better */ -static -char *put_dec(char *buf, unsigned long long num) -{ - while (1) { - unsigned rem; - if (num < 100000) - return put_dec_trunc(buf, num); - rem = do_div(num, 100000); - buf = put_dec_full(buf, rem); - } -} - -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -#define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ -#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ - -enum format_type { - FORMAT_TYPE_NONE, /* Just a string part */ - FORMAT_TYPE_WIDTH, - FORMAT_TYPE_PRECISION, - FORMAT_TYPE_CHAR, - FORMAT_TYPE_STR, - FORMAT_TYPE_PTR, - FORMAT_TYPE_PERCENT_CHAR, - FORMAT_TYPE_INVALID, - FORMAT_TYPE_LONG_LONG, - FORMAT_TYPE_ULONG, - FORMAT_TYPE_LONG, - FORMAT_TYPE_UBYTE, - FORMAT_TYPE_BYTE, - FORMAT_TYPE_USHORT, - FORMAT_TYPE_SHORT, - FORMAT_TYPE_UINT, - FORMAT_TYPE_INT, - FORMAT_TYPE_NRCHARS, - FORMAT_TYPE_SIZE_T, - FORMAT_TYPE_PTRDIFF -}; - -struct printf_spec { - uint8_t type; /* format_type enum */ - uint8_t flags; /* flags to number() */ - uint8_t base; /* number base, 8, 10 or 16 only */ - uint8_t qualifier; /* number qualifier, one of 'hHlLtzZ' */ - int16_t field_width; /* width of output field */ - int16_t precision; /* # of digits/chars */ -}; - -static -char *number(char *buf, char *end, unsigned long long num, - struct printf_spec spec) -{ - /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ - static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ - - char tmp[66]; - char sign; - char locase; - int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); - int i; - - /* locase = 0 or 0x20. ORing digits or letters with 'locase' - * produces same digits or (maybe lowercased) letters */ - locase = (spec.flags & SMALL); - if (spec.flags & LEFT) - spec.flags &= ~ZEROPAD; - sign = 0; - if (spec.flags & SIGN) { - if ((signed long long)num < 0) { - sign = '-'; - num = -(signed long long)num; - spec.field_width--; - } else if (spec.flags & PLUS) { - sign = '+'; - spec.field_width--; - } else if (spec.flags & SPACE) { - sign = ' '; - spec.field_width--; - } - } - if (need_pfx) { - spec.field_width--; - if (spec.base == 16) - spec.field_width--; - } - - /* generate full string in tmp[], in reverse order */ - i = 0; - if (num == 0) - tmp[i++] = '0'; - /* Generic code, for any base: - else do { - tmp[i++] = (digits[do_div(num,base)] | locase); - } while (num != 0); - */ - else if (spec.base != 10) { /* 8 or 16 */ - int mask = spec.base - 1; - int shift = 3; - - if (spec.base == 16) - shift = 4; - do { - tmp[i++] = (digits[((unsigned char)num) & mask] | locase); - num >>= shift; - } while (num); - } else { /* base 10 */ - i = put_dec(tmp, num) - tmp; - } - - /* printing 100 using %2d gives "100", not "00" */ - if (i > spec.precision) - spec.precision = i; - /* leading space padding */ - spec.field_width -= spec.precision; - if (!(spec.flags & (ZEROPAD+LEFT))) { - while (--spec.field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - } - /* sign */ - if (sign) { - if (buf < end) - *buf = sign; - ++buf; - } - /* "0x" / "0" prefix */ - if (need_pfx) { - if (buf < end) - *buf = '0'; - ++buf; - if (spec.base == 16) { - if (buf < end) - *buf = ('X' | locase); - ++buf; - } - } - /* zero or space padding */ - if (!(spec.flags & LEFT)) { - char c = (spec.flags & ZEROPAD) ? '0' : ' '; - while (--spec.field_width >= 0) { - if (buf < end) - *buf = c; - ++buf; - } - } - /* hmm even more zero padding? */ - while (i <= --spec.precision) { - if (buf < end) - *buf = '0'; - ++buf; - } - /* actual digits of result */ - while (--i >= 0) { - if (buf < end) - *buf = tmp[i]; - ++buf; - } - /* trailing space padding */ - while (--spec.field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - - return buf; -} - -static -char *string(char *buf, char *end, const char *s, struct printf_spec spec) -{ - int len, i; - - if ((unsigned long)s == 0) - s = "(null)"; - - len = strnlen(s, spec.precision); - - if (!(spec.flags & LEFT)) { - while (len < spec.field_width--) { - if (buf < end) - *buf = ' '; - ++buf; - } - } - for (i = 0; i < len; ++i) { - if (buf < end) - *buf = *s; - ++buf; ++s; - } - while (len < spec.field_width--) { - if (buf < end) - *buf = ' '; - ++buf; - } - - return buf; -} - -static -char *uuid_string(char *buf, char *end, const uint8_t *addr, - struct printf_spec spec, const char *fmt) -{ - char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; - char *p = uuid; - int i; - static const uint8_t be[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - static const uint8_t le[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15}; - const uint8_t *index = be; - bool_t uc = false; - - switch (*(++fmt)) { - case 'L': - uc = true; /* fall-through */ - case 'l': - index = le; - break; - case 'B': - uc = true; - break; - } - - for (i = 0; i < 16; i++) { - p = pack_hex_byte(p, addr[index[i]]); - switch (i) { - case 3: - case 5: - case 7: - case 9: - *p++ = '-'; - break; - } - } - - *p = 0; - - if (uc) { - p = uuid; - do { - *p = toupper(*p); - } while (*(++p)); - } - - return string(buf, end, uuid, spec); -} - -int kptr_restrict = 1; - -/* - * Show a '%p' thing. A kernel extension is that the '%p' is followed - * by an extra set of alphanumeric characters that are extended format - * specifiers. - * - * Right now we handle: - * - * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form - * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - * Options for %pU are: - * b big endian lower case hex (default) - * B big endian UPPER case hex - * l little endian lower case hex - * L little endian UPPER case hex - * big endian output byte order is: - * [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15] - * little endian output byte order is: - * [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15] - * - 'V' For a struct va_format which contains a format string * and va_list *, - * call vsnprintf(->format, *->va_list). - * Implements a "recursive vsnprintf". - * Do not use this feature without some mechanism to verify the - * correctness of the format string and va_list arguments. - * - */ -static -char *pointer(const char *fmt, char *buf, char *end, void *ptr, - struct printf_spec spec) -{ - if (!ptr) { - /* - * Print (null) with the same width as a pointer so it makes - * tabular output look nice. - */ - if (spec.field_width == -1) - spec.field_width = 2 * sizeof(void *); - return string(buf, end, "(null)", spec); - } - - switch (*fmt) { - case 'U': - return uuid_string(buf, end, ptr, spec, fmt); - case 'V': - return buf + vsnprintf(buf, end - buf, - ((struct va_format *)ptr)->fmt, - *(((struct va_format *)ptr)->va)); - } - spec.flags |= SMALL; - if (spec.field_width == -1) { - spec.field_width = 2 * sizeof(void *); - spec.flags |= ZEROPAD; - } - spec.base = 16; - - return number(buf, end, (unsigned long) ptr, spec); -} - -/* - * Helper function to decode printf style format. - * Each call decode a token from the format and return the - * number of characters read (or likely the delta where it wants - * to go on the next call). - * The decoded token is returned through the parameters - * - * 'h', 'l', or 'L' for integer fields - * 'z' support added 23/7/1999 S.H. - * 'z' changed to 'Z' --davidm 1/25/99 - * 't' added for ptrdiff_t - * - * @fmt: the format string - * @type of the token returned - * @flags: various flags such as +, -, # tokens.. - * @field_width: overwritten width - * @base: base of the number (octal, hex, ...) - * @precision: precision of a number - * @qualifier: qualifier of a number (long, size_t, ...) - */ -static -int format_decode(const char *fmt, struct printf_spec *spec) -{ - const char *start = fmt; - - /* we finished early by reading the field width */ - if (spec->type == FORMAT_TYPE_WIDTH) { - if (spec->field_width < 0) { - spec->field_width = -spec->field_width; - spec->flags |= LEFT; - } - spec->type = FORMAT_TYPE_NONE; - goto precision; - } - - /* we finished early by reading the precision */ - if (spec->type == FORMAT_TYPE_PRECISION) { - if (spec->precision < 0) - spec->precision = 0; - - spec->type = FORMAT_TYPE_NONE; - goto qualifier; - } - - /* By default */ - spec->type = FORMAT_TYPE_NONE; - - for (; *fmt ; ++fmt) { - if (*fmt == '%') - break; - } - - /* Return the current non-format string */ - if (fmt != start || !*fmt) - return fmt - start; - - /* Process flags */ - spec->flags = 0; - - while (1) { /* this also skips first '%' */ - bool_t found = true; - - ++fmt; - - switch (*fmt) { - case '-': spec->flags |= LEFT; break; - case '+': spec->flags |= PLUS; break; - case ' ': spec->flags |= SPACE; break; - case '#': spec->flags |= SPECIAL; break; - case '0': spec->flags |= ZEROPAD; break; - default: found = false; - } - - if (!found) - break; - } - - /* get field width */ - spec->field_width = -1; - - if (isdigit(*fmt)) - spec->field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_WIDTH; - return ++fmt - start; - } - -precision: - /* get the precision */ - spec->precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) { - spec->precision = skip_atoi(&fmt); - if (spec->precision < 0) - spec->precision = 0; - } else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_PRECISION; - return ++fmt - start; - } - } - -qualifier: - /* get the conversion qualifier */ - spec->qualifier = -1; - if (*fmt == 'h' || TOLOWER(*fmt) == 'l' || - TOLOWER(*fmt) == 'z' || *fmt == 't') { - spec->qualifier = *fmt++; - if (spec->qualifier == *fmt) { - if (spec->qualifier == 'l') { - spec->qualifier = 'L'; - ++fmt; - } else if (spec->qualifier == 'h') { - spec->qualifier = 'H'; - ++fmt; - } - } - } - - /* default base */ - spec->base = 10; - switch (*fmt) { - case 'c': - spec->type = FORMAT_TYPE_CHAR; - return ++fmt - start; - - case 's': - spec->type = FORMAT_TYPE_STR; - return ++fmt - start; - - case 'p': - spec->type = FORMAT_TYPE_PTR; - return fmt - start; - /* skip alnum */ - - case 'n': - spec->type = FORMAT_TYPE_NRCHARS; - return ++fmt - start; - - case '%': - spec->type = FORMAT_TYPE_PERCENT_CHAR; - return ++fmt - start; - - /* integer number formats - set up the flags and "break" */ - case 'o': - spec->base = 8; - break; - - case 'x': - spec->flags |= SMALL; - - case 'X': - spec->base = 16; - break; - - case 'd': - case 'i': - spec->flags |= SIGN; - case 'u': - break; - - default: - spec->type = FORMAT_TYPE_INVALID; - return fmt - start; - } - - if (spec->qualifier == 'L') - spec->type = FORMAT_TYPE_LONG_LONG; - else if (spec->qualifier == 'l') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_LONG; - else - spec->type = FORMAT_TYPE_ULONG; - } else if (TOLOWER(spec->qualifier) == 'z') { - spec->type = FORMAT_TYPE_SIZE_T; - } else if (spec->qualifier == 't') { - spec->type = FORMAT_TYPE_PTRDIFF; - } else if (spec->qualifier == 'H') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_BYTE; - else - spec->type = FORMAT_TYPE_UBYTE; - } else if (spec->qualifier == 'h') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_SHORT; - else - spec->type = FORMAT_TYPE_USHORT; - } else { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_INT; - else - spec->type = FORMAT_TYPE_UINT; - } - - return ++fmt - start; -} - -/** - * vsnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * This function follows C99 vsnprintf, but has some extensions: - * %pS output the name of a text symbol with offset - * %ps output the name of a text symbol without offset - * %pF output the name of a function pointer with its offset - * %pf output the name of a function pointer without its offset - * %pB output the name of a backtrace symbol with its offset - * %pR output the address range in a struct resource with decoded flags - * %pr output the address range in a struct resource with raw flags - * %pM output a 6-byte MAC address with colons - * %pm output a 6-byte MAC address without colons - * %pI4 print an IPv4 address without leading zeros - * %pi4 print an IPv4 address with leading zeros - * %pI6 print an IPv6 address with colons - * %pi6 print an IPv6 address without colons - * %pI6c print an IPv6 address as specified by - * http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 - * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper - * case. - * %n is ignored - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - * - * Call this function if you are already dealing with a va_list. - * You probably want snprintf() instead. - */ -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - unsigned long long num; - char *str, *end; - struct printf_spec spec = {0}; - - str = buf; - end = buf + size; - - /* Make sure end is always >= buf */ - if (end < buf) { - end = ((void *)-1); - size = end - buf; - } - - while (*fmt) { - const char *old_fmt = fmt; - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - spec.field_width = va_arg(args, int); - break; - - case FORMAT_TYPE_PRECISION: - spec.precision = va_arg(args, int); - break; - - case FORMAT_TYPE_CHAR: { - char c; - - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - - } - } - c = (unsigned char) va_arg(args, int); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - } - - case FORMAT_TYPE_STR: - str = string(str, end, va_arg(args, char *), spec); - break; - - case FORMAT_TYPE_PTR: - str = pointer(fmt+1, str, end, va_arg(args, void *), - spec); - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_INVALID: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_NRCHARS: { - uint8_t qualifier = spec.qualifier; - - if (qualifier == 'l') { - long *ip = va_arg(args, long *); - *ip = (str - buf); - } else if (TOLOWER(qualifier) == 'z') { - size_t *ip = va_arg(args, size_t *); - *ip = (str - buf); - } else { - int *ip = va_arg(args, int *); - *ip = (str - buf); - } - break; - } - - default: - switch (spec.type) { - case FORMAT_TYPE_LONG_LONG: - num = va_arg(args, long long); - break; - case FORMAT_TYPE_ULONG: - num = va_arg(args, unsigned long); - break; - case FORMAT_TYPE_LONG: - num = va_arg(args, long); - break; - case FORMAT_TYPE_SIZE_T: - num = va_arg(args, size_t); - break; - case FORMAT_TYPE_PTRDIFF: - num = va_arg(args, ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - num = (unsigned char) va_arg(args, int); - break; - case FORMAT_TYPE_BYTE: - num = (signed char) va_arg(args, int); - break; - case FORMAT_TYPE_USHORT: - num = (unsigned short) va_arg(args, int); - break; - case FORMAT_TYPE_SHORT: - num = (short) va_arg(args, int); - break; - case FORMAT_TYPE_INT: - num = (int) va_arg(args, int); - break; - default: - num = va_arg(args, unsigned int); - } - - str = number(str, end, num, spec); - } - } - - if (size > 0) { - if (str < end) - *str = '\0'; - else - end[-1] = '\0'; - } - - /* the trailing null byte doesn't count towards the total */ - return str-buf; - -} - -/** - * vscnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The return value is the number of characters which have been written into - * the @buf not including the trailing '\0'. If @size is == 0 the function - * returns 0. - * - * Call this function if you are already dealing with a va_list. - * You probably want scnprintf() instead. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int i; - - i = vsnprintf(buf, size, fmt, args); - - if (i < size) - return i; - if (size != 0) - return size - 1; - return 0; -} - -/** - * snprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The return value is the number of characters which would be - * generated for the given input, excluding the trailing null, - * as per ISO C99. If the return is greater than or equal to - * @size, the resulting string is truncated. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int snprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsnprintf(buf, size, fmt, args); - va_end(args); - - return i; -} - -/** - * scnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The return value is the number of characters written into @buf not including - * the trailing '\0'. If @size is == 0 the function returns 0. - */ - -int scnprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vscnprintf(buf, size, fmt, args); - va_end(args); - - return i; -} - -/** - * vsprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The function returns the number of characters written - * into @buf. Use vsnprintf() or vscnprintf() in order to avoid - * buffer overflows. - * - * Call this function if you are already dealing with a va_list. - * You probably want sprintf() instead. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int vsprintf(char *buf, const char *fmt, va_list args) -{ - return vsnprintf(buf, INT_MAX, fmt, args); -} - -/** - * sprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of characters written - * into @buf. Use snprintf() or scnprintf() in order to avoid - * buffer overflows. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int sprintf(char *buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsnprintf(buf, INT_MAX, fmt, args); - va_end(args); - - return i; -} - -#ifdef CONFIG_BINARY_PRINTF -/* - * bprintf service: - * vbin_printf() - VA arguments to binary data - * bstr_printf() - Binary data to text string - */ - -/** - * vbin_printf - Parse a format string and place args' binary value in a buffer - * @bin_buf: The buffer to place args' binary value - * @size: The size of the buffer(by words(32bits), not characters) - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The format follows C99 vsnprintf, except %n is ignored, and its argument - * is skiped. - * - * The return value is the number of words(32bits) which would be generated for - * the given input. - * - * NOTE: - * If the return value is greater than @size, the resulting bin_buf is NOT - * valid for bstr_printf(). - */ -int vbin_printf(uint32_t *bin_buf, size_t size, const char *fmt, va_list args) -{ - struct printf_spec spec = {0}; - char *str, *end; - - str = (char *)bin_buf; - end = (char *)(bin_buf + size); - -#define save_arg(type) \ -do { \ - if (sizeof(type) == 8) { \ - unsigned long long value; \ - str = PTR_ALIGN(str, sizeof(uint32_t)); \ - value = va_arg(args, unsigned long long); \ - if (str + sizeof(type) <= end) { \ - *(uint32_t *)str = *(uint32_t *)&value; \ - *(uint32_t *)(str + 4) = *((uint32_t *)&value + 1); \ - } \ - } else { \ - unsigned long value; \ - str = PTR_ALIGN(str, sizeof(type)); \ - value = va_arg(args, int); \ - if (str + sizeof(type) <= end) \ - *(typeof(type) *)str = (type)value; \ - } \ - str += sizeof(type); \ -} while (0) - - while (*fmt) { - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: - case FORMAT_TYPE_INVALID: - case FORMAT_TYPE_PERCENT_CHAR: - break; - - case FORMAT_TYPE_WIDTH: - case FORMAT_TYPE_PRECISION: - save_arg(int); - break; - - case FORMAT_TYPE_CHAR: - save_arg(char); - break; - - case FORMAT_TYPE_STR: { - const char *save_str = va_arg(args, char *); - size_t len; - - if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE - || (unsigned long)save_str < PAGE_SIZE) - save_str = "(null)"; - len = strlen(save_str) + 1; - if (str + len < end) - memcpy(str, save_str, len); - str += len; - break; - } - - case FORMAT_TYPE_PTR: - save_arg(void *); - /* skip all alphanumeric pointer suffixes */ - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_NRCHARS: { - /* skip %n 's argument */ - uint8_t qualifier = spec.qualifier; - void *skip_arg; - if (qualifier == 'l') - skip_arg = va_arg(args, long *); - else if (TOLOWER(qualifier) == 'z') - skip_arg = va_arg(args, size_t *); - else - skip_arg = va_arg(args, int *); - break; - } - - default: - switch (spec.type) { - - case FORMAT_TYPE_LONG_LONG: - save_arg(long long); - break; - case FORMAT_TYPE_ULONG: - case FORMAT_TYPE_LONG: - save_arg(unsigned long); - break; - case FORMAT_TYPE_SIZE_T: - save_arg(size_t); - break; - case FORMAT_TYPE_PTRDIFF: - save_arg(ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - case FORMAT_TYPE_BYTE: - save_arg(char); - break; - case FORMAT_TYPE_USHORT: - case FORMAT_TYPE_SHORT: - save_arg(short); - break; - default: - save_arg(int); - } - } - } - - return (uint32_t *)(PTR_ALIGN(str, sizeof(uint32_t))) - bin_buf; -#undef save_arg -} - -/** - * bstr_printf - Format a string from binary arguments and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @bin_buf: Binary arguments for the format string - * - * This function like C99 vsnprintf, but the difference is that vsnprintf gets - * arguments from stack, and bstr_printf gets arguments from @bin_buf which is - * a binary buffer that generated by vbin_printf. - * - * The format follows C99 vsnprintf, but has some extensions: - * see vsnprintf comment for details. - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - */ -int bstr_printf(char *buf, size_t size, const char *fmt, const uint32_t *bin_buf) -{ - struct printf_spec spec = {0}; - char *str, *end; - const char *args = (const char *)bin_buf; - - if (WARN_ON_ONCE((int) size < 0)) - return 0; - - str = buf; - end = buf + size; - -#define get_arg(type) \ -({ \ - typeof(type) value; \ - if (sizeof(type) == 8) { \ - args = PTR_ALIGN(args, sizeof(uint32_t)); \ - *(uint32_t *)&value = *(uint32_t *)args; \ - *((uint32_t *)&value + 1) = *(uint32_t *)(args + 4); \ - } else { \ - args = PTR_ALIGN(args, sizeof(type)); \ - value = *(typeof(type) *)args; \ - } \ - args += sizeof(type); \ - value; \ -}) - - /* Make sure end is always >= buf */ - if (end < buf) { - end = ((void *)-1); - size = end - buf; - } - - while (*fmt) { - const char *old_fmt = fmt; - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - spec.field_width = get_arg(int); - break; - - case FORMAT_TYPE_PRECISION: - spec.precision = get_arg(int); - break; - - case FORMAT_TYPE_CHAR: { - char c; - - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - } - c = (unsigned char) get_arg(char); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - } - - case FORMAT_TYPE_STR: { - const char *str_arg = args; - args += strlen(str_arg) + 1; - str = string(str, end, (char *)str_arg, spec); - break; - } - - case FORMAT_TYPE_PTR: - str = pointer(fmt+1, str, end, get_arg(void *), spec); - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - case FORMAT_TYPE_INVALID: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_NRCHARS: - /* skip */ - break; - - default: { - unsigned long long num; - - switch (spec.type) { - - case FORMAT_TYPE_LONG_LONG: - num = get_arg(long long); - break; - case FORMAT_TYPE_ULONG: - case FORMAT_TYPE_LONG: - num = get_arg(unsigned long); - break; - case FORMAT_TYPE_SIZE_T: - num = get_arg(size_t); - break; - case FORMAT_TYPE_PTRDIFF: - num = get_arg(ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - num = get_arg(unsigned char); - break; - case FORMAT_TYPE_BYTE: - num = get_arg(signed char); - break; - case FORMAT_TYPE_USHORT: - num = get_arg(unsigned short); - break; - case FORMAT_TYPE_SHORT: - num = get_arg(short); - break; - case FORMAT_TYPE_UINT: - num = get_arg(unsigned int); - break; - default: - num = get_arg(int); - } - - str = number(str, end, num, spec); - } /* default: */ - } /* switch(spec.type) */ - } /* while(*fmt) */ - - if (size > 0) { - if (str < end) - *str = '\0'; - else - end[-1] = '\0'; - } - -#undef get_arg - - /* the trailing null byte doesn't count towards the total */ - return str - buf; -} - -/** - * bprintf - Parse a format string and place args' binary value in a buffer - * @bin_buf: The buffer to place args' binary value - * @size: The size of the buffer(by words(32bits), not characters) - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of words(uint32_t) written - * into @bin_buf. - */ -int bprintf(uint32_t *bin_buf, size_t size, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vbin_printf(bin_buf, size, fmt, args); - va_end(args); - - return ret; -} - -#endif /* CONFIG_BINARY_PRINTF */ - -/** - * vsscanf - Unformat a buffer into a list of arguments - * @buf: input buffer - * @fmt: format of buffer - * @args: arguments - */ -int vsscanf(const char *buf, const char *fmt, va_list args) -{ - const char *str = buf; - char *next; - char digit; - int num = 0; - uint8_t qualifier; - uint8_t base; - int16_t field_width; - bool_t is_sign; - - while (*fmt && *str) { - /* skip any white space in format */ - /* white space in format matchs any amount of - * white space, including none, in the input. - */ - if (isspace(*fmt)) { - fmt = skip_spaces(++fmt); - str = skip_spaces(str); - } - - /* anything that is not a conversion must match exactly */ - if (*fmt != '%' && *fmt) { - if (*fmt++ != *str++) - break; - continue; - } - - if (!*fmt) - break; - ++fmt; - - /* skip this conversion. - * advance both strings to next white space - */ - if (*fmt == '*') { - while (!isspace(*fmt) && *fmt != '%' && *fmt) - fmt++; - while (!isspace(*str) && *str) - str++; - continue; - } - - /* get field width */ - field_width = -1; - if (isdigit(*fmt)) - field_width = skip_atoi(&fmt); - - /* get conversion qualifier */ - qualifier = -1; - if (*fmt == 'h' || TOLOWER(*fmt) == 'l' || - TOLOWER(*fmt) == 'z') { - qualifier = *fmt++; - if (qualifier == *fmt) { - if (qualifier == 'h') { - qualifier = 'H'; - fmt++; - } else if (qualifier == 'l') { - qualifier = 'L'; - fmt++; - } - } - } - - if (!*fmt || !*str) - break; - - base = 10; - is_sign = 0; - - switch (*fmt++) { - case 'c': - { - char *s = (char *)va_arg(args, char*); - if (field_width == -1) - field_width = 1; - do { - *s++ = *str++; - } while (--field_width > 0 && *str); - num++; - } - continue; - case 's': - { - char *s = (char *)va_arg(args, char *); - if (field_width == -1) - field_width = SHRT_MAX; - /* first, skip leading white space in buffer */ - str = skip_spaces(str); - - /* now copy until next white space */ - while (*str && !isspace(*str) && field_width--) - *s++ = *str++; - *s = '\0'; - num++; - } - continue; - case 'n': - /* return number of characters read so far */ - { - int *i = (int *)va_arg(args, int*); - *i = str - buf; - } - continue; - case 'o': - base = 8; - break; - case 'x': - case 'X': - base = 16; - break; - case 'i': - base = 0; - case 'd': - is_sign = 1; - case 'u': - break; - case '%': - /* looking for '%' in str */ - if (*str++ != '%') - return num; - continue; - default: - /* invalid format; stop here */ - return num; - } - - /* have some sort of integer conversion. - * first, skip white space in buffer. - */ - str = skip_spaces(str); - - digit = *str; - if (is_sign && digit == '-') - digit = *(str + 1); - - if (!digit - || (base == 16 && !isxdigit(digit)) - || (base == 10 && !isdigit(digit)) - || (base == 8 && (!isdigit(digit) || digit > '7')) - || (base == 0 && !isdigit(digit))) - break; - - switch (qualifier) { - case 'H': /* that's 'hh' in format */ - if (is_sign) { - signed char *s = (signed char *)va_arg(args, signed char *); - *s = (signed char)simple_strtol(str, &next, base); - } else { - unsigned char *s = (unsigned char *)va_arg(args, unsigned char *); - *s = (unsigned char)simple_strtoul(str, &next, base); - } - break; - case 'h': - if (is_sign) { - short *s = (short *)va_arg(args, short *); - *s = (short)simple_strtol(str, &next, base); - } else { - unsigned short *s = (unsigned short *)va_arg(args, unsigned short *); - *s = (unsigned short)simple_strtoul(str, &next, base); - } - break; - case 'l': - if (is_sign) { - long *l = (long *)va_arg(args, long *); - *l = simple_strtol(str, &next, base); - } else { - unsigned long *l = (unsigned long *)va_arg(args, unsigned long *); - *l = simple_strtoul(str, &next, base); - } - break; - case 'L': - if (is_sign) { - long long *l = (long long *)va_arg(args, long long *); - *l = simple_strtoll(str, &next, base); - } else { - unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *); - *l = simple_strtoull(str, &next, base); - } - break; - case 'Z': - case 'z': - { - size_t *s = (size_t *)va_arg(args, size_t *); - *s = (size_t)simple_strtoul(str, &next, base); - } - break; - default: - if (is_sign) { - int *i = (int *)va_arg(args, int *); - *i = (int)simple_strtol(str, &next, base); - } else { - unsigned int *i = (unsigned int *)va_arg(args, unsigned int*); - *i = (unsigned int)simple_strtoul(str, &next, base); - } - break; - } - num++; - - if (!next) - break; - str = next; - } - - /* - * Now we've come all the way through so either the input string or the - * format ended. In the former case, there can be a %n at the current - * position in the format that needs to be filled. - */ - if (*fmt == '%' && *(fmt + 1) == 'n') { - int *p = (int *)va_arg(args, int *); - *p = str - buf; - } - - return num; -} - -/** - * sscanf - Unformat a buffer into a list of arguments - * @buf: input buffer - * @fmt: formatting of buffer - * @...: resulting arguments - */ -int sscanf(const char *buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsscanf(buf, fmt, args); - va_end(args); - - return i; -} diff --git a/ariane/src/lib/vsprintf.h b/ariane/src/lib/vsprintf.h deleted file mode 100644 index 7b7fea7..0000000 --- a/ariane/src/lib/vsprintf.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2011 Andrei Warkentin - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include - -#ifndef VSPRINTF_H -#define VSPRINTF_H - -struct va_format { - const char *fmt; - va_list *va; -}; - -unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base); - -int sprintf(char *buf, const char *fmt, ...); -int scnprintf(char *buf, size_t size, const char *fmt, ...); -int snprintf(char *buf, size_t size, const char *fmt, ...); -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -int sscanf(const char *buf, const char *fmt, ...); - -#endif /* VSPRINTF_H */ diff --git a/ariane/src/libs/fatfs/diskio.c b/ariane/src/libs/fatfs/diskio.c new file mode 100644 index 0000000..f2f52b0 --- /dev/null +++ b/ariane/src/libs/fatfs/diskio.c @@ -0,0 +1,147 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ +/*-----------------------------------------------------------------------*/ +/* If a working storage control module is available, it should be */ +/* attached to the FatFs via a glue function rather than modifying it. */ +/* This is an example of glue functions to attach various exsisting */ +/* storage control modules to the FatFs module with a defined API. */ +/*-----------------------------------------------------------------------*/ + +#include + +#include /* FatFs lower layer API */ +#include +#include "../../storage/nx_emmc_bis.h" +#include +#include +#include + +/*-----------------------------------------------------------------------*/ +/* Get Drive Status */ +/*-----------------------------------------------------------------------*/ +DSTATUS disk_status ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + return 0; +} + +/*-----------------------------------------------------------------------*/ +/* Inidialize a Drive */ +/*-----------------------------------------------------------------------*/ +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + return 0; +} + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ +DRESULT disk_read ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to read */ +) +{ + switch (pdrv) + { + case DRIVE_SD: + return sdmmc_storage_read(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_RAM: + return ram_disk_read(sector, count, (void *)buff); + case DRIVE_EMMC: + return sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_BIS: + return nx_emmc_bis_read(sector, count, (void *)buff); + } + + return RES_ERROR; +} + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ +DRESULT disk_write ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to write */ +) +{ + switch (pdrv) + { + case DRIVE_SD: + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_RAM: + return ram_disk_write(sector, count, (void *)buff); + case DRIVE_EMMC: + case DRIVE_BIS: + return RES_WRPRT; + } + + return RES_ERROR; +} + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ +static u32 part_rsvd_size = 0; +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DWORD *buf = (DWORD *)buff; + + if (pdrv == DRIVE_SD) + { + switch (cmd) + { + case GET_SECTOR_COUNT: + *buf = sd_storage.sec_cnt - part_rsvd_size; + break; + case GET_BLOCK_SIZE: + *buf = 32768; // Align to 16MB. + break; + } + } + else if (pdrv == DRIVE_RAM) + { + switch (cmd) + { + case GET_SECTOR_COUNT: + *buf = RAM_DISK_SZ >> 9; // 1GB. + break; + case GET_BLOCK_SIZE: + *buf = 2048; // Align to 1MB. + break; + } + } + + return RES_OK; +} + +DRESULT disk_set_info ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DWORD *buf = (DWORD *)buff; + + if (pdrv == DRIVE_SD) + { + switch (cmd) + { + case SET_SECTOR_COUNT: + part_rsvd_size = *buf; + break; + } + } + + return RES_OK; +} diff --git a/ariane/src/libs/fatfs/ffconf.h b/ariane/src/libs/fatfs/ffconf.h new file mode 100644 index 0000000..8eaf8ba --- /dev/null +++ b/ariane/src/libs/fatfs/ffconf.h @@ -0,0 +1,296 @@ +/*---------------------------------------------------------------------------/ +/ FatFs Functional Configurations +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 86604 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define FF_USE_STRFUNC 2 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define FF_USE_FIND 2 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + +#define FF_FASTFS 1 + +#if FF_FASTFS +#undef FF_USE_FASTSEEK +#define FF_USE_FASTSEEK 1 +#endif + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 1 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 1 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 850 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 3 +#define FF_MAX_LFN 255 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN +/ specification. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree() in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_STRF_ENCODE 0 +/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), +/ f_putc(), f_puts and f_printf() convert the character encoding in it. +/ This option selects assumption of character encoding ON THE FILE to be +/ read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +#define FF_FS_RPATH 1 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 4 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 1 +// Order is important. Any change to order, must also be reflected to diskio drive enum. +#define FF_VOLUME_STRS "sd","ram","emmc","bis" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When this function is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define FF_FS_NOFSINFO 1 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 1 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2020 +/* The option FF_FS_NORTC switches timestamp function. If the system does not have +/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable +/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +/* #include // O/S definitions */ +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. +/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + + + +/*--- End of configuration options ---*/ diff --git a/ariane/src/lib/ffsystem.c b/ariane/src/libs/fatfs/ffsystem.c similarity index 52% rename from ariane/src/lib/ffsystem.c rename to ariane/src/libs/fatfs/ffsystem.c index 4851e32..04a3a16 100644 --- a/ariane/src/lib/ffsystem.c +++ b/ariane/src/libs/fatfs/ffsystem.c @@ -1,11 +1,16 @@ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ -/* (C) ChaN, 2017 */ +/* (C) ChaN, 2018 */ +/* (C) CTCaer, 2018 */ /*------------------------------------------------------------------------*/ -#include "ff.h" -#include "heap.h" +#include +//#include "../../config.h" +#include +#include + +//extern nyx_config n_cfg; #if FF_USE_LFN == 3 /* Dynamic memory allocation */ @@ -13,7 +18,7 @@ /* Allocate a memory block */ /*------------------------------------------------------------------------*/ -void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ +void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { @@ -26,10 +31,36 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no /*------------------------------------------------------------------------*/ void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do for null) */ + void* mblock /* Pointer to the memory block to free (nothing to do if null) */ ) { free(mblock); /* Free the memory block with POSIX API */ } #endif + +#if FF_FS_NORTC == 0 + +/*------------------------------------------------------------------------*/ +/* Get real time clock */ +/*------------------------------------------------------------------------*/ + +DWORD get_fattime ( + void +) +{ + rtc_time_t time; + + max77620_rtc_get_time(&time); + /* + if (n_cfg.timeoff) + { + u32 epoch = (u32)((s32)max77620_rtc_date_to_epoch(&time) + (s32)100); + max77620_rtc_epoch_to_date(epoch, &time); + } + */ + return (((DWORD)(time.year - 1980) << 25) | ((DWORD)time.month << 21) | ((DWORD)time.day << 16) | + ((DWORD)time.hour << 11) | ((DWORD)time.min << 5) | (time.sec >> 1)); +} + +#endif diff --git a/ariane/src/libs/hekate_config.c b/ariane/src/libs/hekate_config.c new file mode 100644 index 0000000..015b783 --- /dev/null +++ b/ariane/src/libs/hekate_config.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "hekate_config.h" +#include +#include +//#include "gfx/tui.h" +#include +#include +#include +#include +#include +#include +#include +#include + +extern hekate_config h_cfg; + +void set_default_configuration() +{ + h_cfg.autoboot = 0; + h_cfg.autoboot_list = 0; + h_cfg.bootwait = 3; + h_cfg.se_keygen_done = 0; + h_cfg.backlight = 100; + h_cfg.autohosoff = 0; + h_cfg.autonogc = 1; + h_cfg.updater2p = 0; + h_cfg.brand = NULL; + h_cfg.tagline = NULL; + h_cfg.errors = 0; + h_cfg.eks = NULL; + h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; + h_cfg.aes_slots_new = false; + h_cfg.rcm_patched = fuse_check_patched_rcm(); + h_cfg.emummc_force_disable = false; +} + +int create_config_entry() +{ + if (!sd_mount()) + return 1; + + char lbuf[32]; + FIL fp; + bool mainIniFound = false; + + LIST_INIT(ini_sections); + + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + mainIniFound = true; + else + { + u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); + if (res == FR_NO_FILE || res == FR_NO_PATH) + { + f_mkdir("bootloader"); + f_mkdir("bootloader/ini"); + f_mkdir("bootloader/payloads"); + f_mkdir("bootloader/sys"); + } + else + { + if (!res) + f_close(&fp); + return 1; + } + } + + if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return 1; + // Add config entry. + f_puts("[config]\nautoboot=", &fp); + itoa(h_cfg.autoboot, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); + itoa(h_cfg.autoboot_list, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbootwait=", &fp); + itoa(h_cfg.bootwait, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbacklight=", &fp); + itoa(h_cfg.backlight, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautohosoff=", &fp); + itoa(h_cfg.autohosoff, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautonogc=", &fp); + itoa(h_cfg.autonogc, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nupdater2p=", &fp); + itoa(h_cfg.updater2p, lbuf, 10); + f_puts(lbuf, &fp); + if (h_cfg.brand) + { + f_puts("\nbrand=", &fp); + f_puts(h_cfg.brand, &fp); + } + if (h_cfg.tagline) + { + f_puts("\ntagline=", &fp); + f_puts(h_cfg.tagline, &fp); + } + f_puts("\n", &fp); + + if (mainIniFound) + { + // Re-construct existing entries. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + switch (ini_sec->type) + { + case INI_CHOICE: // Re-construct Boot entry [ ]. + f_puts("[", &fp); + f_puts(ini_sec->name, &fp); + f_puts("]\n", &fp); + // Re-construct boot entry's config. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + f_puts(kv->key, &fp); + f_puts("=", &fp); + f_puts(kv->val, &fp); + f_puts("\n", &fp); + } + break; + case INI_CAPTION: // Re-construct caption entry { }. + f_puts("{", &fp); + f_puts(ini_sec->name, &fp); + f_puts("}\n", &fp); + break; + case INI_NEWLINE: // Re-construct cosmetic newline \n. + f_puts("\n", &fp); + break; + case INI_COMMENT: // Re-construct comment entry #. + f_puts("#", &fp); + f_puts(ini_sec->name, &fp); + f_puts("\n", &fp); + break; + } + } + } + + f_close(&fp); + sd_end(); + + return 0; +} + + +void load_emummc_cfg(emummc_cfg_t *emu_info) +{ + memset(emu_info, 0, sizeof(emummc_cfg_t)); + + // Parse emuMMC configuration. + LIST_INIT(ini_sections); + if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "emummc")) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("enabled", kv->key)) + emu_info->enabled = atoi(kv->val); + else if (!strcmp("sector", kv->key)) + emu_info->sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_info->id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + emu_info->path = kv->val; + else if (!strcmp("nintendo_path", kv->key)) + emu_info->nintendo_path = kv->val; + } + } + } + } +} +/* +#pragma GCC push_options +#pragma GCC optimize ("Os") + +static void _save_config() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (!create_config_entry()) + gfx_puts("\nConfiguration was saved!\n"); + else + EPRINTF("\nConfiguration saving failed!"); + gfx_puts("\nPress any key..."); +} + +static void _config_autoboot_list(void *ent) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) + boot_text[(i - 1) * 512] = ' '; + + else + boot_text[(i - 1) * 512] = '*'; + strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 1) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 1]; + i++; + + if ((i - 1) > max_entries) + break; + } + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 1; + _save_config(); + + ment_t *tmp = (ment_t *)ent; + tmp->data = NULL; + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_end(); +} + +void config_autoboot() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + u32 boot_text_size = 512; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(boot_text_size * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (!h_cfg.autoboot) + ments[2].caption = "*Disable"; + else + ments[2].caption = " Disable"; + ments[2].data = &boot_values[0]; + + ments[3].type = MENT_HDLR_RE; + if (h_cfg.autoboot_list) + ments[3].caption = "*More configs..."; + else + ments[3].caption = " More configs..."; + ments[3].handler = _config_autoboot_list; + ments[3].data = (void *)0xCAFE; + + ments[4].type = MENT_CHGLINE; + + u32 i = 5; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) + boot_text[(i - 4) * boot_text_size] = ' '; + + else + boot_text[(i - 4) * boot_text_size] = '*'; + strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 4) * boot_text_size]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 4]; + i++; + + if ((i - 4) > max_entries) + break; + } + } + if (i < 6 && !h_cfg.autoboot_list) + { + ments[i].type = MENT_CAPTION; + ments[i].caption = "No main configurations found..."; + ments[i].color = 0xFFFFDD00; + i++; + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 0; + _save_config(); + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_end(); + + if (temp_autoboot == NULL) + return; +} + +void config_bootdelay() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 delay_entries = 6; + u32 delay_text_size = 32; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); + u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); + char *delay_text = (char *)malloc(delay_text_size * delay_entries); + + for (u32 j = 0; j < delay_entries; j++) + delay_values[j] = j; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (h_cfg.bootwait) + ments[2].caption = " 0 seconds (Bootlogo disabled)"; + else + ments[2].caption = "*0 seconds (Bootlogo disabled)"; + ments[2].data = &delay_values[0]; + + u32 i = 0; + for (i = 1; i < delay_entries; i++) + { + if (h_cfg.bootwait != i) + delay_text[i * delay_text_size] = ' '; + else + delay_text[i * delay_text_size] = '*'; + delay_text[i * delay_text_size + 1] = i + '0'; + strcpy(delay_text + i * delay_text_size + 2, " seconds"); + + ments[i + 2].type = MENT_DATA; + ments[i + 2].caption = delay_text + (i * delay_text_size); + ments[i + 2].data = &delay_values[i]; + } + + memset(&ments[i + 2], 0, sizeof(ment_t)); + menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; + + u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); + if (temp_bootwait != NULL) + { + h_cfg.bootwait = *(u32 *)temp_bootwait; + _save_config(); + } + + free(ments); + free(delay_values); + free(delay_text); + + if (temp_bootwait == NULL) + return; + btn_wait(); +} + +void config_backlight() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 bri_text_size = 8; + u32 bri_entries = 11; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); + u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); + char *bri_text = (char *)malloc(bri_text_size * bri_entries); + + for (u32 j = 1; j < bri_entries; j++) + bri_values[j] = j * 10; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 0; + for (i = 1; i < bri_entries; i++) + { + if ((h_cfg.backlight / 20) != i) + bri_text[i * bri_text_size] = ' '; + else + bri_text[i * bri_text_size] = '*'; + + if (i < 10) + { + bri_text[i * bri_text_size + 1] = i + '0'; + strcpy(bri_text + i * bri_text_size + 2, "0%"); + } + else + strcpy(bri_text + i * bri_text_size + 1, "100%"); + + ments[i + 1].type = MENT_DATA; + ments[i + 1].caption = bri_text + (i * bri_text_size); + ments[i + 1].data = &bri_values[i]; + } + + memset(&ments[i + 1], 0, sizeof(ment_t)); + menu_t menu = {ments, "Backlight brightness", 0, 0}; + + u32 *temp_backlight = (u32 *)tui_do_menu(&menu); + if (temp_backlight != NULL) + { + h_cfg.backlight = (*(u32 *)temp_backlight) * 2; + _save_config(); + } + + free(ments); + free(bri_values); + free(bri_text); + + if (temp_backlight == NULL) + return; + btn_wait(); +} + +void config_auto_hos_poweroff() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); + u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); + + for (u32 j = 0; j < 3; j++) + { + hp_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &hp_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autohosoff == 1) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Enable"; + ments[4].caption = " Enable (No logo)"; + } + else if (h_cfg.autohosoff >= 2) + { + ments[2].caption = " Disable"; + ments[3].caption = " Enable"; + ments[4].caption = "*Enable (No logo)"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Enable"; + ments[4].caption = " Enable (No logo)"; + } + + memset(&ments[5], 0, sizeof(ment_t)); + menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; + + u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); + if (temp_autohosoff != NULL) + { + h_cfg.autohosoff = *(u32 *)temp_autohosoff; + _save_config(); + } + + free(ments); + free(hp_values); + + if (temp_autohosoff == NULL) + return; + btn_wait(); +} + +void config_nogc() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); + u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); + + for (u32 j = 0; j < 2; j++) + { + cb_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &cb_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autonogc) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Auto"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Auto"; + } + + memset(&ments[4], 0, sizeof(ment_t)); + menu_t menu = {ments, "No Gamecard", 0, 0}; + + u32 *temp_nogc = (u32 *)tui_do_menu(&menu); + if (temp_nogc != NULL) + { + h_cfg.autonogc = *(u32 *)temp_nogc; + _save_config(); + } + + free(ments); + free(cb_values); + + if (temp_nogc == NULL) + return; + btn_wait(); +} + +#pragma GCC pop_options +*/ diff --git a/ariane/src/libs/hekate_config.h b/ariane/src/libs/hekate_config.h new file mode 100644 index 0000000..6bd8775 --- /dev/null +++ b/ariane/src/libs/hekate_config.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "hos/hos.h" +#include +#include "../storage/emummc.h" + +typedef struct _hekate_config +{ + // Non-volatile config. + u32 autoboot; + u32 autoboot_list; + u32 bootwait; + u32 backlight; + u32 autohosoff; + u32 autonogc; + u32 updater2p; + char *brand; + char *tagline; + // Global temporary config. + bool se_keygen_done; + bool sept_run; + bool aes_slots_new; + bool emummc_force_disable; + bool rcm_patched; + u32 errors; + hos_eks_mbr_t *eks; +} hekate_config; + +void set_default_configuration(); +int create_config_entry(); +void config_autoboot(); +void config_bootdelay(); +void config_backlight(); +void config_auto_hos_poweroff(); +void config_nogc(); + +void load_emummc_cfg(emummc_cfg_t *emu_info); + +#endif /* _CONFIG_H_ */ diff --git a/ariane/src/libs/hos/fss.c b/ariane/src/libs/hos/fss.c new file mode 100644 index 0000000..d2bfafc --- /dev/null +++ b/ariane/src/libs/hos/fss.c @@ -0,0 +1,247 @@ +/* + * Atmosphère Fusée Secondary Storage parser. + * + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "fss.h" +#include "hos.h" +#include "../hekate_config.h" +#include +#include +#include "../../storage/emummc.h" +#include + +#include +#define DPRINTF(...) + +extern hekate_config h_cfg; + +extern bool is_ipl_updated(void *buf, char *path, bool force); + +// FSS0 Magic and Meta header offset. +#define FSS0_MAGIC 0x30535346 +#define FSS0_META_OFFSET 0x4 + +// FSS0 Content Types. +#define CNT_TYPE_FSP 0 +#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor). +#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw). +#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw). +#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader). +#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys). +#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition). +#define CNT_TYPE_BMP 7 +#define CNT_TYPE_EMC 8 +#define CNT_TYPE_KLD 9 // Kernel Loader. +#define CNT_TYPE_KRN 10 // Kernel. + +// FSS0 Content Flags. +#define CNT_FLAG0_EXPERIMENTAL (1 << 0) + +// FSS0 Meta Header. +typedef struct _fss_meta_t +{ + u32 magic; + u32 size; + u32 crt0_off; + u32 cnt_off; + u32 cnt_count; + u32 hos_ver; + u32 version; + u32 git_rev; +} fss_meta_t; + +// FSS0 Content Header. +typedef struct _fss_content_t +{ + u32 offset; + u32 size; + u8 type; + u8 flags0; + u8 flags1; + u8 flags2; + u32 rsvd1; + char name[0x10]; +} fss_content_t; + +static void _update_r2p(const char *path) +{ + char *r2p_path = malloc(256); + u32 path_len = strlen(path); + strcpy(r2p_path, path); + + while(path_len) + { + if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C)) + { + r2p_path[path_len] = 0; + strcat(r2p_path, "reboot_payload.bin"); + u8 *r2p_payload = sd_file_read(r2p_path, NULL); + + is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false); + + free(r2p_payload); + break; + } + path_len--; + } + + free(r2p_path); +} + +int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) +{ + FIL fp; + + bool stock = false; + int sept_used = 0; + + if (!sept_ctxt) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) + { + if (!strcmp("stock", kv->key)) + if (kv->val[0] == '1') + stock = true; + } + + if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable)) + return 1; + } + + if (f_open(&fp, path, FA_READ) != FR_OK) + return 0; + + void *fss = malloc(f_size(&fp)); + + // Read first 1024 bytes of the fss file. + f_read(&fp, fss, 1024, NULL); + + // Get FSS0 Meta header offset. + u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET); + fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr); + + // Check if valid FSS0 and parse it. + if (fss_meta->magic == FSS0_MAGIC) + { + gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" + "Max HOS supported: %d.%d.%d\n" + "Unpacking and loading components.. ", + fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, + fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); + + if (!sept_ctxt) + { + ctxt->atmosphere = true; + ctxt->fss0_hosver = fss_meta->hos_ver; + } + + // Parse FSS0 contents. + fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off); + void *content; + for (u32 i = 0; i < fss_meta->cnt_count; i++) + { + content = (void *)(fss + curr_fss_cnt[i].offset); + + // Check if offset is inside limits. + if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size) + continue; + + // If content is experimental and experimental flag is not enabled, skip it. + if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental) + continue; + + // Parse content. + if (!sept_ctxt) + { + // Prepare content context. + switch (curr_fss_cnt[i].type) + { + case CNT_TYPE_KIP: + if (stock) + continue; + merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); + mkip1->kip1 = content; + list_append(&ctxt->kip1_list, &mkip1->link); + DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); + break; + case CNT_TYPE_EXO: + ctxt->secmon_size = curr_fss_cnt[i].size; + ctxt->secmon = content; + break; + case CNT_TYPE_WBT: + ctxt->warmboot_size = curr_fss_cnt[i].size; + ctxt->warmboot = content; + break; + default: + continue; + } + + // Load content to launch context. + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, content, curr_fss_cnt[i].size, NULL); + } + else + { + // Load sept content directly to launch context. + switch (curr_fss_cnt[i].type) + { + case CNT_TYPE_SP1: + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL); + break; + case CNT_TYPE_SP2: + if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15)) + { + f_lseek(&fp, curr_fss_cnt[i].offset); + f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL); + sept_used = 1; + goto out; + } + break; + default: + break; + } + } + } + +out: + gfx_printf("Done!\n"); + f_close(&fp); + + _update_r2p(path); + + return (!sept_ctxt ? 1 : sept_used); + } + + f_close(&fp); + free(fss); + + return 0; +} + +int load_sept_from_ffs0(fss0_sept_t *sept_ctxt) +{ + LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link) + { + if (!strcmp("fss0", kv->key)) + return parse_fss(NULL, kv->val, sept_ctxt); + } + + return 0; +} diff --git a/ariane/src/libs/hos/fss.h b/ariane/src/libs/hos/fss.h new file mode 100644 index 0000000..3f56d7c --- /dev/null +++ b/ariane/src/libs/hos/fss.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _FSS_H_ +#define _FSS_H_ + +#include "hos.h" + +typedef struct _fss0_sept_t +{ + u32 kb; + ini_sec_t *cfg_sec; + void *sept_primary; + void *sept_secondary; + +} fss0_sept_t; + +int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt); +int load_sept_from_ffs0(fss0_sept_t *sept_ctxt); + +#endif diff --git a/ariane/src/libs/hos/hos.c b/ariane/src/libs/hos/hos.c new file mode 100644 index 0000000..d022f22 --- /dev/null +++ b/ariane/src/libs/hos/hos.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 st4rk + * Copyright (c) 2018 Ced2911 + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "hos.h" +#include "sept.h" +#include "../hekate_config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../storage/nx_emmc.h" +#include +#include +#include + +extern hekate_config h_cfg; + +static u8 *bis_keys = NULL; + +static const u8 keyblob_keyseeds[][0x10] = { + { 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, // 1.0.0. + { 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, // 3.0.0. + { 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, // 3.0.1. + { 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, // 4.0.0. + { 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, // 5.0.0. + { 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } // 6.0.0. +}; + +static const u8 cmac_keyseed[0x10] = + { 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 }; + +static const u8 master_keyseed_retail[0x10] = + { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C }; + +static const u8 master_keyseed_4xx_5xx_610[0x10] = + { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; + +static const u8 master_keyseed_620[0x10] = + { 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A }; + +static const u8 console_keyseed[0x10] = + { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; + +static const u8 console_keyseed_4xx_5xx[0x10] = + { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; + +const u8 package2_keyseed[0x10] = + { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; + +static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] = { + { 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D }, // Zeroes encrypted with mkey 00. + { 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD }, // Mkey 00 encrypted with mkey 01. + { 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 }, // Mkey 01 encrypted with mkey 02. + { 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 }, // Mkey 02 encrypted with mkey 03. + { 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 }, // Mkey 03 encrypted with mkey 04. + { 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE }, // Mkey 04 encrypted with mkey 05. + { 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 }, // Mkey 05 encrypted with mkey 06. + { 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F }, // Mkey 06 encrypted with mkey 07. + { 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, // Mkey 07 encrypted with mkey 08. + { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, // Mkey 08 encrypted with mkey 09. + { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, // Mkey 09 encrypted with mkey 10. +}; + +static const u8 new_console_keyseed[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + { 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D }, // 4.x New Device Key Source. + { 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C }, // 5.x New Device Key Source. + { 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 }, // 6.x New Device Key Source. + { 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 }, // 6.2.0 New Device Key Source. + { 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D }, // 7.0.0 New Device Key Source. + { 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE }, // 8.1.0 New Device Key Source. + { 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 }, // 9.0.0 New Device Key Source. + { 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 }, // 9.1.0 New Device Key Source. +}; + +static const u8 new_console_kekseed[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = { + { 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D }, // 4.x New Device Keygen Source. + { 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E }, // 5.x New Device Keygen Source. + { 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF }, // 6.x New Device Keygen Source. + { 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB }, // 6.2.0 New Device Keygen Source. + { 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E }, // 7.0.0 New Device Keygen Source. + { 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D }, // 8.1.0 New Device Keygen Source. + { 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED }, // 9.0.0 New Device Keygen Source. + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. +}; + +static const u8 gen_keyseed[0x10] = + { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8 }; + +static const u8 gen_kekseed[0x10] = + { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 }; + +static const u8 gen_keyseed_retail[0x10] = + { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95 }; + +static const u8 bis_kekseed[0x10] = + { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F }; + +static const u8 bis_keyseed[][0x10] = { + { 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48 }, // BIS 0 Crypt seed. + { 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06 }, // BIS 0 Tweak seed. + { 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F }, // BIS 1 Crypt seed. + { 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4 }, // BIS 1 Tweak seed. + { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C }, // BIS 2/3 Crypt seed. + { 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4 } // BIS 2/3 Tweak seed. +}; + +bool hos_eks_rw_try(u8 *buf, bool write) +{ + for (u32 i = 0; i < 3; i++) + { + if (!write) + { + if (sdmmc_storage_read(&sd_storage, 0, 1, buf)) + return true; + } + else + { + if (sdmmc_storage_write(&sd_storage, 0, 1, buf)) + return true; + } + } + + return false; +} + +void hos_eks_get() +{ + // Check if EKS already found and parsed. + if (!h_cfg.eks) + { + // Read EKS blob. + u8 *mbr = calloc(512 , 1); + if (!hos_eks_rw_try(mbr, false)) + goto out; + + // Decrypt EKS blob. + hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80); + se_aes_crypt_ecb(14, 0, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Check if valid and for this unit. + if (eks->magic == HOS_EKS_MAGIC && + eks->sbk_low == FUSE(FUSE_PRIVATE_KEY0)) + { + h_cfg.eks = eks; + return; + } + +out: + free(mbr); + } +} + +void hos_eks_save(u32 kb) +{ + if (kb >= KB_FIRMWARE_VERSION_700) + { + u32 key_idx = 0; + if (kb >= KB_FIRMWARE_VERSION_810) + key_idx = 1; + + bool new_eks = false; + if (!h_cfg.eks) + { + h_cfg.eks = calloc(512 , 1); + new_eks = true; + } + + // If matching blob doesn't exist, create it. + bool update_eks = key_idx ? (h_cfg.eks->enabled[key_idx] < kb) : !h_cfg.eks->enabled[0]; + if (update_eks) + { + // Read EKS blob. + u8 *mbr = calloc(512 , 1); + if (!hos_eks_rw_try(mbr, false)) + { + if (new_eks) + { + free(h_cfg.eks); + h_cfg.eks = NULL; + } + + goto out; + } + + // Get keys. + u8 *keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(keys + 0x800, keys, 0x10); + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->enabled[key_idx] = kb; + h_cfg.eks->sbk_low = FUSE(FUSE_PRIVATE_KEY0); + + // Copy new keys. + memcpy(h_cfg.eks->dkg, keys + 10 * 0x10, 0x10); + memcpy(h_cfg.eks->dkk, keys + 15 * 0x10, 0x10); + + if (!h_cfg.aes_slots_new) + { + memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 12 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 13 * 0x10, 0x10); + } + else // New sept slots. + { + memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 13 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 12 * 0x10, 0x10); + } + + // Encrypt EKS blob. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + + free(eks); + free(keys); +out: + free(mbr); + } + } +} + +void hos_eks_clear(u32 kb) +{ + if (h_cfg.eks && kb >= KB_FIRMWARE_VERSION_700) + { + u32 key_idx = 0; + if (kb >= KB_FIRMWARE_VERSION_810) + key_idx = 1; + + // Check if Current Master key is enabled. + if (h_cfg.eks->enabled[key_idx]) + { + // Read EKS blob. + u8 *mbr = calloc(512 , 1); + if (!hos_eks_rw_try(mbr, false)) + goto out; + + // Disable current Master key version. + h_cfg.eks->enabled[key_idx] = 0; + + // Encrypt EKS blob. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + EMC(EMC_SCRATCH0) &= ~EMC_SEPT_RUN; + h_cfg.sept_run = false; + + free(eks); +out: + free(mbr); + } + } +} + +void hos_eks_bis_save() +{ + bool new_eks = false; + if (!h_cfg.eks) + { + h_cfg.eks = calloc(512 , 1); + new_eks = true; + } + + // If matching blob doesn't exist, create it. + if (!h_cfg.eks->enabled_bis) + { + // Read EKS blob. + u8 *mbr = calloc(512 , 1); + if (!hos_eks_rw_try(mbr, false)) + { + if (new_eks) + { + free(h_cfg.eks); + h_cfg.eks = NULL; + } + + goto out; + } + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->enabled_bis = 1; + h_cfg.eks->sbk_low = FUSE(FUSE_PRIVATE_KEY0); + + // Copy new keys. + memcpy(h_cfg.eks->bis_keys[0].crypt, bis_keys + (0 * 0x10), 0x10); + memcpy(h_cfg.eks->bis_keys[0].tweak, bis_keys + (1 * 0x10), 0x10); + + memcpy(h_cfg.eks->bis_keys[1].crypt, bis_keys + (2 * 0x10), 0x10); + memcpy(h_cfg.eks->bis_keys[1].tweak, bis_keys + (3 * 0x10), 0x10); + + memcpy(h_cfg.eks->bis_keys[2].crypt, bis_keys + (4 * 0x10), 0x10); + memcpy(h_cfg.eks->bis_keys[2].tweak, bis_keys + (5 * 0x10), 0x10); + + // Encrypt EKS blob. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + + free(eks); +out: + free(mbr); + } +} + +void hos_eks_bis_clear() +{ + // Check if BIS keys are enabled. + if (h_cfg.eks && h_cfg.eks->enabled_bis) + { + // Read EKS blob. + u8 *mbr = calloc(512 , 1); + if (!hos_eks_rw_try(mbr, false)) + goto out; + + // Disable BIS storage. + h_cfg.eks->enabled_bis = 0; + + // Encrypt EKS blob. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS blob to SD. + memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t)); + hos_eks_rw_try(mbr, true); + + free(eks); +out: + free(mbr); + } +} + +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) +{ + u8 tmp[0x30]; + u32 retries = 0; + + if (kb > KB_FIRMWARE_VERSION_MAX) + return 0; + + if (kb <= KB_FIRMWARE_VERSION_600) + tsec_ctxt->size = 0xF00; + else if (kb == KB_FIRMWARE_VERSION_620) + tsec_ctxt->size = 0x2900; + else if (kb == KB_FIRMWARE_VERSION_700) + tsec_ctxt->size = 0x3000; + else + tsec_ctxt->size = 0x3300; + + // Prepare smmu tsec page for 6.2.0. + if (kb == KB_FIRMWARE_VERSION_620) + { + u8 *tsec_paged = (u8 *)page_alloc(3); + memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size); + tsec_ctxt->fw = tsec_paged; + } + + // Get TSEC key. + if (kb <= KB_FIRMWARE_VERSION_620) + { + while (tsec_query(tmp, kb, tsec_ctxt) < 0) + { + memset(tmp, 0x00, 0x20); + retries++; + + // We rely on racing conditions, make sure we cover even the unluckiest cases. + if (retries > 15) + { + EPRINTF("\nFailed to get TSEC keys. Please try again.\n"); + return 0; + } + } + } + + if (kb >= KB_FIRMWARE_VERSION_700) + { + // Use HOS EKS if it exists. + u32 key_idx = 0; + if (kb >= KB_FIRMWARE_VERSION_810) + key_idx = 1; + + if (h_cfg.eks && h_cfg.eks->enabled[key_idx] >= kb) + { + // Set Device keygen key to slot 10. + se_aes_key_set(10, h_cfg.eks->dkg, 0x10); + // Set Master key to slot 12. + se_aes_key_set(12, h_cfg.eks->keys[key_idx].mkk, 0x10); + // Set FW Device key key to slot 13. + se_aes_key_set(13, h_cfg.eks->keys[key_idx].fdk, 0x10); + // Set Device key to slot 15. + se_aes_key_set(15, h_cfg.eks->dkk, 0x10); + } + else + h_cfg.aes_slots_new = se_key_acc_ctrl_get(12) == 0x6A; + + se_aes_key_clear(8); + se_aes_unwrap_key(8, !h_cfg.aes_slots_new ? 12 : 13, package2_keyseed); + } + else if (kb == KB_FIRMWARE_VERSION_620) + { + // Set TSEC key. + se_aes_key_set(12, tmp, 0x10); + // Set TSEC root key. + se_aes_key_set(13, tmp + 0x10, 0x10); + + // Decrypt keyblob and set keyslots + se_aes_crypt_block_ecb(12, 0, tmp + 0x20, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tmp + 0x20); + se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx); + se_aes_unwrap_key(15, 15, console_keyseed); + + // Package2 key. + se_aes_unwrap_key(8, 13, master_keyseed_620); + se_aes_unwrap_key(9, 8, master_keyseed_retail); + se_aes_unwrap_key(8, 9, package2_keyseed); + } + else + { + // Set TSEC key. + se_aes_key_set(13, tmp, 0x10); + + // Derive keyblob keys from TSEC+SBK. + se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]); + se_aes_unwrap_key(15, 14, tmp); + se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]); + se_aes_unwrap_key(13, 14, tmp); + + // Clear SBK. + se_aes_key_clear(14); + + //TODO: verify keyblob CMAC. + //se_aes_unwrap_key(11, 13, cmac_keyseed); + //se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0); + //if (!memcmp(keyblob, tmp, 0x10)) + // return 0; + + se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed); + se_aes_unwrap_key(11, 13, cmac_keyseed); + + // Decrypt keyblob and set keyslots. + se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); + se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key. + se_aes_key_set(12, keyblob + 0x20, 0x10); + se_aes_key_set(13, keyblob + 0x20, 0x10); + + se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail); + + switch (kb) + { + case KB_FIRMWARE_VERSION_100_200: + case KB_FIRMWARE_VERSION_300: + case KB_FIRMWARE_VERSION_301: + se_aes_unwrap_key(13, 15, console_keyseed); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + break; + case KB_FIRMWARE_VERSION_400: + se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx); + se_aes_unwrap_key(15, 15, console_keyseed); + se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + break; + case KB_FIRMWARE_VERSION_500: + case KB_FIRMWARE_VERSION_600: + se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx); + se_aes_unwrap_key(15, 15, console_keyseed); + se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610); + se_aes_unwrap_key(12, 12, master_keyseed_retail); + break; + } + + // Package2 key. + se_aes_unwrap_key(8, 12, package2_keyseed); + } + + return 1; +} + +static void _hos_validate_sept_mkey(u32 kb) +{ + u8 tmp_mkey[0x10]; + u32 mkey_idx = sizeof(mkey_vectors) / 0x10; + u8 mkey_slot = !h_cfg.aes_slots_new ? 12 : 13; + do + { + mkey_idx--; + se_aes_crypt_ecb(mkey_slot, 0, tmp_mkey, 0x10, mkey_vectors[mkey_idx], 0x10); + for (u32 idx = 0; idx < mkey_idx; idx++) + { + se_aes_key_clear(2); + se_aes_key_set(2, tmp_mkey, 0x10); + se_aes_crypt_ecb(2, 0, tmp_mkey, 0x10, mkey_vectors[mkey_idx - 1 - idx], 0x10); + } + + if (!memcmp(tmp_mkey, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) + { + se_aes_key_clear(2); + hos_eks_save(kb); + return; + } + } while (mkey_idx - 1); + + se_aes_key_clear(2); + hos_eks_clear(kb); +} + +int hos_bis_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) +{ + u32 keygen_rev = 0; + u32 console_key_slot = kb >= KB_FIRMWARE_VERSION_400 ? 15 : 13; + + if (!bis_keys) + bis_keys = malloc(0x10 * 6); + + if (!h_cfg.eks || !h_cfg.eks->enabled_bis) + { + hos_keygen(keyblob, kb, tsec_ctxt); + + // New keygen was introduced in 4.0.0. + // We check unconditionally in order to support downgrades. + keygen_rev = fuse_read_odm_keygen_rev(); + + if (keygen_rev) + { + u8 tmp_mkey[0x10]; + u32 mkey_idx = sizeof(mkey_vectors) / 0x10; + u8 mkey_slot = kb >= KB_FIRMWARE_VERSION_700 ? (!h_cfg.aes_slots_new ? 12 : 13) : (kb == KB_FIRMWARE_VERSION_620 ? 9 : 12); + + // Keygen revision uses bootloader version, which starts from 1. + keygen_rev -= (KB_FIRMWARE_VERSION_400 + 1); + + // Derive mkey 0. + do + { + mkey_idx--; + se_aes_crypt_ecb(mkey_slot, 0, tmp_mkey, 0x10, mkey_vectors[mkey_idx], 0x10); + for (u32 idx = 0; idx < mkey_idx; idx++) + { + se_aes_key_clear(2); + se_aes_key_set(2, tmp_mkey, 0x10); + se_aes_crypt_ecb(2, 0, tmp_mkey, 0x10, mkey_vectors[mkey_idx - 1 - idx], 0x10); + } + } while (memcmp(tmp_mkey, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0 && (mkey_idx - 1)); + + // Derive new device key. + se_aes_key_clear(1); + se_aes_unwrap_key(1, 10, new_console_keyseed[keygen_rev]); // Uses Device key 4x. + se_aes_crypt_ecb(10, 0, tmp_mkey, 0x10, new_console_keyseed[keygen_rev], 0x10); // Uses Device key 4x. + se_aes_unwrap_key(1, 2, new_console_kekseed[keygen_rev]); // Uses Master Key 0. + se_aes_unwrap_key(1, 1, tmp_mkey); + + console_key_slot = 1; + } + + // Generate generic kek. + se_aes_key_clear(2); + se_aes_unwrap_key(2, console_key_slot, gen_keyseed_retail); + + // Clear bis keys storage. + memset(bis_keys, 0, 0x10 * 6); + + // Generate BIS 0 Keys. + se_aes_crypt_block_ecb(2, 0, bis_keys + (0 * 0x10), bis_keyseed[0]); + se_aes_crypt_block_ecb(2, 0, bis_keys + (1 * 0x10), bis_keyseed[1]); + + // Generate generic kek. + se_aes_key_clear(2); + se_aes_unwrap_key(2, console_key_slot, gen_kekseed); + se_aes_unwrap_key(2, 2, bis_kekseed); + se_aes_unwrap_key(2, 2, gen_keyseed); + + // Generate BIS 1 Keys. + se_aes_crypt_block_ecb(2, 0, bis_keys + (2 * 0x10), bis_keyseed[2]); + se_aes_crypt_block_ecb(2, 0, bis_keys + (3 * 0x10), bis_keyseed[3]); + + // Generate BIS 2/3 Keys. + se_aes_crypt_block_ecb(2, 0, bis_keys + (4 * 0x10), bis_keyseed[4]); + se_aes_crypt_block_ecb(2, 0, bis_keys + (5 * 0x10), bis_keyseed[5]); + + if (kb >= KB_FIRMWARE_VERSION_700) + _hos_validate_sept_mkey(kb); + } + else + { + memcpy(bis_keys + (0 * 0x10), h_cfg.eks->bis_keys[0].crypt, 0x10); + memcpy(bis_keys + (1 * 0x10), h_cfg.eks->bis_keys[0].tweak, 0x10); + + memcpy(bis_keys + (2 * 0x10), h_cfg.eks->bis_keys[1].crypt, 0x10); + memcpy(bis_keys + (3 * 0x10), h_cfg.eks->bis_keys[1].tweak, 0x10); + + memcpy(bis_keys + (4 * 0x10), h_cfg.eks->bis_keys[2].crypt, 0x10); + memcpy(bis_keys + (5 * 0x10), h_cfg.eks->bis_keys[2].tweak, 0x10); + } + + // Clear all AES keyslots. + for (u32 i = 0; i < 6; i++) + se_aes_key_clear(i); + + // Set BIS keys. + se_aes_key_set(0, bis_keys + (0 * 0x10), 0x10); + se_aes_key_set(1, bis_keys + (1 * 0x10), 0x10); + + se_aes_key_set(2, bis_keys + (2 * 0x10), 0x10); + se_aes_key_set(3, bis_keys + (3 * 0x10), 0x10); + + se_aes_key_set(4, bis_keys + (4 * 0x10), 0x10); + se_aes_key_set(5, bis_keys + (5 * 0x10), 0x10); + + return 1; +} + +void hos_bis_keys_clear() +{ + // Clear all aes keyslots. + for (u32 i = 0; i < 6; i++) + se_aes_key_clear(i); + + // Set SBK back. + u32 sbk[4] = { + FUSE(FUSE_PRIVATE_KEY0), + FUSE(FUSE_PRIVATE_KEY1), + FUSE(FUSE_PRIVATE_KEY2), + FUSE(FUSE_PRIVATE_KEY3) + }; + // Set SBK to slot 14. + se_aes_key_set(14, sbk, 0x10); + + // Lock SBK from being read. + se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG); +} diff --git a/ariane/src/libs/hos/hos.h b/ariane/src/libs/hos/hos.h new file mode 100644 index 0000000..c8830e8 --- /dev/null +++ b/ariane/src/libs/hos/hos.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _HOS_H_ +#define _HOS_H_ + +#include "pkg1.h" +#include "pkg2.h" +#include +#include +#include + +#include + +#define KB_FIRMWARE_VERSION_100_200 0 +#define KB_FIRMWARE_VERSION_300 1 +#define KB_FIRMWARE_VERSION_301 2 +#define KB_FIRMWARE_VERSION_400 3 +#define KB_FIRMWARE_VERSION_500 4 +#define KB_FIRMWARE_VERSION_600 5 +#define KB_FIRMWARE_VERSION_620 6 +#define KB_FIRMWARE_VERSION_700 7 +#define KB_FIRMWARE_VERSION_810 8 +#define KB_FIRMWARE_VERSION_900 9 +#define KB_FIRMWARE_VERSION_910 10 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 + +#define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x30534B45 + +typedef struct _hos_eks_keys_t +{ + u8 mkk[0x10]; + u8 fdk[0x10]; +} hos_eks_keys_t; + +typedef struct _hos_eks_bis_keys_t +{ + u8 crypt[0x10]; + u8 tweak[0x10]; +} hos_eks_bis_keys_t; + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u8 enabled[5]; + u8 enabled_bis; + u8 rsvd[2]; + u32 sbk_low; + u8 dkg[0x10]; + u8 dkk[0x10]; + hos_eks_keys_t keys[5]; + hos_eks_bis_keys_t bis_keys[3]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) == 304, "HOS EKS size is wrong!"); + +typedef struct _launch_ctxt_t +{ + void *keyblob; + + void *pkg1; + const pkg1_id_t *pkg1_id; + + void *warmboot; + u32 warmboot_size; + void *secmon; + u32 secmon_size; + + void *pkg2; + u32 pkg2_size; + bool new_pkg2; + + void *kernel; + u32 kernel_size; + link_t kip1_list; + char* kip1_patches; + + ini_sec_t *cfg; +} launch_ctxt_t; + +void hos_eks_get(); +void hos_eks_save(u32 kb); +void hos_eks_clear(u32 kb); +void hos_eks_bis_save(); +void hos_eks_bis_clear(); +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); +int hos_bis_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); +void hos_bis_keys_clear(); + +#endif diff --git a/ariane/src/libs/hos/pkg1.c b/ariane/src/libs/hos/pkg1.c new file mode 100644 index 0000000..df6f420 --- /dev/null +++ b/ariane/src/libs/hos/pkg1.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 st4rk + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2018 balika011 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "hos.h" +#include "pkg1.h" +#include +#include +#include +#include + +/* + * package1.1 header: + * package1.1 layout: + * 1.0: {sm, ldr, wb} { 2, 1, 0 } + * 2.0+: {wb, ldr, sm} { 0, 1, 2 } + * 4.0+: {ldr, sm, wb} { 1, 2, 0 } + */ + +static const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTION_WB }; +static const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM }; +static const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB }; + +static const pkg1_id_t _pkg1_ids[] = { + { "20161121183008", 0, 0x1900, 0x3FE0, 0x40014020, 0x8000D000 }, // 1.0.0. + { "20170210155124", 0, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000 }, // 2.0.0 - 2.3.0. + { "20170519101410", 1, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, // 3.0.0. + { "20170710161758", 2, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, // 3.0.1 - 3.0.2. + { "20170921172629", 3, 0x1800, 0x3FE0, 0x4002B000, 0x4003B000 }, // 4.0.0 - 4.1.0. + { "20180220163747", 4, 0x1900, 0x3FE0, 0x4002B000, 0x4003B000 }, // 5.0.0 - 5.1.0. + { "20180802162753", 5, 0x1900, 0x3FE0, 0x4002B000, 0x4003D800 }, // 6.0.0 - 6.1.0. + { "20181107105733", 6, 0x0E00, 0x6FE0, 0x4002B000, 0x4003D800 }, // 6.2.0. + { "20181218175730", 7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, // 7.0.0. + { "20190208150037", 7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, // 7.0.1. + { "20190314172056", 7, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 8.0.0 - 8.0.1. + { "20190531152432", 8, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 8.1.0. + { "20190809135709", 9, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 9.0.0 - 9.0.1. + { "20191021113848", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 9.1.0. + { "20200303104606", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 10.0.0. + { NULL } //End. +}; + +const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date) +{ + if (build_date) + { + memcpy(build_date, (char *)(pkg1 + 0x10), 14); + build_date[14] = 0; + } + + for (u32 i = 0; _pkg1_ids[i].id; i++) + if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12)) + return &_pkg1_ids[i]; + return NULL; +} + +void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1) +{ + // Decrypt package1. + u8 *pkg11 = pkg1 + id->pkg11_off; + u32 pkg11_size = *(u32 *)pkg11; + se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10); +} + +const u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1) +{ + const u8 *sec_map; + const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20); + + u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size }; + //u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off }; + + // Get correct header mapping. + if (id->kb == KB_FIRMWARE_VERSION_100_200 && !strcmp(id->id, "20161121183008")) + sec_map = sec_map_100; + else if (id->kb >= KB_FIRMWARE_VERSION_100_200 && id->kb <= KB_FIRMWARE_VERSION_301) + sec_map = sec_map_2xx; + else + sec_map = sec_map_4xx; + + // Copy secmon, warmboot and nx bootloader payloads. + u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t); + for (u32 i = 0; i < 3; i++) + { + if (sec_map[i] == PK11_SECTION_WB && wm_dst) + memcpy(wm_dst, pdata, sec_size[sec_map[i]]); + else if (sec_map[i] == PK11_SECTION_LD && ldr_dst) + memcpy(ldr_dst, pdata, sec_size[sec_map[i]]); + else if (sec_map[i] == PK11_SECTION_SM && sm_dst) + memcpy(sm_dst, pdata, sec_size[sec_map[i]]); + pdata += sec_size[sec_map[i]]; + } + + return sec_map; +} diff --git a/ariane/src/libs/hos/pkg1.h b/ariane/src/libs/hos/pkg1.h new file mode 100644 index 0000000..74f101b --- /dev/null +++ b/ariane/src/libs/hos/pkg1.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PKG1_H_ +#define _PKG1_H_ + +#include + +#define PK11_SECTION_WB 0 +#define PK11_SECTION_LD 1 +#define PK11_SECTION_SM 2 + +typedef struct _pkg1_id_t +{ + const char *id; + u32 kb; + u32 tsec_off; + u32 pkg11_off; + u32 secmon_base; + u32 warmboot_base; +} pkg1_id_t; + +typedef struct _pk11_hdr_t +{ + u32 magic; + u32 wb_size; + u32 wb_off; + u32 pad; + u32 ldr_size; + u32 ldr_off; + u32 sm_size; + u32 sm_off; +} pk11_hdr_t; + +const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date); +void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); +const u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); + +#endif diff --git a/ariane/src/libs/hos/pkg2.c b/ariane/src/libs/hos/pkg2.c new file mode 100644 index 0000000..a7f6aab --- /dev/null +++ b/ariane/src/libs/hos/pkg2.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "pkg2.h" +#include "hos.h" + +#include "../hekate_config.h" +#include +#include +#include +#include + +#include + +extern hekate_config h_cfg; +extern const u8 package2_keyseed[]; + +u32 pkg2_newkern_ini1_val; +u32 pkg2_newkern_ini1_start; +u32 pkg2_newkern_ini1_end; + +/*#include +#define DPRINTF(...) gfx_printf(__VA_ARGS__) +#define DEBUG_PRINTING*/ +#define DPRINTF(...) + +u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1) +{ + u32 size = sizeof(pkg2_kip1_t); + for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++) + size += kip1->sections[j].size_comp; + return size; +} + +void pkg2_get_newkern_info(u8 *kern_data) +{ + u32 pkg2_newkern_ini1_off = 0; + pkg2_newkern_ini1_start = 0; + + // Find static OP offset that is close to INI1 offset. + u32 counter_ops = 0x100; + while (counter_ops) + { + if (*(u32 *)(kern_data + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC) + { + pkg2_newkern_ini1_off = 0x100 - counter_ops + 12; // OP found. Add 12 for the INI1 offset. + break; + } + + counter_ops -= 4; + } + + // Offset not found? + if (!counter_ops) + return; + + u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_off); + pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + pkg2_newkern_ini1_off; // Parse ADR and PC. + + pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); + pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); +} + +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) +{ + u8 *ptr; + // Check for new pkg2 type. + if (!pkg2->sec_size[PKG2_SEC_INI1]) + { + pkg2_get_newkern_info(pkg2->data); + + if (!pkg2_newkern_ini1_start) + return false; + + ptr = pkg2->data + pkg2_newkern_ini1_start; + *new_pkg2 = true; + } + else + ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL]; + + pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr; + ptr += sizeof(pkg2_ini1_t); + + for (u32 i = 0; i < ini1->num_procs; i++) + { + pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr; + pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t)); + ki->kip1 = kip1; + ki->size = pkg2_calc_kip1_size(kip1); + list_append(info, &ki->link); + ptr += ki->size; +DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size); + } + + return true; +} + +static const u8 mkey_vector_8xx[][0x10] = +{ + // Master key 8 encrypted with 9. (8.1.0 with 9.0.0) + { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, + // Master key 9 encrypted with 10. (9.0.0 with 9.1.0) + { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A } +}; + +static bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed) +{ + // Decrypt older encrypted mkey. + se_aes_crypt_ecb(src_slot, 0, mkey, 0x10, key_seed, 0x10); + // Set and unwrap pkg2 key. + se_aes_key_clear(9); + se_aes_key_set(9, mkey, 0x10); + se_aes_unwrap_key(9, 9, package2_keyseed); + + // Decrypt header. + se_aes_crypt_ctr(9, tmp_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + + // Return if header is valid. + return (tmp_test->magic == PKG2_MAGIC); +} + +pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb) +{ + pkg2_hdr_t mkey_test; + u8 *pdata = (u8 *)data; + u8 keyslot = 8; + + // Skip signature. + pdata += 0x100; + + pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata; + + // Skip header. + pdata += sizeof(pkg2_hdr_t); + + // Check if we need to decrypt with newer mkeys. Valid for sept for 8.1.0 and up. + se_aes_crypt_ctr(8, &mkey_test, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + + if (mkey_test.magic == PKG2_MAGIC) + goto key_found; + + // Decrypt older pkg2 via new mkeys. + if ((kb >= KB_FIRMWARE_VERSION_810) && (kb < KB_FIRMWARE_VERSION_MAX)) + { + u8 tmp_mkey[0x10]; + u8 decr_slot = !h_cfg.aes_slots_new ? 12 : 13; // Sept mkey. + u8 mkey_seeds_cnt = sizeof(mkey_vector_8xx) / 0x10; + u8 mkey_seeds_idx = mkey_seeds_cnt; // Real index + 1. + u8 mkey_seeds_min_idx = mkey_seeds_cnt - (KB_FIRMWARE_VERSION_MAX - kb); + + while (mkey_seeds_cnt) + { + // Decrypt and validate mkey. + int res = _pkg2_key_unwrap_validate(&mkey_test, hdr, decr_slot, + tmp_mkey, mkey_vector_8xx[mkey_seeds_idx - 1]); + + if (res) + { + keyslot = 9; + goto key_found; + } + else + { + // Set current mkey in order to decrypt a lower mkey. + mkey_seeds_idx--; + se_aes_key_clear(9); + se_aes_key_set(9, tmp_mkey, 0x10); + + decr_slot = 9; // Temp key. + + // Check if we tried last key for that pkg2 version. + // And start with a lower mkey in case sept is older. + if (mkey_seeds_idx == mkey_seeds_min_idx) + { + mkey_seeds_cnt--; + mkey_seeds_idx = mkey_seeds_cnt; + decr_slot = !h_cfg.aes_slots_new ? 12 : 13; // Sept mkey. + } + + // Out of keys. pkg2 is latest or process failed. + if (!mkey_seeds_cnt) + se_aes_key_clear(9); + } + } + } + +key_found: + // Decrypt header. + se_aes_crypt_ctr(keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); + //gfx_hexdump((u32)hdr, hdr, 0x100); + + if (hdr->magic != PKG2_MAGIC) + return NULL; + + for (u32 i = 0; i < 4; i++) + { +DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]); + if (!hdr->sec_size[i]) + continue; + + se_aes_crypt_ctr(keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); + //gfx_hexdump((u32)pdata, pdata, 0x100); + + pdata += hdr->sec_size[i]; + } + + if (keyslot != 8) + se_aes_key_clear(9); + + return hdr; +} diff --git a/ariane/src/libs/hos/pkg2.h b/ariane/src/libs/hos/pkg2.h new file mode 100644 index 0000000..fddfce7 --- /dev/null +++ b/ariane/src/libs/hos/pkg2.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PKG2_H_ +#define _PKG2_H_ + +#include +#include + +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 +#define PKG2_SEC_KERNEL 0 +#define PKG2_SEC_INI1 1 + +#define INI1_MAGIC 0x31494E49 +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset. +#define PKG2_NEWKERN_START 0x800 + +extern u32 pkg2_newkern_ini1_val; +extern u32 pkg2_newkern_ini1_start; +extern u32 pkg2_newkern_ini1_end; + +typedef struct _pkg2_hdr_t +{ + u8 ctr[0x10]; + u8 sec_ctr[0x40]; + u32 magic; + u32 base; + u32 pad0; + u8 pkg2_ver; + u8 bl_ver; + u16 pad1; + u32 sec_size[4]; + u32 sec_off[4]; + u8 sec_sha256[0x80]; + u8 data[]; +} pkg2_hdr_t; + +typedef struct _pkg2_ini1_t +{ + u32 magic; + u32 size; + u32 num_procs; + u32 pad; +} pkg2_ini1_t; + +typedef struct _pkg2_kip1_sec_t +{ + u32 offset; + u32 size_decomp; + u32 size_comp; + u32 attrib; +} pkg2_kip1_sec_t; + +#define KIP1_NUM_SECTIONS 6 + +typedef struct _pkg2_kip1_t +{ + u32 magic; + u8 name[12]; + u64 tid; + u32 proc_cat; + u8 main_thrd_prio; + u8 def_cpu_core; + u8 res; + u8 flags; + pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS]; + u32 caps[0x20]; + u8 data[]; +} pkg2_kip1_t; + +typedef struct _pkg2_kip1_info_t +{ + pkg2_kip1_t *kip1; + u32 size; + link_t link; +} pkg2_kip1_info_t; + +void pkg2_get_newkern_info(u8 *kern_data); +u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1); +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); + +pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb); + +#endif diff --git a/ariane/src/libs/hos/sept.c b/ariane/src/libs/hos/sept.c new file mode 100644 index 0000000..6f29729 --- /dev/null +++ b/ariane/src/libs/hos/sept.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "hos.h" +#include "sept.h" +#include "../hekate_config.h" +#include +#include +#include +#include +#include +#include +#include +#include "../storage/nx_emmc.h" +#include +#include +#include +#include +#include + +#include + +#define RELOC_META_OFF 0x7C +#define PATCHED_RELOC_SZ 0x94 + +#define WB_RST_ADDR 0x40010ED0 +#define WB_RST_SIZE 0x30 + +u8 warmboot_reboot[] = { + 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 + 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 + 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0xFE, 0xFF, 0xFF, 0xEA, // LOOP + 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 + 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 +}; + +#define SEPT_PRI_ADDR 0x4003F000 + +#define SEPT_PK1T_ADDR 0xC0400000 +#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) +#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) +#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) +#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) + +extern volatile boot_cfg_t *b_cfg; +extern hekate_config h_cfg; +extern volatile nyx_storage_t *nyx_str; + +extern bool is_ipl_updated(void *buf); +extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); + +void check_sept() +{ + hos_eks_get(); + + // Check if non-hekate payload is used for sept and restore it. + if (h_cfg.sept_run) + { + if (!f_stat("sept/payload.bak", NULL)) + { + f_unlink("sept/payload.bin"); + f_rename("sept/payload.bak", "sept/payload.bin"); + } + + return; + } + + u8 *pkg1 = (u8 *)calloc(1, 0x40000); + + sdmmc_storage_t storage; + sdmmc_t sdmmc; + if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + { + EPRINTF("Failed to init eMMC."); + goto out_free; + } + + sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0); + + // Read package1. + char *build_date = malloc(32); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date); + free(build_date); + if (!pkg1_id) + { + EPRINTF("Unknown pkg1 version."); + goto out_free; + } + + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + { + u32 key_idx = 0; + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_810) + key_idx = 1; + + if (h_cfg.eks && h_cfg.eks->enabled[key_idx] >= pkg1_id->kb) + { + h_cfg.sept_run = true; + goto out_free; + } + + sdmmc_storage_end(&storage); + reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb); + } + +out_free: + free(pkg1); + sdmmc_storage_end(&storage); +} + +int reboot_to_sept(const u8 *tsec_fw, u32 kb) +{ + FIL fp; + + // Copy warmboot reboot code and TSEC fw. + u32 tsec_fw_size = 0x3000; + if (kb > KB_FIRMWARE_VERSION_700) + tsec_fw_size = 0x3300; + memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); + memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size); + *(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size; + + // Copy sept-primary. + if (f_open(&fp, "sept/sept-primary.bin", FA_READ)) + goto error; + + if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Copy sept-secondary. + if (kb < KB_FIRMWARE_VERSION_810) + { + if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ)) + goto error; + } + else + { + if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ)) + goto error; + } + + if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + b_cfg->boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN); + + bool update_sept_payload = true; + if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE)) + { + ipl_ver_meta_t tmp_ver; + ipl_ver_meta_t heka_ver; + f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t)); + f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL); + memcpy(&heka_ver, (u8 *)nyx_str->hekate + 0x118, sizeof(ipl_ver_meta_t)); + + if (tmp_ver.magic == heka_ver.magic) + { + if (tmp_ver.version == heka_ver.version) + { + // Save auto boot config to sept payload, if any. + boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); + memcpy(tmp_cfg, (boot_cfg_t *)b_cfg, sizeof(boot_cfg_t)); + f_lseek(&fp, PATCHED_RELOC_SZ); + f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); + update_sept_payload = false; + } + + f_close(&fp); + } + else + { + f_close(&fp); + f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload. + } + } + + if (update_sept_payload) + { + volatile reloc_meta_t *reloc = (reloc_meta_t *)(nyx_str->hekate + RELOC_META_OFF); + f_mkdir("sept"); + f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, (u8 *)nyx_str->hekate, reloc->end - reloc->start, NULL); + f_close(&fp); + } + + sd_end(); + + u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); + + void (*sept)() = (void *)pk1t_sept; + + reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); + + // Patch SDRAM init to perform an SVC immediately after second write. + PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; + PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; + // Set SVC handler to jump to sept-primary in IRAM. + PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; + PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; + + //hw_reinit_workaround(false, 0); + reconfig_hw_workaround(false, 0); + + (*sept)(); + +error: + return 0; +} diff --git a/ariane/src/libs/hos/sept.h b/ariane/src/libs/hos/sept.h new file mode 100644 index 0000000..d431840 --- /dev/null +++ b/ariane/src/libs/hos/sept.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SEPT_H_ +#define _SEPT_H_ + +#include + +void check_sept(); +int reboot_to_sept(const u8 *tsec_fw, u32 kb); + +#endif diff --git a/ariane/src/link.ld b/ariane/src/link.ld new file mode 100644 index 0000000..cd8b8a1 --- /dev/null +++ b/ariane/src/link.ld @@ -0,0 +1,25 @@ +ENTRY(_start) + +SECTIONS { + PROVIDE(__ipl_start = IPL_LOAD_ADDR); + . = __ipl_start; + .text : { + *(.text._start); + *(._boot_cfg); + *(._ipl_version); + *(.text._irq_setup); + *(.text*); + } + .data : { + *(.data*); + *(.rodata*); + } + . = ALIGN(0x10); + __ipl_end = .; + .bss : { + __bss_start = .; + *(COMMON) + *(.bss*) + __bss_end = .; + } +} diff --git a/ariane/src/logo.h b/ariane/src/logo.h new file mode 100644 index 0000000..bdb9a85 --- /dev/null +++ b/ariane/src/logo.h @@ -0,0 +1,824 @@ +#ifndef LOGO_H + +#define LOGO_H +#define X_BOOTLOGO 57 +#define Y_BOOTLOGO 400 +#define SZ_BOOTLOGO 68400 +#define SZ_BOOTLOGO_BLZ 9732 +// @8bpp RGB. +static unsigned char BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = { + 0x0C, 0xA0, 0x0F, 0xF0, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0xFF, 0x21, 0x39, + 0x0F, 0x00, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0xE3, 0x11, 0x94, 0x7C, + 0xCE, 0x3C, 0x03, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFE, 0x4B, 0xF0, 0x15, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x03, 0x30, 0x00, 0x00, 0xB7, 0x00, 0x55, 0x12, 0xFF, 0x29, 0x42, 0x1E, + 0x40, 0x5A, 0x7B, 0xEE, 0x22, 0xFF, 0x03, 0x30, 0xA4, 0x00, 0x00, 0xAB, + 0x00, 0xDC, 0x02, 0x2E, 0x08, 0x03, 0x10, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0x7B, 0xB5, 0x0F, 0x00, + 0x64, 0xF2, 0xF7, 0x02, 0xE7, 0xA8, 0x50, 0x6B, 0x87, 0x00, 0x87, 0xF0, + 0x88, 0x32, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFD, 0x0F, 0xF0, 0x0F, + 0xF0, 0x4B, 0xF0, 0x37, 0x02, 0x1E, 0x10, 0x1E, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x4E, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xFF, 0x4A, 0x63, 0x00, 0xBD, 0x87, + 0x10, 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xF0, 0x11, 0x67, 0x0F, 0x00, + 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0xE2, 0x1E, 0x66, 0xF0, 0x57, 0xF0, + 0xFF, 0xA8, 0xF0, 0x1E, 0xF0, 0x7B, 0xAD, 0x1E, 0x10, 0xA8, 0xF0, 0x53, + 0xF1, 0x0F, 0xF0, 0xF3, 0x2A, 0xF0, 0x9C, 0xDE, 0x00, 0xC6, 0xFF, 0x00, + 0x00, 0x03, 0x30, 0xC1, 0x00, 0x00, 0x45, 0x10, 0xBD, 0xFF, 0x00, 0x21, + 0x31, 0x03, 0x30, 0x83, 0x0F, 0xF0, 0x4B, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, + 0x42, 0xF0, 0x53, 0xF1, 0x36, 0xF0, 0xA8, 0xF0, 0xFF, 0x63, 0xF0, 0xA8, + 0x60, 0x0F, 0xF0, 0x4B, 0xF0, 0xE3, 0x14, 0x1E, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0xFF, 0x73, 0xA8, 0xA0, 0x36, 0xF0, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, + 0xF0, 0x54, 0xF0, 0xA8, 0xF0, 0xFE, 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, + 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0xFF, 0x4B, + 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0xF0, 0x36, 0xF0, 0xA8, + 0xF0, 0x42, 0xF0, 0xFF, 0xA8, 0xF0, 0x54, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xFF, 0xA8, 0xF0, 0xA8, + 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0xE4, 0x16, 0x1E, 0xF0, 0xB5, 0x53, 0xF1, + 0xBF, 0xA8, 0xF0, 0xA8, 0xF0, 0x33, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, + 0xF0, 0x51, 0xF0, 0xA8, 0xF0, 0xFF, 0x53, 0xF1, 0xA8, 0xF0, 0xA8, 0xF0, + 0x3C, 0xF0, 0xA8, 0xF0, 0xC6, 0x42, 0xF0, 0x00, 0x5F, 0xB5, 0xA8, 0xF0, + 0x57, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xA5, 0xA8, 0x60, 0x42, 0xF0, 0xDE, + 0x30, 0x00, 0xDD, 0x71, 0x0F, 0xF0, 0x2A, 0xF0, 0x8C, 0xA8, 0xD0, 0xA8, + 0xF0, 0x5A, 0xF0, 0xEF, 0xA8, 0xF0, 0x1E, 0xB0, 0xA8, 0xF0, 0x63, 0x42, + 0xF0, 0xA8, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xF7, 0x42, 0xF0, 0xA8, 0xF0, + 0x54, 0xF0, 0xA8, 0xF0, 0x53, 0xF1, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, + 0xFF, 0x2D, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0xA8, + 0xF0, 0x53, 0xF1, 0x42, 0xF0, 0xFF, 0xA8, 0xC0, 0x39, 0xF0, 0xA8, 0xF0, + 0x63, 0x00, 0x42, 0xC0, 0xA8, 0xF0, 0x57, 0xF0, 0xA8, 0xF0, 0xFF, 0x03, + 0x30, 0xB9, 0xA1, 0x73, 0xA8, 0xA0, 0x9E, 0x31, 0x84, 0x50, 0xA8, 0x40, + 0x0F, 0xF0, 0xFB, 0x30, 0xF0, 0xA8, 0xF0, 0x3C, 0x60, 0xA8, 0xF0, 0x57, + 0xF0, 0xA8, 0xF0, 0x06, 0x20, 0x0E, 0x31, 0xFF, 0x63, 0x40, 0xA8, 0xF0, + 0x42, 0x60, 0xA8, 0xF0, 0x39, 0xF0, 0xA8, 0xF0, 0xB9, 0xC1, 0xA8, 0xF0, + 0xFF, 0x5A, 0xF0, 0xA8, 0xF0, 0x53, 0xF1, 0xA8, 0xF0, 0x03, 0x00, 0x42, + 0x40, 0xA8, 0xF0, 0x10, 0x7F, 0x3C, 0xF0, 0xA8, 0xF0, 0xBD, 0x0E, 0x21, + 0x45, 0x40, 0x42, 0x30, 0xA8, 0xF0, 0x57, 0xF0, 0xFB, 0xA8, 0xF0, 0x67, + 0xB2, 0xEF, 0xA8, 0x80, 0x53, 0xF1, 0x53, 0xF1, 0x3C, 0xF0, 0xA8, 0xF0, + 0xFB, 0xA8, 0xF0, 0xA8, 0xF0, 0x5A, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xA9, + 0xE2, 0xAD, 0x42, 0x60, 0xBF, 0x53, 0xF1, 0x3C, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0xA8, 0xF0, 0x5A, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xFF, 0xFE, 0xB1, + 0x6A, 0x0B, 0x87, 0xF0, 0x6B, 0xA8, 0x80, 0x39, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0xF7, 0xB5, 0xA8, 0xC0, 0x5A, 0xF0, 0xA8, 0xF0, 0x1E, 0xF0, 0x53, + 0x61, 0xFE, 0xF1, 0xA8, 0xF0, 0xFE, 0x3C, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, + 0xA8, 0xF0, 0x5A, 0xF0, 0xA8, 0xF0, 0x1E, 0xF0, 0xFE, 0x11, 0xFF, 0xA8, + 0xD0, 0xA8, 0xF0, 0x0F, 0xF0, 0x30, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, + 0xF0, 0x4E, 0xF0, 0xFF, 0xA8, 0xF0, 0xA8, 0xF0, 0x42, 0xA8, 0xF0, 0xE7, + 0xA8, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xEB, 0x04, 0xC8, 0xA8, 0xA0, 0x0F, + 0xF0, 0x4B, 0xF0, 0x63, 0xFE, 0x21, 0x63, 0xF0, 0xBA, 0x29, 0xEF, 0xA8, + 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x5A, + 0xF0, 0xA8, 0xF0, 0xFF, 0x1E, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x35, 0x67, + 0x0F, 0xF0, 0x2A, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xFF, 0x5A, 0xF0, 0x53, + 0xF1, 0x1E, 0xD0, 0xA8, 0xF0, 0x42, 0xF0, 0xB5, 0xA8, 0x80, 0x0F, 0xF0, + 0xDF, 0x2A, 0xF0, 0x84, 0xA8, 0xA0, 0xA8, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, + 0x8E, 0x05, 0x1E, 0xC0, 0xFD, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0xF0, 0x36, + 0xF0, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0xF0, 0x54, 0xF0, 0xFF, 0xA8, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, + 0xA8, 0xF0, 0xFF, 0x0F, 0xF0, 0x4B, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x42, + 0xD0, 0xA8, 0xF0, 0x39, 0xF0, 0xA8, 0xF0, 0xFF, 0xB5, 0x42, 0xF0, 0xF7, + 0x00, 0xA8, 0xF0, 0x54, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xF2, 0xA8, 0xF0, + 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, + 0x4B, 0xF0, 0xFF, 0xA8, 0xF0, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0xF0, 0x36, + 0xF0, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0xF0, 0xFF, 0x54, 0xF0, 0xA8, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, + 0xFF, 0xA8, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x42, + 0xF0, 0xA8, 0xE0, 0x36, 0xF0, 0xFF, 0xA8, 0xF0, 0x42, 0xF0, 0xA8, 0x90, + 0x5A, 0xF0, 0xA8, 0xF0, 0xC9, 0xA0, 0xA8, 0x80, 0xEE, 0x62, 0xFF, 0x87, + 0x60, 0x08, 0x81, 0x60, 0x75, 0x00, 0x63, 0xA8, 0x80, 0x39, 0xF0, 0xA8, + 0xF0, 0xED, 0xBC, 0x01, 0x45, 0x50, 0x08, 0xA8, 0xE0, 0x0F, 0xF0, 0x4B, + 0xF0, 0x25, 0x02, 0x1E, 0x90, 0xFB, 0x08, 0x1E, 0x60, 0x6B, 0xA8, 0x70, + 0x42, 0xF0, 0xA8, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xFA, 0x42, 0xF0, 0xA8, + 0xF0, 0x54, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x98, 0x51, 0x52, 0x42, 0xF0, + 0xBF, 0x30, 0x10, 0x5A, 0x8C, 0x03, 0x30, 0x0F, 0xF0, 0x2A, 0xF0, 0x05, + 0x01, 0x42, 0x00, 0xF9, 0x42, 0xF0, 0xF6, 0x00, 0x06, 0x40, 0x0F, 0xF0, + 0x4B, 0xF0, 0xD8, 0x00, 0xAD, 0xF7, 0x3F, 0x03, 0x10, 0x03, 0x30, 0x00, + 0x00, 0xA5, 0xE7, 0x00, 0xAD, 0xEF, 0x07, 0x00, 0x63, 0x94, 0x42, 0x40, + 0x4A, 0x6B, 0x08, 0xBD, 0x08, 0x42, 0xF0, 0xFF, 0x00, 0x73, 0xAD, 0x06, + 0x40, 0x3C, 0xF0, 0x42, 0xF0, 0xE1, 0x94, 0xCE, 0x42, 0x10, 0x42, 0xF0, + 0x18, 0x31, 0x03, 0x30, 0x0F, 0xF0, 0xCC, 0x4B, 0xF0, 0x66, 0x00, 0x0F, + 0x00, 0x03, 0x10, 0x03, 0x30, 0x00, 0x00, 0xAD, 0xF7, 0x3F, 0x08, 0xB5, + 0xFF, 0x00, 0x7B, 0xB5, 0x1E, 0x40, 0x18, 0x40, 0x29, 0x08, 0x73, 0xA5, + 0x09, 0x10, 0x84, 0x50, 0x00, 0x5A, 0x30, 0x84, 0x00, 0x73, 0x9C, 0x6F, + 0x00, 0x06, 0x40, 0x0F, 0xF0, 0x27, 0xF0, 0xF0, 0x39, 0x5A, 0x42, 0x50, + 0x84, 0x3C, 0x50, 0x84, 0x42, 0x00, 0x09, 0x70, 0xD4, 0x0F, 0xF0, 0x2A, + 0xF0, 0x29, 0x42, 0x08, 0x73, 0x9C, 0x03, 0x10, 0x83, 0x03, 0x30, 0x00, + 0x00, 0x5A, 0x7B, 0x08, 0x6B, 0x9C, 0x00, 0x03, 0x31, 0x4A, 0x06, 0x50, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x1B, 0xF6, 0xBF, 0xF7, 0x31, 0x08, 0x63, + 0x8C, 0x00, 0x00, 0x0F, 0xF0, 0xC3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0xFF, 0x00, + 0x00, 0xD3, 0x05, 0x01, 0x02, 0x89, 0x0A, 0x4B, 0x6C, 0x99, 0x00, 0x00, + 0x00, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x56, + 0x01, 0x0E, 0x14, 0x6B, 0x36, 0x19, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xF7, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x21, + 0xF0, 0xFC, 0x23, 0x84, 0x7F, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x24, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0x53, 0xE1, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xD2, 0xF0, 0x53, 0x31, 0x3D, 0x15, 0xA8, 0x90, 0x03, 0x30, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x93, 0xF0, 0xFF, 0xEA, 0x23, 0x21, 0x19, 0xCD, 0x6E, + 0x99, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x06, 0x60, 0x93, 0x36, 0xAB, 0x90, 0xA2, 0xF0, 0xF2, + 0xF1, 0xE7, 0x03, 0xFF, 0xE0, 0x7A, 0xAD, 0xF7, 0x09, 0x90, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF9, 0x06, 0x60, 0x28, 0x32, 0xA9, + 0x32, 0xF2, 0x67, 0xA8, 0xF0, 0xA5, 0xF0, 0x4A, 0x01, 0xCE, 0xF7, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4E, 0xF0, 0x37, 0xF5, + 0x66, 0x03, 0x4D, 0xC1, 0xFF, 0x96, 0xF0, 0xCE, 0x37, 0x00, 0x21, 0x31, + 0x0C, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0xE3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x39, 0xF0, 0xF5, 0x07, 0x0C, 0xB0, 0xA5, 0xF0, 0x4A, 0x21, 0xFF, + 0x6B, 0x9C, 0x0F, 0xD0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFC, 0x3C, 0xF0, 0x05, 0x2D, 0xA5, 0xF0, 0x4A, 0xF1, 0xC8, + 0x01, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x48, 0xF0, 0x81, 0xF6, 0xA5, 0x60, 0xA2, 0xF0, 0x3F, 0x43, 0xA5, 0x7F, + 0xEF, 0xCE, 0x37, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x48, 0xF0, 0xFE, 0x81, 0xF6, 0x1B, 0x00, 0xEF, 0x61, 0x9C, 0xF0, + 0x3F, 0x43, 0x9F, 0xFF, 0x10, 0x0F, 0xF0, 0xBF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x4E, 0xF0, 0xC3, 0xF9, 0x81, 0x16, 0xA2, 0xC0, 0x4A, 0xF1, + 0xFF, 0x68, 0x04, 0x3F, 0x33, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x45, 0xF0, 0xFF, 0x3F, 0xF3, 0x06, 0x60, 0x9C, 0xF0, + 0x3F, 0x33, 0x18, 0x03, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0x3F, 0xF3, 0x68, 0x21, 0x09, 0x70, 0x4B, + 0xFF, 0xD4, 0x31, 0xFF, 0x31, 0x0E, 0x0C, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xFF, 0xAB, 0x0F, 0x00, + 0x00, 0xA2, 0x60, 0x9F, 0xF0, 0xD9, 0x3E, 0x9F, 0x2F, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0x3F, 0xF3, + 0xBD, 0x08, 0x9C, 0x1F, 0xF2, 0xA1, 0xF2, 0xF1, 0x84, 0x00, 0x35, 0x0D, + 0x0C, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x3C, 0xF0, 0xC1, 0x02, 0x06, 0x00, 0xA2, 0xB0, 0x3F, 0xF3, 0xCE, + 0x07, 0xFF, 0xBD, 0x62, 0x04, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x48, 0xF0, 0xFE, 0x3F, 0xF3, 0x1E, 0x00, 0xA5, 0x80, + 0xA5, 0xF0, 0xE4, 0x2C, 0x5A, 0x8C, 0x0C, 0xC0, 0x9F, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x3C, 0xF0, 0x3A, 0x0B, 0x3F, + 0x03, 0xFF, 0x4A, 0xA1, 0x9C, 0xF0, 0x4D, 0x2A, 0x3F, 0xF3, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x39, 0xF0, 0xBF, + 0x1A, 0x9C, 0x4A, 0xB1, 0x4A, 0xF1, 0xCE, 0x27, 0x0F, 0xF0, 0xF7, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xC9, + 0x00, 0x4A, 0xB1, 0xFF, 0x3F, 0xF3, 0x84, 0x20, 0x8C, 0xF4, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, 0xFF, 0xA5, 0xF0, 0x39, + 0x52, 0x1B, 0x00, 0x8C, 0x64, 0x9F, 0xF0, 0x4A, 0x2A, 0x3F, 0x43, 0xF9, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x48, 0xF0, + 0x3F, 0xF3, 0x4A, 0xF1, 0xFF, 0x4A, 0xF1, 0xA4, 0xFD, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x3C, 0xF0, 0xFF, 0xAB, 0x06, + 0xB0, 0x04, 0xA5, 0x80, 0x9F, 0xF0, 0xD9, 0x45, 0x8C, 0x34, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x45, 0xF0, 0x3F, + 0xF3, 0xA5, 0xF0, 0x3F, 0xF3, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0x9A, 0x08, 0xA2, 0xB0, + 0xFF, 0x3F, 0xF3, 0x71, 0x14, 0xBD, 0x03, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x48, 0xF0, 0x37, 0xF5, 0xA5, 0x80, + 0xA2, 0xF0, 0x8C, 0x74, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x48, 0xF0, 0x3F, 0xF3, 0x4A, 0xE1, 0x4A, + 0xF1, 0x3F, 0x13, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x4B, 0xF0, 0x7A, 0xF7, 0x21, 0x10, 0xFF, 0x9C, 0xA5, 0x80, + 0x9C, 0xF0, 0x8C, 0x24, 0x50, 0x07, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0x48, 0xF0, 0x2D, 0xF6, 0x1B, 0x10, 0x4A, + 0x51, 0x99, 0xF0, 0xD4, 0x41, 0xFF, 0x5A, 0x84, 0x0F, 0xF0, 0x00, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF4, 0x4B, 0xF0, 0xA2, 0xF0, + 0x73, 0xB5, 0x0C, 0xA0, 0x9C, 0xF0, 0x9C, 0x8C, 0x24, 0xB3, 0x21, 0x39, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x48, 0xF0, + 0xFC, 0x7A, 0xF7, 0xB5, 0x32, 0x06, 0x50, 0x06, 0x60, 0x50, 0x31, 0x3F, + 0x53, 0x6B, 0xA5, 0x3F, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xBE, 0x02, 0xFF, 0x1B, 0x10, 0xF6, + 0x63, 0x9F, 0xF0, 0xDB, 0x33, 0x39, 0x5A, 0x0F, 0xF0, 0x0F, 0xF0, 0xCF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0x6E, 0x01, + 0x03, 0x00, 0xA5, 0x40, 0xFF, 0xA2, 0xF0, 0x28, 0x22, 0x14, 0x04, 0x00, + 0x8C, 0xF4, 0x10, 0x21, 0x0F, 0xF0, 0x97, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0x16, 0x02, 0xA8, 0x00, 0xE8, 0x42, 0xFF, + 0xA2, 0xF0, 0x3F, 0x23, 0xD1, 0x01, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x39, 0xF0, 0x53, 0x81, 0xA8, + 0x50, 0x82, 0xF2, 0x84, 0xC6, 0x08, 0x1F, 0x21, 0x31, 0x03, 0x30, 0x9C, + 0xF0, 0x4A, 0xF1, 0xFE, 0x04, 0x0F, 0xF0, 0x08, 0x7C, 0x0F, 0xF0, 0x0F, + 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x42, 0x63, 0x58, 0x05, 0x9F, + 0x06, 0x00, 0xA8, 0x70, 0x94, 0xE7, 0x95, 0xB1, 0x36, 0x40, 0x3F, 0x73, + 0x9F, 0xF0, 0xF3, 0xA2, 0xF0, 0x63, 0x8C, 0x04, 0xD6, 0x21, 0x10, 0x30, + 0xF0, 0x21, 0xC0, 0x65, 0x34, 0xF5, 0x06, 0x30, 0x0F, 0x90, 0x03, 0x30, + 0x06, 0x30, 0x41, 0x24, 0x1E, 0x10, 0x9C, 0xE7, 0x3F, 0xF0, 0x00, 0x3F, + 0x60, 0xFE, 0x01, 0x66, 0x70, 0xE0, 0x21, 0xD5, 0x10, 0x31, 0x4A, 0x3F, + 0x0C, 0xC0, 0x93, 0xF0, 0x12, 0x73, 0x84, 0xCE, 0xA2, 0x00, 0x10, 0x94, + 0x27, 0x0F, 0x80, 0x74, 0xF1, 0x2F, 0xF1, 0x6A, 0xF2, 0xA0, 0xF2, 0xA8, + 0xF0, 0x3B, 0x41, 0xE4, 0x23, 0xFF, 0x73, 0xAD, 0x06, 0x40, 0x9F, 0xF0, + 0xA2, 0xF0, 0x52, 0x7B, 0x08, 0x1C, 0x8C, 0xCE, 0x08, 0x94, 0x0F, 0xE0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x81, 0xF0, 0xF0, 0x7E, 0xF0, 0xA8, 0xB0, 0x44, + 0x11, 0x8C, 0x28, 0x42, 0xE6, 0x31, 0x0F, 0xF0, 0x90, 0xF0, 0xF7, 0x7B, + 0x00, 0x08, 0x7B, 0xB5, 0x0F, 0x60, 0x41, 0x71, 0x30, 0xC0, 0x24, 0xC0, + 0xF1, 0x1D, 0xC1, 0x0F, 0x90, 0x03, 0x30, 0x06, 0x20, 0xF3, 0x60, 0x08, + 0xA8, 0xA0, 0x39, 0x5F, 0x10, 0x9C, 0xE7, 0x36, 0x10, 0x7B, 0xB5, 0x08, + 0x18, 0x08, 0x29, 0x00, 0x00, 0x0F, 0xF0, 0x8D, 0xF0, 0x14, 0x01, 0xA5, + 0x00, 0xF2, 0x51, 0x0F, 0xF0, 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xA7, 0xF1, 0x53, 0x31, 0xA8, 0x70, 0x10, 0xA5, 0x3F, 0xEF, 0x08, 0x63, + 0x94, 0x06, 0x60, 0x9C, 0xF0, 0x4A, 0xF1, 0x03, 0x30, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x06, 0x60, 0x08, 0xF9, 0xD0, 0xA8, + 0x20, 0xDF, 0x42, 0x6B, 0x2A, 0x40, 0x29, 0x42, 0x27, 0x00, 0x03, 0x10, + 0x99, 0xF0, 0xE4, 0xA5, 0xF0, 0x31, 0x52, 0x69, 0x30, 0x06, 0x20, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF9, 0x0F, 0xF0, 0x06, 0x60, 0x51, 0x00, + 0x03, 0x30, 0x03, 0x30, 0xAB, 0x10, 0x36, 0x00, 0x08, 0x7F, 0x4A, 0x73, + 0x0C, 0xA0, 0x9C, 0xF0, 0xCC, 0xFF, 0x6B, 0x9C, 0x00, 0x00, 0x9C, 0x10, + 0x94, 0xDE, 0x0C, 0xA0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xF8, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x8C, 0xD6, 0x10, 0x94, 0xD6, + 0x07, 0x08, 0x4A, 0x7B, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xF8, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFC, + 0xF6, 0xA2, 0x00, 0x55, 0x35, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x88, + 0xF2, 0xAA, 0x04, 0xC0, 0x03, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0x64, 0x05, + 0xFC, 0x06, 0xE6, 0x01, 0xD7, 0x0A, 0x9F, 0x20, 0xFF, 0xA8, 0xA0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, + 0xF0, 0xFF, 0x9E, 0xF7, 0x41, 0x21, 0x9F, 0x50, 0xA8, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x48, 0xF0, 0x13, + 0xF5, 0x63, 0x13, 0xD5, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0xF7, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x51, 0xF0, 0x88, 0xF2, 0x5E, 0x05, 0xE6, + 0x31, 0x9F, 0x90, 0xFF, 0x96, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x57, 0xF0, 0x88, 0xF2, 0xFF, 0xE6, 0x01, 0x9F, + 0xC0, 0x96, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x60, 0xF0, 0xF6, 0xFC, 0xFC, 0x26, 0xBD, 0x9F, 0xF0, 0x90, + 0xF0, 0x4A, 0xF1, 0x80, 0xA4, 0xF7, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x69, 0xF0, 0x13, 0xF5, 0x5A, 0xE6, 0x81, 0x0F, 0xF0, 0xDF, 0x0F, 0xF0, + 0x78, 0xF0, 0x94, 0xDE, 0x47, 0x01, 0x09, 0x90, 0x0F, 0xF0, 0x0F, 0xF0, + 0xF3, 0x0F, 0xF0, 0x63, 0xF0, 0x13, 0xF5, 0x0F, 0xF0, 0x0F, 0xF0, 0xBF, + 0xF1, 0x6E, 0x37, 0xE5, 0x08, 0xFF, 0x54, 0x00, 0x0C, 0xC0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x6F, 0xF0, 0x88, 0xF2, 0xB5, 0x05, 0x41, 0xD1, 0xFF, 0x0F, + 0xF0, 0x8D, 0xF0, 0x9F, 0xF0, 0x2D, 0xF3, 0x0F, 0xF0, 0x0F, 0xF0, 0x6F, + 0xF0, 0x9D, 0xFE, 0xFF, 0x63, 0x9F, 0x00, 0x41, 0x11, 0xA8, 0x90, 0x0F, + 0xF0, 0x8D, 0xE0, 0xC6, 0x9F, 0xC0, 0xBE, 0x08, 0x63, 0x94, 0x4F, 0x0E, + 0x09, 0x80, 0x0F, 0xF0, 0x0F, 0xF0, 0x75, 0xF0, 0xF8, 0xFB, 0xFD, 0x4A, + 0x08, 0x5A, 0x94, 0x3F, 0x00, 0x39, 0x00, 0x24, 0xF0, 0xE1, 0x0F, 0xF0, + 0xB1, 0x30, 0x17, 0x61, 0xE9, 0x61, 0x9E, 0x57, 0xCF, 0xB3, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x72, 0xF0, 0x88, 0xF2, 0x4A, 0x88, 0xF2, 0x0F, 0xF0, + 0x8D, 0xF0, 0x9F, 0xF0, 0xCF, 0x03, 0xFB, 0x71, 0xF4, 0x0F, 0xF0, 0x0F, + 0xF0, 0x6F, 0xF0, 0x88, 0xF2, 0x9F, 0x30, 0xCE, 0x9F, 0xF0, 0xBF, 0x0F, + 0xF0, 0x81, 0xF0, 0xA2, 0x20, 0xE6, 0x41, 0x13, 0xC5, 0x0F, 0xF0, 0x0F, + 0xF0, 0x72, 0xF0, 0xFF, 0xDE, 0xF3, 0xB9, 0x04, 0xE4, 0x00, 0x9F, 0x90, + 0x0F, 0xF0, 0x8A, 0xF0, 0xE6, 0xF1, 0xB5, 0xF5, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x72, 0xF0, 0x87, 0xF9, 0x08, 0x70, 0x4B, 0x9F, 0xA0, 0x0F, 0xF0, + 0xEF, 0x87, 0xF0, 0x9F, 0xF0, 0x2A, 0xC3, 0x0F, 0xF0, 0x0F, 0xF0, 0x75, + 0xF0, 0xD5, 0xFC, 0x8F, 0x01, 0xFF, 0xE7, 0x00, 0xE1, 0x00, 0x9F, 0x60, + 0x0F, 0xF0, 0x8A, 0xF0, 0xE6, 0xF1, 0x2A, 0x03, 0x57, 0x00, 0xFF, 0xCC, + 0x03, 0xF9, 0x96, 0x0F, 0xF0, 0x0F, 0xF0, 0x72, 0xF0, 0xAE, 0xFF, 0x20, + 0x0D, 0x10, 0x7F, 0x7B, 0x9F, 0x40, 0x09, 0x80, 0x0F, 0xF0, 0x26, 0xF1, + 0x9F, 0x80, 0x8C, 0x9F, 0x10, 0xBE, 0x3D, 0xCE, 0x0F, 0xF0, 0x0F, 0xF0, + 0x72, 0xF0, 0x40, 0xF8, 0x10, 0x73, 0x42, 0x1C, 0x9F, 0x36, 0x30, 0x27, + 0x50, 0x0F, 0xF0, 0x41, 0xF1, 0x44, 0x71, 0x9F, 0x80, 0x7B, 0x9F, 0xF0, + 0xBF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x5A, 0xF0, 0x98, 0x17, 0x8C, + 0xDE, 0x0C, 0xC0, 0x9F, 0x0F, 0xF0, 0x87, 0xE0, 0x9F, 0x60, 0xD6, 0x2A, + 0x23, 0x84, 0x2A, 0xC3, 0x0F, 0xF0, 0xD7, 0x0F, 0xF0, 0x0F, 0xF0, 0x5D, + 0xF0, 0xA8, 0xF0, 0x06, 0x50, 0x1E, 0x30, 0x0F, 0x90, 0x06, 0x60, 0xFF, + 0x9F, 0xA0, 0x74, 0xB7, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x57, 0xF0, 0xA8, 0xF0, 0xFF, 0xA8, 0xF0, 0xA2, 0xF0, 0x41, 0x71, 0xAC, + 0x08, 0x2A, 0xB3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x51, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x44, 0xF1, 0x75, 0x1C, 0x7C, 0x02, + 0x7C, 0x65, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x3F, 0xF0, 0xA8, 0xF0, 0xA2, 0xF0, 0xFF, 0x41, 0x0A, 0x9F, 0x00, + 0xDA, 0x24, 0x31, 0x06, 0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF7, + 0x0F, 0xF0, 0x0F, 0xF0, 0x3C, 0xF0, 0xA8, 0xF0, 0xE9, 0x64, 0x9F, 0xC0, + 0x6E, 0x07, 0x0F, 0xD0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0x38, 0xF4, 0x8C, 0x7F, 0xD6, 0x4A, 0x24, + 0xFB, 0x44, 0x44, 0x01, 0xAC, 0x65, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xD4, 0xF4, 0x18, + 0x8C, 0xDE, 0x1F, 0xA5, 0x23, 0x94, 0x40, 0xF2, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFD, 0x0F, 0xF0, 0x27, 0xF0, 0xE2, + 0xF2, 0x08, 0x52, 0xB4, 0x03, 0x0C, 0xA0, 0x0F, 0xF0, 0xE7, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x27, 0xF0, 0xB7, 0xF6, 0xF6, 0x06, 0x55, 0xC8, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, + 0xF0, 0xF5, 0xFA, 0xC6, 0x36, 0xFF, 0x10, 0x84, 0x65, 0x21, 0xC7, 0x42, + 0xC7, 0xF2, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x0F, 0xF0, 0x0F, + 0xF0, 0x48, 0xF0, 0x44, 0xF1, 0x04, 0x1B, 0x9F, 0x50, 0xC7, 0xF2, 0x62, + 0x11, 0xFF, 0x2C, 0xF4, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x48, 0xF0, 0xFD, 0x02, 0xFF, 0x69, 0x33, 0xA2, 0xE0, 0x96, + 0xF0, 0xCE, 0x13, 0x32, 0x08, 0x4A, 0x7B, 0x17, 0x62, 0x41, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x63, 0xF0, 0xAE, 0xF0, 0x73, 0x7F, + 0xBD, 0x18, 0x8C, 0xD6, 0x10, 0xAE, 0xB0, 0xA2, 0xF0, 0x62, 0xF1, 0xE0, + 0xDD, 0x04, 0xB7, 0x06, 0xE7, 0x03, 0x03, 0x10, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x66, 0xF0, 0x62, 0xF1, 0x63, 0x9C, 0x78, + 0xD3, 0x0F, 0xF0, 0x93, 0xF0, 0x13, 0x22, 0xF3, 0x2C, 0x34, 0xC7, 0x02, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x66, 0xF0, 0x62, 0xF1, + 0xFF, 0xDD, 0x04, 0xF3, 0x36, 0x0C, 0xC0, 0x9F, 0xF0, 0xB1, 0xF0, 0x78, + 0x00, 0x23, 0x01, 0xD1, 0xF4, 0xFF, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x5A, 0xF0, 0x62, 0x51, 0xAE, 0x00, 0xFE, 0x0F, 0xD0, + 0x0F, 0xF0, 0x90, 0xF0, 0x62, 0x11, 0xA5, 0xC7, 0x02, 0x1F, 0x08, 0x0F, + 0xF0, 0xEF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x66, 0xF0, 0xA7, 0xF7, + 0x62, 0x31, 0x13, 0xF2, 0xA8, 0xF0, 0xFF, 0xB1, 0xF0, 0x78, 0x00, 0x88, + 0x02, 0x62, 0x11, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x69, 0xF0, 0x42, 0xF6, 0x39, 0x63, 0x62, 0xB1, 0xBD, 0x03, 0x30, 0xA2, + 0xF0, 0xD3, 0xB1, 0xF0, 0x7B, 0x00, 0xAE, 0x00, 0x20, 0x01, 0x1A, 0x01, + 0x0F, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x69, 0xF0, 0x62, + 0xF1, 0x42, 0x10, 0x52, 0x8C, 0x10, 0x07, 0x73, 0xB5, 0x18, 0x84, 0x13, + 0x22, 0x0F, 0xF0, 0x09, 0x90, 0x8D, 0xE0, 0xF0, 0x75, 0x00, 0x10, 0x52, + 0x84, 0x5D, 0x23, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF1, 0x0F, 0xF0, + 0x66, 0xF0, 0x62, 0xF1, 0x6B, 0x91, 0x25, 0xCE, 0x1E, 0x70, 0xC3, 0xC0, + 0xD7, 0x0C, 0x80, 0x3E, 0x41, 0xA2, 0x50, 0x78, 0x00, 0x26, 0x01, 0x08, + 0x4A, 0x73, 0x1F, 0x95, 0x04, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x60, 0xF0, 0x62, 0xF1, 0x2C, 0x34, 0xFF, 0x21, 0x60, 0x6E, 0x41, + 0x06, 0x60, 0x63, 0x33, 0x06, 0x60, 0x8A, 0x20, 0x35, 0x31, 0xAA, 0x14, + 0xFF, 0x39, 0x5A, 0x03, 0x20, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x5D, 0xF0, 0xFC, 0x62, 0xF1, 0x29, 0x08, 0x42, 0x73, 0x62, 0xA1, + 0x62, 0xF1, 0x53, 0xF1, 0xE1, 0x84, 0xA8, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x54, 0xF0, 0xAE, 0xF0, 0xFE, 0x29, 0x62, 0x01, + 0x8C, 0xC7, 0x62, 0x0F, 0x60, 0x0A, 0x72, 0x53, 0xB1, 0x32, 0x01, 0xFA, + 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4E, + 0xF0, 0xB1, 0xF0, 0xFD, 0x18, 0x62, 0x71, 0x00, 0x00, 0x10, 0xAB, 0x80, + 0xA2, 0x70, 0xA8, 0xC0, 0x0F, 0xF0, 0xF6, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0x62, 0x11, 0x4A, 0x7F, 0x62, + 0x01, 0xAE, 0x20, 0xC6, 0x03, 0x30, 0x00, 0x00, 0x10, 0xA8, 0xA0, 0xA8, + 0xF0, 0xDB, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x3F, 0xF0, 0x62, 0xF1, 0x31, 0x7F, 0x62, 0x31, 0x0C, 0x00, 0xAE, 0x00, + 0x03, 0x20, 0x00, 0x00, 0xBD, 0xA8, 0x70, 0x0F, 0xF0, 0xDF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xB1, 0xF0, + 0xAE, 0x00, 0xFF, 0x31, 0x5A, 0x10, 0x5A, 0x94, 0x10, 0x6B, 0xB5, 0x00, + 0x00, 0x00, 0x18, 0x7B, 0xC6, 0x18, 0x7B, 0xCE, 0x08, 0x01, 0x29, 0x4A, + 0x0C, 0xA0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFC, 0x0F, 0xF0, 0x30, 0xF0, 0xAE, 0xF0, 0x21, 0x39, 0xAE, 0x00, 0x10, + 0x6B, 0x27, 0xAD, 0x18, 0x84, 0xD6, 0xA8, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x18, 0xF0, 0x08, 0x10, 0x3F, 0x21, 0x10, 0x4A, 0x7B, 0x08, 0x31, + 0x52, 0x0F, 0xF0, 0x80, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x12, 0xF6, 0x53, 0x71, 0x5A, 0xA5, 0x00, 0x00, 0x0F, + 0xF0, 0xCF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x10, 0x52, 0x8C, + 0x18, 0x5A, 0x94, 0x53, 0x81, 0x81, 0x42, 0x54, 0xF3, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFE, 0x2D, 0xF0, + 0xFF, 0xF3, 0xA8, 0x50, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x30, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x30, + 0xF0, 0xA8, 0xF0, 0x5A, 0x7F, 0xA8, 0x60, 0x18, 0xA8, 0x40, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFD, 0x0F, 0xF0, 0x0F, + 0xF0, 0x27, 0xF0, 0xA8, 0xF0, 0x39, 0xA8, 0xB0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xEF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x21, + 0xF0, 0xBD, 0x08, 0x3F, 0x31, 0x52, 0xA8, 0x40, 0x21, 0x42, 0x21, 0x73, + 0xC6, 0x04, 0x03, 0x10, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, + 0x00, 0x6B, 0xB5, 0x18, 0x73, 0xBD, 0x07, 0x10, 0x39, 0x63, 0xA8, 0x30, + 0x08, 0x18, 0x31, 0x18, 0x08, 0x52, 0x94, 0x03, 0x20, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x0F, 0xF0, 0x0F, 0xF0, + 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x7B, 0x10, 0x4A, 0x1F, 0x84, 0x08, + 0x29, 0x4A, 0x0C, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x12, 0xF0, 0xF3, 0x60, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, 0xF0, 0xF2, 0xF1, 0xFF, + 0x10, 0x95, 0x3F, 0xF0, 0x67, 0xF2, 0x9F, 0x00, 0x06, 0x60, 0x96, 0x30, + 0x90, 0x20, 0x73, 0x7F, 0xB1, 0x00, 0xB1, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x2A, 0xF0, 0x3F, 0xF3, 0xD2, 0x00, 0x55, 0x05, 0xFF, 0xAA, 0x34, 0x4E, + 0xF0, 0x6A, 0xF2, 0xB3, 0x34, 0x05, 0xF4, 0xB1, 0x90, 0x2C, 0x37, 0x5C, + 0x31, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x2A, 0xF0, 0xA5, 0x30, + 0x53, 0xD1, 0x4B, 0xF0, 0xD4, 0x24, 0xFF, 0x1D, 0x01, 0x6F, 0x63, 0x9C, + 0xF0, 0x3F, 0xF3, 0x48, 0x00, 0x08, 0x24, 0xFC, 0x0F, 0xF0, 0xDF, 0x30, + 0xF0, 0x3F, 0xF3, 0x4A, 0x4A, 0x51, 0x63, 0xA8, 0x80, 0x51, 0xF0, 0xC5, + 0xE1, 0xEB, 0x0F, 0xF0, 0x8A, 0xF0, 0x3F, 0xF6, 0x0F, 0xF0, 0x36, 0xF0, + 0x3F, 0xF3, 0x6C, 0x00, 0x09, 0x00, 0xFF, 0xA8, 0xF0, 0x5A, 0xF0, 0xA0, + 0xF2, 0x0F, 0xF0, 0x8A, 0xF0, 0xAB, 0xF0, 0x27, 0xF3, 0x39, 0xF0, 0xFF, + 0xD5, 0xF0, 0xA5, 0x00, 0x2A, 0x40, 0xA8, 0xF0, 0xC2, 0xF1, 0x39, 0x6B, + 0x1D, 0xC1, 0x9F, 0x0F, 0xF0, 0x57, 0xF0, 0x48, 0xF0, 0x04, 0x72, 0xA5, + 0xF0, 0x30, 0xF0, 0x80, 0x21, 0x4A, 0xC1, 0xFF, 0xA8, 0xF0, 0x67, 0xF2, + 0x0F, 0xF0, 0x0F, 0xF0, 0x51, 0xF0, 0x45, 0xF0, 0xE8, 0x32, 0xA8, 0xF0, + 0xFF, 0x2C, 0xF4, 0xD8, 0x50, 0x2D, 0xF0, 0x22, 0x78, 0x4E, 0xF3, 0x2D, + 0xF0, 0x38, 0xF4, 0x03, 0x30, 0xFF, 0x2C, 0xF4, 0x1D, 0xF1, 0x56, 0xF1, + 0x76, 0xF2, 0x17, 0xC1, 0x30, 0xF0, 0x23, 0xF4, 0x6F, 0xC0, 0xFF, 0xDE, + 0xF0, 0x0F, 0x30, 0x06, 0x00, 0x00, 0x00, 0x10, 0x39, 0x63, 0x18, 0x0F, + 0x39, 0x6B, 0x00, 0x00, 0xE1, 0x00, 0x39, 0x60, 0x33, 0xF0, 0xE7, 0x00, + 0x06, 0x50, 0xFC, 0xDF, 0xF2, 0x20, 0x11, 0xDE, 0xD0, 0x2D, 0xF0, 0x4A, + 0x8C, 0xA5, 0x60, 0x50, 0xF1, 0xCF, 0x33, 0xF0, 0x1E, 0x00, 0x4B, 0x00, + 0x12, 0x00, 0x33, 0xF0, 0x25, 0x32, 0x07, 0x22, 0x30, 0xF0, 0xFF, 0x0D, + 0x75, 0x82, 0xF2, 0xA5, 0xB0, 0x30, 0xF0, 0x8C, 0x34, 0x63, 0x3F, 0x03, + 0xA6, 0xF2, 0xDF, 0xFB, 0x61, 0xF8, 0xF1, 0x4A, 0xC7, 0x66, 0xF0, 0x29, + 0x07, 0xCF, 0x60, 0x66, 0xF0, 0xE7, 0xA0, 0xFF, 0x81, 0x20, 0x4A, 0xF1, + 0x72, 0xF0, 0x80, 0x11, 0x2D, 0xF0, 0xA8, 0x80, 0x72, 0xF0, 0x0C, 0xA0, + 0xFF, 0x69, 0xF0, 0xAF, 0xF2, 0x63, 0xF0, 0xEA, 0x80, 0x21, 0x00, 0x0C, + 0xC0, 0x30, 0xF0, 0xF2, 0x21, 0xFF, 0x30, 0x20, 0x45, 0xF0, 0x4E, 0x16, + 0x45, 0xB0, 0x17, 0xF1, 0x69, 0xF0, 0x60, 0xF0, 0x56, 0x21, 0xFF, 0x1B, + 0xF0, 0x03, 0x00, 0x2A, 0x00, 0xCC, 0x00, 0x1E, 0x00, 0x0C, 0xC0, 0xA5, + 0xF0, 0x3F, 0xF3, 0xFF, 0x4C, 0xF2, 0x48, 0xF0, 0x89, 0x01, 0x0C, 0xA0, + 0x63, 0xF0, 0x01, 0xF2, 0x21, 0x42, 0x3F, 0x15, 0xF0, 0x21, 0x5A, 0x13, + 0x12, 0xE9, 0x01, 0x09, 0x90, 0x36, 0xF0, 0x3F, 0xF3, 0xF9, 0x2A, 0xF0, + 0x29, 0x01, 0x00, 0x00, 0x69, 0xF0, 0x89, 0x01, 0x0F, 0xF0, 0x5A, 0xF0, + 0x57, 0xF3, 0xFF, 0x03, 0x20, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, + 0x00, 0x3C, 0x00, 0xF2, 0x41, 0xE2, 0x32, 0xFF, 0x33, 0xF0, 0xA8, 0xF0, + 0x66, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x45, 0xF0, 0xCA, 0x02, 0x5A, 0x90, + 0xFF, 0x9F, 0xF0, 0x3F, 0xF0, 0xE4, 0x03, 0x06, 0x40, 0x36, 0xF0, 0xA8, + 0xF0, 0x5A, 0x63, 0xC0, 0xBF, 0x08, 0x11, 0x0F, 0xF0, 0x0F, 0xF0, 0x42, + 0xF0, 0x2D, 0x00, 0xA8, 0x30, 0xA5, 0xF0, 0x42, 0xF0, 0xFF, 0xA5, 0x00, + 0xEA, 0x90, 0x36, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x08, 0x71, 0x0F, 0xF0, + 0x48, 0xF0, 0xFF, 0xAE, 0xF3, 0xA8, 0xF0, 0x4A, 0xF1, 0x31, 0x5A, 0x4A, + 0xC1, 0x36, 0xF0, 0xAA, 0xFD, 0xE7, 0xA8, 0xF0, 0xFA, 0x52, 0x0F, 0xF0, + 0x48, 0xF0, 0x57, 0xF0, 0xB5, 0x0C, 0xC0, 0xA2, 0xF0, 0xDF, 0x08, 0x21, + 0x39, 0x0F, 0xF0, 0x00, 0x36, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xE8, 0xA8, + 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xA5, 0xF0, 0x29, 0x52, 0x9D, + 0xF2, 0x9F, 0x0F, 0xF0, 0x2A, 0xF0, 0xA8, 0xF0, 0x53, 0xF1, 0x0F, 0xF0, + 0x39, 0xF0, 0xFF, 0xF3, 0xA5, 0xF0, 0xFF, 0xEB, 0x0B, 0x10, 0x21, 0x42, + 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0xF1, 0x54, 0xF3, 0x0F, + 0xF0, 0x39, 0xF0, 0x53, 0xF1, 0x17, 0xFA, 0x10, 0x29, 0x4A, 0x1F, 0x54, + 0x70, 0x0F, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0xA8, 0xB0, 0xA8, 0xF0, 0x0F, + 0xF0, 0x36, 0xF0, 0xFF, 0xFE, 0xF1, 0xFF, 0xF3, 0xEF, 0x0D, 0x03, 0x10, + 0x0F, 0xF0, 0x0F, 0xF0, 0x30, 0xF0, 0xA8, 0xF0, 0xFF, 0xA8, 0xF0, 0x0F, + 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x39, + 0xF0, 0xFF, 0xFE, 0xF1, 0xA8, 0x60, 0xA8, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, + 0x53, 0xF1, 0xA8, 0xF0, 0x5A, 0x7F, 0xA8, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0xE0, 0x57, 0x0F, 0xF0, 0x36, 0xF0, 0xFF, 0xFF, + 0xF3, 0x4A, 0xFE, 0xF1, 0xAD, 0xA8, 0xC0, 0x0F, 0xF0, 0x39, 0xF0, 0xA8, + 0xF0, 0xF5, 0x53, 0xF1, 0xA8, 0xF0, 0x0F, 0xF0, 0x30, 0xF0, 0xA8, 0xF0, + 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x30, 0xF0, 0x02, 0x7A, 0xA8, + 0x20, 0x60, 0xA6, 0xA8, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0xFF, + 0xFC, 0x26, 0xA8, 0x30, 0xA8, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, + 0x4E, 0xC0, 0xA8, 0x90, 0xFF, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0x6A, + 0xD5, 0x5A, 0xA8, 0xB0, 0x0F, 0xF0, 0x3C, 0xF0, 0xEF, 0xAB, 0xF9, 0xA8, + 0xA0, 0xA8, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0xFF, 0x0F, 0xF0, 0x39, 0xF0, 0xA8, 0xF0, 0x53, 0xE1, 0xA8, 0x80, + 0x0F, 0xF0, 0x36, 0xF0, 0x53, 0xF1, 0xFF, 0x08, 0xD4, 0xA8, 0xF0, 0x0F, + 0xF0, 0x39, 0xF0, 0xA8, 0xF0, 0x5A, 0xFE, 0xE1, 0x5A, 0x5F, 0xAD, 0xA8, + 0x60, 0x0F, 0xF0, 0x36, 0xF0, 0xFE, 0xF1, 0x5A, 0xC0, 0xAD, 0x21, 0x0F, + 0xF0, 0xFE, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0x4E, 0xF0, 0xA4, 0xB1, + 0x0F, 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0xFF, 0x57, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x2D, 0xF0, 0xA8, 0xF0, 0x4E, 0xF0, 0x0F, 0xF0, 0x36, 0xF0, 0xFF, + 0x54, 0xF3, 0xA8, 0xF0, 0x57, 0x80, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, + 0xA8, 0xF0, 0xA8, 0xF0, 0xFF, 0x0F, 0xF0, 0x36, 0xF0, 0xA8, 0xF0, 0x59, + 0xF1, 0xE1, 0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0xFF, 0xA8, 0xF0, + 0xA8, 0xF0, 0x0F, 0xF0, 0x90, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0C, 0xB0, + 0x0F, 0xF0, 0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x6B, 0x18, 0x39, + 0x73, 0xA8, 0x60, 0x87, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, 0x8D, 0xF0, + 0xA8, 0xF0, 0xA5, 0xF0, 0x06, 0x40, 0x0F, 0xF0, 0xFF, 0x09, 0x90, 0x03, + 0x30, 0x00, 0x00, 0xBD, 0x00, 0x75, 0xE3, 0x66, 0x03, 0x03, 0x10, 0xA8, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x81, 0xF0, 0x03, 0x23, 0x06, 0x40, + 0x0F, 0xF0, 0x0F, 0xF0, 0x7E, 0xF0, 0xFF, 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, + 0xF0, 0x0F, 0xF0, 0x90, 0xF0, 0xFE, 0xF1, 0xA8, 0x80, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x7B, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, + 0x90, 0xF0, 0xA8, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x72, + 0xF0, 0xA8, 0xF0, 0x4E, 0xB0, 0xA8, 0x90, 0x0F, 0xF0, 0xFF, 0x90, 0xF0, + 0x53, 0xF1, 0x7B, 0x09, 0x90, 0x0F, 0xF0, 0x0F, 0xF0, 0x09, 0x90, 0x03, + 0x30, 0xFB, 0x00, 0x00, 0x21, 0x52, 0x1E, 0x30, 0xC9, 0x70, 0x0F, 0x00, + 0x87, 0xF0, 0xDD, 0x31, 0xF9, 0x0F, 0xF0, 0x0F, 0xF0, 0x81, 0xF0, 0x18, + 0x42, 0x7B, 0x09, 0x90, 0x0F, 0xF0, 0xC7, 0x0F, 0xF0, 0x09, 0x90, 0x03, + 0x30, 0x00, 0x00, 0x21, 0x4A, 0x9C, 0x0F, 0x00, 0x8F, 0xB7, 0x00, 0xAB, + 0x40, 0x4E, 0x10, 0x84, 0x03, 0x30, 0x87, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xF7, 0x7E, 0xF0, 0x21, 0x42, 0x8C, 0x0C, 0xB0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x09, 0x90, 0xF1, 0x03, 0x30, 0x00, 0x00, 0xA5, 0x29, 0x52, 0xAD, 0x1B, + 0x90, 0x0F, 0x00, 0xC3, 0x87, 0xF0, 0x03, 0x10, 0x0F, 0xF0, 0x0F, 0xF0, + 0x60, 0xF0, 0xA5, 0x1F, 0x31, 0x09, 0x80, 0xBF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x03, 0x00, 0x29, 0xFC, 0x0F, 0xBF, + 0x5A, 0x3F, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0xE6, 0xF1, 0xCF, 0xD9, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x1E, 0xF0, 0xFC, 0xA6, 0xA5, 0xA8, 0x90, 0x0F, 0xF0, 0xDF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x33, 0xF0, + 0xFC, 0xF6, 0x88, 0x62, 0xFF, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x33, 0xF0, 0xFF, 0x9F, 0xF0, + 0xA8, 0xC0, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x3F, 0xF0, 0xE6, 0xF1, 0x44, 0xC1, 0xA8, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x4B, 0xF0, + 0xE6, 0xF1, 0x9F, 0x30, 0xB1, 0x50, 0xAE, 0xF0, 0xA8, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x57, 0xF0, 0x9F, 0xF0, 0xE6, + 0x71, 0x24, 0x00, 0x12, 0xB0, 0xFF, 0x93, 0x30, 0x03, 0x30, 0x03, 0x30, + 0x00, 0x00, 0xA8, 0xA0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0x5A, 0xF0, 0xE6, 0xF1, 0x41, 0x61, 0x99, 0x60, 0x93, 0xF0, 0x4A, + 0xF1, 0x97, 0xF2, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x63, 0xF0, + 0x13, 0xF5, 0x88, 0x32, 0x0F, 0xF0, 0x8D, 0xF0, 0xFF, 0x44, 0xF1, 0x12, + 0x0C, 0x8E, 0x22, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x6F, 0xF0, 0x71, + 0xF4, 0xFF, 0x13, 0x15, 0x9F, 0xC0, 0x0F, 0xF0, 0x84, 0xF0, 0xE6, 0xF1, + 0x9F, 0x40, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x66, 0xF0, 0x88, + 0xF2, 0x05, 0x17, 0x0F, 0xF0, 0x8D, 0xF0, 0x44, 0xF1, 0xE6, 0x71, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x6C, 0xF0, 0xE6, 0xF1, 0x13, 0x95, + 0x0F, 0xF0, 0x8A, 0xF0, 0xFF, 0x44, 0xF1, 0xE6, 0x31, 0x44, 0xF1, 0x0F, + 0xF0, 0x0F, 0xF0, 0x6C, 0xF0, 0xB7, 0xFC, 0xE1, 0x30, 0xFF, 0x29, 0x4A, + 0x0F, 0xF0, 0x94, 0x29, 0x0F, 0xF0, 0x78, 0xF0, 0x4A, 0x64, 0xCF, 0x33, + 0x39, 0x71, 0xF4, 0x0F, 0xF0, 0x0F, 0xF0, 0x6F, 0xF0, 0x88, 0xF2, 0x2A, + 0xC3, 0xFD, 0x0F, 0xF0, 0x84, 0xF0, 0x44, 0xF1, 0xE6, 0x31, 0x9F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x6C, 0xF0, 0xFF, 0x9F, 0xF0, 0x3F, 0x00, 0x06, + 0x60, 0x0F, 0xF0, 0x87, 0xF0, 0x44, 0xF1, 0x88, 0x32, 0x9F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x6C, 0xF0, 0xE6, 0xF1, 0x9F, 0x90, 0x0F, 0xF0, + 0x0F, 0xF0, 0x75, 0xF0, 0xFF, 0xA2, 0x20, 0x39, 0xA2, 0xA0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x60, 0xF0, 0x2C, 0x2A, 0xFD, 0x00, 0x00, 0x9F, + 0x90, 0x0F, 0xF0, 0x84, 0xF0, 0x9F, 0xF0, 0x41, 0x01, 0x2A, 0xF3, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0x6F, 0xF0, 0xE5, 0xF8, 0x41, 0x01, 0x9F, 0xC0, + 0x0F, 0xF0, 0x81, 0xF0, 0xE6, 0xF1, 0xFF, 0x9F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x6F, 0xF0, 0x4A, 0xF1, 0x45, 0x00, 0xA2, 0x60, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x78, 0xF0, 0x5E, 0x02, 0x5D, 0x00, 0x2A, 0xD3, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x60, 0xF0, 0x2C, 0x2A, 0x18, 0x31, 0x6B, + 0x18, 0x29, 0x1A, 0x0F, 0xF0, 0xC3, 0x0F, 0xF0, 0x7E, 0xF0, 0x2A, 0xF3, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x66, 0xF0, 0xA8, 0xF0, 0xFF, 0xA5, + 0x06, 0x50, 0x0F, 0xF0, 0x90, 0xF0, 0x9F, 0xF0, 0xCC, 0xE3, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFE, 0x0F, 0xF0, 0x5D, 0xF0, 0x53, 0xF1, 0x4A, 0xA8, 0xC0, + 0x9C, 0xF0, 0xE6, 0xF1, 0x41, 0x01, 0xF7, 0x9F, 0xD0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x4E, 0xF0, 0xA9, 0xF2, 0xA2, 0xF0, 0xFF, + 0x9F, 0xF0, 0x2A, 0xF3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x4E, 0xF0, 0xA8, 0xF0, 0xFF, 0xA8, 0xF0, 0x44, 0xF1, 0x9F, 0x00, 0x41, + 0xF1, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x39, 0xF0, 0xA8, 0xF0, 0x9F, 0xD0, 0x31, 0x63, 0xBA, 0xC9, 0x0F, 0xF0, + 0xCF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x3C, 0xF0, 0xA8, + 0xF0, 0x31, 0xA8, 0x20, 0xBF, 0x03, 0x30, 0x9D, 0xC5, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x33, 0xF0, + 0xA8, 0xF0, 0x29, 0x42, 0x9C, 0xFB, 0x64, 0xAC, 0xC5, 0x0F, 0xF0, 0xE3, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, + 0xA8, 0xF0, 0x21, 0x7F, 0x31, 0x73, 0xA5, 0x33, 0x40, 0xF2, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x0F, 0xF0, 0x0F, 0xF0, 0x24, + 0xF0, 0x40, 0xF2, 0x65, 0xF4, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0x0F, 0xF0, 0x15, 0xF0, 0xA7, 0x67, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x9F, + 0xF0, 0x62, 0xF1, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x3F, 0xF0, 0xA6, 0xF2, 0x9F, 0x30, 0x9C, 0x60, + 0xFF, 0xB1, 0x30, 0x8A, 0x00, 0x78, 0xF3, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x48, 0xF0, 0x50, 0xF1, 0x0F, 0x20, + 0x06, 0x30, 0xB7, 0x60, 0x00, 0x00, 0x62, 0x31, 0x62, 0xF1, 0xFF, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x60, 0xF0, 0x5F, 0xF1, 0x39, + 0x21, 0x3F, 0x31, 0xAE, 0x10, 0xAB, 0x60, 0xA5, 0xF0, 0x62, 0xF1, 0xA7, + 0x34, 0x62, 0xD1, 0x0F, 0xF0, 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x5A, 0xF0, 0x62, 0xF1, 0x13, 0x82, 0xA5, 0xF0, 0x16, 0xF2, 0xFF, 0x13, + 0x22, 0x63, 0x78, 0x83, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x63, 0xF0, 0xFD, 0x62, 0xF1, 0xC7, 0xF2, 0xA8, 0xF0, 0x62, 0xF1, 0x8C, + 0xA7, 0x34, 0x62, 0xA1, 0x0F, 0xF0, 0xEF, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x5D, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0xA2, 0xF0, 0x13, 0xF2, 0xFF, + 0x62, 0xF1, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x5D, 0xF0, + 0x2C, 0xF4, 0x42, 0x7F, 0xB1, 0x80, 0x0F, 0xF0, 0x96, 0xF0, 0x42, 0x62, + 0x61, 0x29, 0x03, 0x30, 0x0F, 0xF0, 0xD7, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x63, 0xF0, 0x62, 0xF1, 0xEA, 0x00, 0x62, 0x11, 0x62, 0xF1, 0xFF, + 0x9F, 0xF0, 0x62, 0xF1, 0x18, 0x62, 0x41, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0xFB, 0x63, 0xF0, 0x62, 0xF1, 0x62, 0xF1, 0x0F, 0xF0, + 0x96, 0xF0, 0x81, 0x00, 0x78, 0x00, 0x08, 0x7F, 0x18, 0x31, 0xB1, 0x90, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x60, 0xF0, 0xFC, 0x62, + 0xF1, 0x33, 0x00, 0x29, 0x13, 0xB2, 0xA2, 0xF0, 0x5C, 0xF1, 0x78, 0x00, + 0x23, 0x01, 0xFB, 0xAB, 0x90, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x5A, 0xF0, 0x62, 0xF1, 0xAE, 0xC0, 0xFF, 0x0F, 0xF0, 0x90, 0xF0, + 0xAA, 0x94, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x48, 0xF0, 0x62, 0xF1, 0xA8, 0xF0, 0xA8, 0xF0, 0xFF, 0x23, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x4B, 0xF0, + 0x62, 0xF1, 0x63, 0x21, 0x00, 0x0C, 0xC0, 0x9F, 0xF0, 0xEF, 0xA8, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x3F, 0xF0, + 0x62, 0xF1, 0xFF, 0x09, 0x90, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x3C, 0xF0, 0x62, 0xF1, + 0xB1, 0xB0, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x39, 0xF0, 0xAE, 0xF0, 0xB1, 0x10, 0xAE, + 0x40, 0xAB, 0x20, 0x29, 0x7F, 0xA8, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x30, 0xF0, 0xFF, 0x62, 0xF1, + 0x18, 0x29, 0xAE, 0x00, 0x31, 0x39, 0x8C, 0x29, 0x09, 0x39, 0x8C, 0x31, + 0x39, 0x94, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0xE0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2A, 0xF0, 0xAE, 0xF0, 0x18, + 0x7F, 0x29, 0x5A, 0x21, 0x29, 0x63, 0xA8, 0x30, 0x0F, 0xF0, 0x0F, 0xF0, + 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x15, 0xF0, 0x00, 0x00, 0xFF, 0x08, 0x06, 0x50, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0xFE, 0x0F, 0xF0, + 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x10, 0x21, 0x1F, + 0x04, 0x26, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0xE5, 0x00, 0x00 +}; + + +#endif // LOGO_H diff --git a/ariane/src/main.c b/ariane/src/main.c index 4a82e73..c149b24 100644 --- a/ariane/src/main.c +++ b/ariane/src/main.c @@ -1,791 +1,215 @@ -#include "utils.h" -#include "lib/printk.h" -#include "lib/heap.h" -#include "display/video_fb.h" +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer + * Copyright (c) 2020 eliboa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ -#include "hwinit/btn.h" -#include "hwinit/hwinit.h" -#include "hwinit/di.h" -#include "hwinit/mc.h" -#include "hwinit/mtc.h" -#include "hwinit/t210.h" -#include "hwinit/sdmmc.h" -#include "hwinit/timer.h" -#include "hwinit/cluster.h" -#include "hwinit/clock.h" -#include "hwinit/max77620.h" -#include "hwinit/max7762x.h" -#include "hwinit/util.h" -#include "hwinit/i2c.h" -#include "hwinit/pmc.h" -#include "hwinit/uart.h" -#include "hwinit/fuse.h" -#include "hwinit/pinmux.h" -#include "hwinit/sdram.h" -#include "hwinit/carveout.h" -#include "rcm_usb.h" -#include "usb_output.h" -#include "storage.h" -#include "lib/ff.h" -#include "lib/decomp.h" -#include "cbmem.h" -#include -#include +#include "libs/hekate_config.h" +hekate_config h_cfg; +emummc_cfg_t emu_cfg; -#include "usb_command.h" +#include +#include +#include +#include +#include +#include "gfx/gfx.h" +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "logo.h" -#define XVERSION 3 -#define IPL_HEAP_START 0x84000000 -#define IPL_HEAP_SZ 0x20000000 // 512MB. -#define IPL_STACK_TOP 0x83100000 -#define IPL_LOAD_ADDR 0x40008000 +extern int _usbd_initialize_ep0(); +#include "ariane.h" +bool usb_ready = false; + +// Hekate & boot config +boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; +const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = { + .magic = BL_MAGIC, + .version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16), + .rsvd0 = 0, + .rsvd1 = 0 +}; + +volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; extern void pivot_stack(u32 stack_top); -static int initialize_mount(FATFS* outFS, u8 devNum) -{ - sdmmc_t* currCont = get_controller_for_index(devNum); - sdmmc_storage_t* currStor = get_storage_for_index(devNum); - - if (currCont == NULL || currStor == NULL) - { - printk("get_controller_for_index(%d) OR get_storage_for_index(%d) failed\n", devNum, devNum); - return 0; - } - if (currStor->sdmmc != NULL) - return 1; //already initialized - - if (devNum == 0) //maybe support more ? - { - if (sdmmc_storage_init_sd(currStor, currCont, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) && f_mount(outFS, "", 1) == FR_OK) - return 1; - else - { - if (currStor->sdmmc != NULL) - sdmmc_storage_end(currStor, 0); - - memset(currCont, 0, sizeof(sdmmc_t)); - memset(currStor, 0, sizeof(sdmmc_storage_t)); - } - } - - if (devNum == 1) - { - if (sdmmc_storage_init_mmc(currStor, currCont, SDMMC_4, SDMMC_BUS_WIDTH_8, 4) == 1) - { - printk("sdmmc_storage_init_mmc succeeded\n"); - if (sdmmc_storage_set_mmc_partition(currStor, 1)) // BOOT0 - return 1; - - printk("sdmmc_storage_set_mmc_partition failed\n"); - } - - printk("sdmmc_storage_init_mmc 2 failed\n"); - if (currStor->sdmmc != NULL) - sdmmc_storage_end(currStor, 0); - - memset(currCont, 0, sizeof(sdmmc_t)); - memset(currStor, 0, sizeof(sdmmc_storage_t)); - } - - return 0; -} - -static void deinitialize_storage(u32 devNum) -{ - if (devNum == 0) - f_unmount(""); - - sdmmc_storage_t* currStor = get_storage_for_index((u8)devNum); - if (currStor != NULL && currStor->sdmmc != NULL) - { - if (!sdmmc_storage_end(currStor, 1)) - dbg_print("sdmmc_storage_end for storage idx %u FAILED!\n", devNum); - else - memset(currStor, 0, sizeof(sdmmc_storage_t)); - } - -} -static void deinitialize_storages() -{ - for (u32 i=0; i 2) - { - UC_Header* uc = (UC_Header*)usb_read_buff; - if (uc->signature == COMMAND || uc->signature == EXEC_COMMAND) - { - printk("Received command from USB host\n"); - return uc->command; - } - } - } - return NONE; -} - -// This is a safe and unused DRAM region for our payloads. -#define RELOC_META_OFF 0x7C -#define PATCHED_RELOC_SZ 0x94 -#define PATCHED_RELOC_STACK 0x40007000 -#define PATCHED_RELOC_ENTRY 0x40010000 -#define EXT_PAYLOAD_ADDR 0xC0000000 -#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -#define COREBOOT_END_ADDR 0xD0000000 -#define CBFS_DRAM_EN_ADDR 0x4003e000 -#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" -#define EMC_SCRATCH0 0x324 -#define EMC_HEKA_UPD (1 << 30) - static void *coreboot_addr; -typedef struct __attribute__((__packed__)) _reloc_meta_t -{ - u32 start; - u32 stack; - u32 end; - u32 ep; -} reloc_meta_t; - void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { - memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); + memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); - volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); + volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); - relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); - relocator->stack = PATCHED_RELOC_STACK; - relocator->end = payload_dst + payload_size; - relocator->ep = payload_dst; -} + relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); + relocator->stack = PATCHED_RELOC_STACK; + relocator->end = payload_dst + payload_size; + relocator->ep = payload_dst; -FRESULT f_write_buffer(FIL* fp, const void* buffer, u32 length, u32 *bytesWritten) -{ - int block_size = 4096; - int btw = 0; - *bytesWritten = 0; - FRESULT res; - while(btw < length) + if (payload_size == 0x7000) { - char b[block_size]; - memcpy(b, buffer + btw, block_size); - unsigned int bytesWrite = 0; - int bs = btw + block_size > length ? length - btw : block_size; - printk("Prepare to write %db to file\n", bs); - res = f_write(fp, b, bs, &bytesWrite); - if (res != FR_OK) - { - printk("Res = %d\n", res); - *bytesWritten = btw; - return res; - } - if (!(bytesWrite > 0)) - { - printk("ERROR 2 bytesWrite = 0\n"); - return 20; - } - btw += bytesWrite; - printk("%d bytesWriten\n", bytesWrite); - } - *bytesWritten = btw; - return res; -} - -void send_response(const void* in_buffer, u32 size) -{ - u32 new_size = size + sizeof(u16), bytes = 0; - if (new_size > RESPONSE_MAX_SIZE) - return; - - u16 signature = RESPONSE; - memcpy(&usb_write_buff[0], (u8*)&signature, sizeof(u16)); - memcpy(&usb_write_buff[sizeof(u16)], in_buffer, size); - rcm_usb_device_write_ep1_in_sync(&usb_write_buff[0], new_size, &bytes); -} - -bool recv_bin_packet(u32 *bytesReceived) -{ - //printk("Preparing to receive packet\n"); - memset(&usb_read_buff[0], 0, sizeof(UC_BlockHeader)); - *bytesReceived = 0; - u32 bytesTransferred = 0; - if(rcm_usb_device_read_ep1_out_sync(usb_read_buff, USB_BUFFER_LENGTH, &bytesTransferred) && !bytesTransferred) - { - printk("Failed to receive packet\n"); - return false; + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); //Bootblock + *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; } +} - UC_BlockHeader *bh = (UC_BlockHeader*)&usb_read_buff[0]; +bool is_ipl_updated(void *buf, char *path, bool force) +{ + ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t)); - if (bh->signature != BIN_PACKET) - { - printk("Error, did not receive a bin packet from usb pipe\n"); - return false; - } + bool magic_valid = update_ft->magic == ipl_ver.magic; + bool force_update = force && !magic_valid; + bool is_valid_old = magic_valid && (byte_swap_32(update_ft->version) < byte_swap_32(ipl_ver.version)); - //memcpy(&[buffer[0], &usb_read_buff[sizeof(UC_BlockHeader)]], bh->block_size); + if (magic_valid) + if (byte_swap_32(update_ft->version) > byte_swap_32(ipl_ver.version)) + return false; + + // Update if old or broken. + if (force_update || is_valid_old) + { + FIL fp; + volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); + boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); + memset(tmp_cfg, 0, sizeof(boot_cfg_t)); - // Send bloc size in response - send_response((const void*)&bh->block_size, sizeof(bh->block_size)); - - *bytesReceived = bh->block_size; - //printk("Received a packet %db\n", bh->block_size); + f_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL); + + // Write needed tag in case injected ipl uses old versioning. + f_write(&fp, "ARIA01", 6, NULL); + + // Reset boot storage configuration. + f_lseek(&fp, PATCHED_RELOC_SZ); + f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); + + f_close(&fp); + free(tmp_cfg); + } return true; } -void on_WriteSDFileCommand() +void ipl_main() { - UC_SDIO* uc = (UC_SDIO*)usb_read_buff; - - printk("Received a WRITE_SD_FILE for path : %s (%uMB)\n", uc->path, uc->file_size / 1024 / 1024); - printk("file_size = %u, bytescount = %u\n", uc->file_size, 0); - //printk("file_size = %u, bytescount = %u\n", uc->file_size, 0); - //printk("Size of UC_SDIO = %ld, sign=%ld, command=%ld, path=%ld, filesize=%ld\n", sizeof(*uc), sizeof(uc->signature), sizeof(uc->command), sizeof(uc->path), sizeof(uc->file_size)); - - bool lz4compress = uc->is_lz4_compressed; - FIL fp; - FRESULT res; - f_unlink(uc->path); - res = f_open (&fp, uc->path, FA_WRITE | FA_CREATE_ALWAYS); - if (res == FR_OK) - { - u32* bytesCount = malloc(sizeof(u32)); - u32* bytesTotal = malloc(sizeof(u32)); - u32* begin_time = malloc(sizeof(u32)); - *bytesCount = 0; - *bytesTotal = uc->file_size; - *begin_time = get_tmr_s(); - int numTries = 0; - numTries = 0; - char *path = malloc(256); - memcpy(path, uc->path, 256); - u8* buf32 = malloc(64); - int *buf32_s = malloc(sizeof(int)); - *buf32_s = 0; - int *pre_pct = malloc(sizeof(int)); - *pre_pct = -1; - while (*bytesCount < *bytesTotal) - { - u32 bytesTransferred = 0; - if (!recv_bin_packet(&bytesTransferred)) - break; - - //printk("Preparing to write file block\n"); - // Write (uncompressed bin) - u32 bytesWrite = 0; - if (f_write(&fp, &usb_read_buff[32], bytesTransferred, &bytesWrite) != FR_OK) - { - printk("Failed to write tmp_buffer\n"); - break; - } - if (!(bytesWrite > 0)) - { - printk("ERROR bytesWrite = 0\n"); - break; - } - *bytesCount += bytesWrite; - - //printk("File block written (total %u\n", *bytesCount); - - int pct = (u64)(*bytesCount) * 100 / *bytesTotal; - if (pct != *pre_pct || *bytesCount >= *bytesTotal) - { - printk("\rDownloading %s - %d%% (%d MB) ", path, pct, *bytesCount / 1024 / 1024 ); - *pre_pct = pct; - } - - /* - //printk("Prepare to receive file\n"); - if(rcm_usb_device_read_ep1_out_sync(usb_read_buff, USB_BUFFER_LENGTH, &bytesTransferred)) - { - printk("Failed to receive file at off. %u \n", *bytesCount); - numTries++; - continue; - } - if (bytesTransferred) - { - unsigned int bytesWrite = 0; - UC_BlockHeader *bh = (UC_BlockHeader*)&usb_read_buff[0]; - - if (bh->signature != BIN_PACKET) - { - printk("Error, did not receive a bin packet from usb pipe"); - break; - } - - if (lz4compress) - { - int bfs = bh->block_full_size; - int bs = bh->block_size; - //printk("Received a compress packet. block_size %d, block_full_size %d, max_size %d\n\n", bh->block_size, bh->block_full_size, 1024*1024); - - u8 *lz4_buffer = malloc(1024*1024); - memset(lz4_buffer, 0, 1024*1024); - - int len = LZ4_decompress_safe((char*)&usb_read_buff[32], (char*)lz4_buffer, bs, 1024*1024); - if (len <= 0) - { - printk("Error decomp, len is %d", len); - break; - } - if (len != bfs) - { - printk("Error decomp size %d != bfs %d\n", len, bfs); - break; - } //else printk("LZ4 decompress done (%db)\n", len); - - - int align_val = 32; - // Push back 32b align buffer - if(*buf32_s && len < (1024*1024) - *buf32_s) - { - //printk("Push back 32b align buffer\n"); - memcpy(&lz4_buffer[len], &buf32[0], *buf32_s); - len += *buf32_s; - *buf32_s = 0; - } - - // Save 32b align buffer - if (len % align_val) - { - //printk("Save 32b align buffer\n"); - *buf32_s = len - ((len / align_val) * align_val); - memcpy(&buf32[0], &lz4_buffer[len - *buf32_s], *buf32_s); - len -= *buf32_s; - } - - if (len % align_val) - { - printk("Buffer is not 32b aligned\n"); - break; - } - - // Write - bytesWrite = 0; - if (f_write(&fp, lz4_buffer, len, &bytesWrite) != FR_OK) - { - printk("Failed to write tmp_buffer\n"); - break; - } - if (!(bytesWrite > 0)) - { - printk("ERROR bytesWrite = 0\n"); - break; - } - *bytesCount += bytesWrite; - - free(lz4_buffer); - - bytesWrite = 0; - if (lz4compress && *bytesCount + *buf32_s > *bytesTotal && *buf32_s && f_write_buffer(&fp, buf32, *buf32_s > 32 ? 64 : 32, &bytesWrite) != FR_OK) - { - printk("Failed to write tmp_buffer\n"); - break; - } - *bytesCount += bytesWrite; - - - } - else - { - // Write (uncompressed bin) - bytesWrite = 0; - if (f_write(&fp, &usb_read_buff[32], bh->block_size, &bytesWrite) != FR_OK) - { - printk("Failed to write tmp_buffer\n"); - break; - } - if (!(bytesWrite > 0)) - { - printk("ERROR bytesWrite = 0\n"); - break; - } - *bytesCount += bytesWrite; - } - - int pct = (u64)(*bytesCount) * 100 / *bytesTotal; - if (pct != *pre_pct || *bytesCount >= *bytesTotal) - { - printk("\rDownloading %s - %d%% (%d MB) ", path, pct, *bytesCount / 1024 / 1024 ); - *pre_pct = pct; - } - - } - else - { - printk("Failed to receive file at off. %u \n", *bytesCount); - break; - } - */ - } - printk("\nBytes received. %u (%u seconds)\n", *bytesCount, (get_tmr_s() - *begin_time)); - f_close(&fp); - free(bytesCount); free(bytesTotal); free(begin_time); - free(path); free(buf32); free(buf32_s); free(pre_pct); - } - else - { - printk("Failed to open file. Err %d\n", res); - } -} - -void on_PushPayloadCommand() -{ - printk("Received a push payload command\n"); - video_clear_line(); - UC_EXEC* uc = (UC_EXEC*)usb_read_buff; - - if (uc->command != PUSH_PAYLOAD) - { - printk("Wrong PUSH_PAYLOAD command\n"); - video_clear_line(); - return; - } - - void *buf = (void *)RCM_PAYLOAD_ADDR; - u32 size = uc->bin_size; - - u32 bytesCount = 0; - printk("Preparing to receive payload, size = %u\n", size); - video_clear_line(); - while (bytesCount < size) - { - u32 bytesTransferred = 0; - if (!recv_bin_packet(&bytesTransferred)) - { - printk("Failed to receive file at off. %u \n", bytesCount); - break; - } - - memcpy(buf + bytesCount, &usb_read_buff[sizeof(UC_BlockHeader)], bytesTransferred); - bytesCount += bytesTransferred; - } - - if (bytesCount != size) - return; - - /* - uint32_t mrt_time = 2; - uint8_t reg_val = mrt_time - 2; - //bit 3..5 is the value we want to set - reg_val &= 0x7; - reg_val <<= 3; - reg_val |= 0x40; //always set normally - max77620_send_byte(MAX77620_REG_ONOFFCNFG1, reg_val); - */ - printk("Payload received and copied in RAM\n"); - video_clear_line(); - deinitialize_storages(); - msleep(200); - //mc_disable_ahb_redirect(); - - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); - //reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); - - //printk("Launch payload\n"); - display_end(); - - void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; - (*ext_payload_ptr)(); - - printk("Failed to launch payload\n"); - clock_halt_bpmp(); - return; -} - -void on_RebootRCMCommand() -{ - deinitialize_storages(); - mc_disable_ahb_redirect(); - display_end(); - - bool confirm = true; - send_response((const void*)&confirm, sizeof(bool)); // Notify caller - msleep(10); - - // Reboot to RCM - PMC(APBDEV_PMC_SCRATCH0) = (1 << 1); - PMC(0x0) |= PMC_CNTRL_MAIN_RST; - - while (true) - clock_halt_bpmp(); -} - - - -bool get_autoRCM_state(bool *state) -{ - if(!initialize_mount(NULL, 1)) - { - printk("Failed to mount EMMC BOOT0\n"); - return false; - } - - bool bct_state[4]; - bool autoRcmOn[4] = {false, false, false, false}; - sdmmc_storage_t* currStor = get_storage_for_index(1); - for (int i = 0; i < 4; i++) - { - u8 buff[0x200]; - memset(buff, 0, 0x200); - if (!sdmmc_storage_read(currStor, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) - { - printk("Error reading BCT %d from BOOT0.\n", i); - deinitialize_storage(1); - return false; - } - - if (buff[0x10] == 0xF7) bct_state[i] = true; - else bct_state[i] = false; - } - - if (!memcmp(autoRcmOn, bct_state, 4)) - *state = true; - else - *state = false; - - deinitialize_storage(1); - return true; -} - -bool set_autoRCM_state(bool autoRCM) -{ - if(!initialize_mount(NULL, 1)) - { - printk("Failed to mount EMMC BOOT0\n"); - return false; - } - sdmmc_storage_t* currStor = get_storage_for_index(1); - for (int i = 0; i < 4; i++) - { - u8 buff[0x200]; - memset(buff, 0, 0x200); - if (!sdmmc_storage_read(currStor, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) - { - printk("Error reading BCT %d from BOOT0.\n", i); - deinitialize_storage(1); - return false; - } - if (!autoRCM) - buff[0x10] = 0xF7; - else - { - u8 randomXor = 0; - do randomXor = (unsigned)get_tmr_ms() & 0xFF; - while (!randomXor); - buff[0x10] ^= randomXor; - } - if (!sdmmc_storage_write(currStor, (0x200 + (0x4000 * i)) / 0x200, 1, &buff[0])) - { - printk("Error writing BCT %d from BOOT0.\n", i); - deinitialize_storage(1); - return false; - } - } - deinitialize_storage(1); - return true; -} - -void on_setAutoRcmCommand(bool state) -{ - bool res = set_autoRCM_state(state); - send_response((const void*)&res, sizeof(bool)); // Notify caller -} - -void on_getDeviceInfoCommand(FATFS *fs) -{ - // Init a device info struct - UC_DeviceInfo di; - di.signature = DEVINFO; - - // AutoRCM - get_autoRCM_state(&di.autoRCM); - - // Burnt fuses - di.burnt_fuses = 0; - for (u32 i = 0; i < 32; i++) - { - if ((fuse_read_odm(7) >> i) & 1) - di.burnt_fuses++; - } - - // Battery - int value = 0; - i2c_recv_buf_small((u8 *)&value, 2, I2C_1, 0x36, 0x06); - di.battery_capacity = value >> 8; - - // FS info - if (fs == NULL || fs->fs_type == 0) - { - di.sdmmc_initialized = false; - di.cfw_sxos = false; - di.cfw_ams = false; - di.cbl_hekate = false; - } - else - { - di.sdmmc_initialized = true; - di.emmc_fs_type = fs->fs_type; - di.emmc_fs_cl_size = fs->csize; - di.emmc_fs_last_cl = fs->n_fatent - 2; - FATFS *ffs; - f_getfree("", &di.emmc_fs_free_cl, &ffs); - FILINFO fno; - di.cfw_sxos = (f_stat("boot.dat", &fno) == FR_OK); - di.cbl_hekate = (f_stat("bootloader/hekate_ipl.ini", &fno) == FR_OK); - di.cfw_ams = (f_stat("BCT.ini", &fno) == FR_OK) - || (f_stat("atmosphere/BCT.ini", &fno) == FR_OK) - || (f_stat("atmosphere/config/BCT.ini", &fno) == FR_OK); - - /* - * ToDo: - * - emunand detection - * - fw detection (sys + emu) - * - get Nintendo device ID - * - check for ipatched switch - */ - - } - - - u32 bytes; - rcm_usb_device_write_ep1_in_sync((u8*)&di, sizeof(UC_DeviceInfo), &bytes); -} - -int main(void) -{ - - u32* lfb_base; - - config_hw(); + u32 start_tmr = get_tmr_ms(); + config_hw(); // Do initial HW configuration. This is compatible with consecutive reruns without a reset. + bpmp_mmu_disable(); // Disable MMU to get RCM USB access. We don't neeed mmu for Ariane. + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); // Pivot the stack so we have enough space. - pivot_stack(IPL_STACK_TOP); + pivot_stack(IPL_STACK_TOP); - //Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. - heap_init(IPL_HEAP_START); - //heap_init(0x90020000); + // Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between. + heap_init(IPL_HEAP_START); + + // Hekate default conf + set_default_configuration(); // Train DRAM and switch to max frequency. - //minerva_init(); + minerva_init(); + minerva_change_freq(FREQ_1600); + + if(!sd_mount()) + gfx_printf("FAILED TO MOUNT SD !!!\n"); - display_enable_backlight(false); display_init(); + u32 *fb = display_init_framebuffer_pitch(); + gfx_init_ctxt(fb, 720, 1280, 720); + gfx_con_init(); - // Set up the display, and register it as a printk provider. - lfb_base = display_init_framebuffer(); - video_init(lfb_base); - - //Init the CBFS memory store in case we are booting coreboot - cbmem_initialize_empty(); - mc_enable_ahb_redirect(); - /* Turn on the backlight after initializing the lfb */ - /* to avoid flickering. */ - display_enable_backlight(true); + u8 *BOOTLOGO = (void *)malloc(0x30000); + blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO); + gfx_clear_color((u32)266270); - if (!rcm_usb_device_ready()) //somehow usb isn't initialized - printk("ERROR RCM USB not initialized, press the power button to turn off the system.\n"); + u32 logo_pos_x = 331; + u32 logo_pos_y = 440; + gfx_set_rect_rgb(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, logo_pos_x, logo_pos_y); - //u8 *holdingBuffer = (void*)malloc(USB_BUFFER_LENGTH*2); - //usbBuffer = (void*)ALIGN_UP((u32)&holdingBuffer[0], USB_BUFFER_LENGTH); - printk("ARIANE\n"); - - FATFS fs; - memset(&fs, 0, sizeof(FATFS)); - if(!initialize_mount(&fs, 0)) + //gfx_rect(X_BOOTLOGO + 200, 3, logo_pos_x - 100, logo_pos_y - 100, 1472191); + //gfx_rect(X_BOOTLOGO + 200, 3, logo_pos_x - 100, logo_pos_y + 100 + Y_BOOTLOGO, 1472191); + //gfx_rect(3, Y_BOOTLOGO + 200, logo_pos_x - 100, logo_pos_y - 100, 1472191); + //gfx_rect(3, Y_BOOTLOGO + 203, logo_pos_x + 100 + X_BOOTLOGO, logo_pos_y - 100, 1472191); + + display_backlight_pwm_init(); + h_cfg.backlight = 100; + display_backlight_brightness(h_cfg.backlight, 500); + + gfx_con_setpos(400, 700); + gfx_con_setcol(0xFF2B3D8E, 266270, 266270); + gfx_printf(" v0.1 by eliboa. credits: CTCaer, naehrwert, rajkosto\n"); + + gfx_con_setpos(10, 0); + gfx_printf("Hold power button to power off"); + + //gfx_con.mute = 1; + + if(b_cfg.extra_cfg & EXTRA_CFG_NYX_BIS) { - printk("Failed to initialise SD Card\n"); - memset(&fs, 0, sizeof(FATFS)); - } + //PMC(0x50) = (1 << 1); + gfx_printf("EXTRA_CFG_NYX_BIS\n"); + gfx_printf("h_cfg.sept_run = %s\n", !h_cfg.sept_run ? "false" : "true"); + hos_set_keys(FORBID_SEPT_REBOOT); + b_cfg.extra_cfg = 0; + //reboot_to_rcm(); + //bpmp_halt(); + //goto end; + } - // AutoRCM - bool autoRCM; - if (get_autoRCM_state(&autoRCM)) - printk("autoRCM state : %s\n", autoRCM ? "ON" : "OFF"); - - // Fuses - u32 burntFuses = 0; - for (u32 i = 0; i < 32; i++) + if (!rcm_usb_device_ready()) { - if ((fuse_read_odm(7) >> i) & 1) - burntFuses++; + gfx_printf("ERROR RCM USB not initialized\n"); + goto end; } - printk("Burnt Fuses : %u\n", burntFuses); + else usb_ready = true; - // Battery - int value = 0; - i2c_recv_buf_small((u8 *)&value, 2, I2C_1, 0x36, 0x06); - printk("Battery: %3d%\n", value >> 8); + set_deviceinfo(); - static const char READY_NOTICE[] = "READY.\n"; - unsigned int bytesTransferred = 0; + gfx_printf("%kARIANE loaded in %d ms%k\n\n", 0xFFFFFF00, get_tmr_ms() - start_tmr, 0xFFFFFFFF); + + free(BOOTLOGO); while(1) { if (btn_read() == BTN_POWER) - { - printk("EXIT\n"); - goto progend; - } - - /* - * ToDo - * -> Detect USB unplug - */ - - // Dispatcher - switch (usb_command_read()) - { - case GET_STATUS : - rcm_ready_notice(); - break; - case WRITE_SD_FILE : - on_WriteSDFileCommand(); - break; - case PUSH_PAYLOAD : - on_PushPayloadCommand(); - break; - case REBOOT_RCM : - on_RebootRCMCommand(); - break; - case GET_DEVICE_INFO: - on_getDeviceInfoCommand(&fs); - break; - case SET_AUTORCM_ON: - on_setAutoRcmCommand(true); - break; - case SET_AUTORCM_OFF: - on_setAutoRcmCommand(false); - break; - } + goto end; + + // Handle USB commands + UC_CommandType command = usb_command_read(); + if (command != NONE) + command_dispatcher(command); } - -progend_user: - printk("Press POWER button to exit\n"); - while(1) { if (btn_read() == BTN_POWER) goto progend;} -progend: - // Tell the PMIC to turn everything off - shutdown_using_pmic(); - - /* Do nothing for now */ - return 0; +end: + bpmp_halt(); + return; } diff --git a/ariane/src/minerva_tc/LICENSE b/ariane/src/minerva_tc/LICENSE deleted file mode 100644 index d159169..0000000 --- a/ariane/src/minerva_tc/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/ariane/src/minerva_tc/README.md b/ariane/src/minerva_tc/README.md deleted file mode 100644 index 9161c06..0000000 --- a/ariane/src/minerva_tc/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Minerva Training Cell - -![Image of Minerva](https://ctcaer.com/wii/switch/minerva.png) - - -### Custom Nvidia Tegra X1 DRAM trainer. - -Devices: **Nvidia Shield Android TV**, **Nintendo Switch**, **Nvidia Jetson TX1**, **Nvidia Drive CX & PX**, **Google Pixel C** and **various cars**. - -RAM chip type support: **DDR2**, **DDR3**, **LPDDR3** and **LPDDR4**. - -Other: Supports Periodic training and up to 2133MHz frequencies. - - -A working example can be found [Here](https://github.com/CTCaer/hekate/tree/master/modules/hekate_libsys_minerva). - - - -``` -Minerva Training Cell (C) 2018 CTCaer. - -/* Pain... And suffering. */ -``` diff --git a/ariane/src/minerva_tc/mtc/mtc.c b/ariane/src/minerva_tc/mtc/mtc.c deleted file mode 100644 index ee51e4e..0000000 --- a/ariane/src/minerva_tc/mtc/mtc.c +++ /dev/null @@ -1,4018 +0,0 @@ -/* - * Minerva Training Cell - * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. - * - * Copyright (c) 2018 CTCaer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include "mtc.h" -#include "mtc_mc_emc_regs.h" -#include "types.h" - -#define EPRINTF(...) -#define EPRINTFARGS(...) - -bool emc_2X_clk_src_is_pllmb; -bool fsp_for_src_freq; -bool train_ram_patterns; - -/* - * REF: PLL Input reference (OSC_FREQ). - * DIVN: PLL feedback divider. - * DIVM: PLL input divider. - * DIVP: PLL post divider. - * PLL_OUT = (REF / DIVM) * DIVN / DIVP - * - * DIVP | DIVP - * Encoded | Real - * ---------------------- - * 0 | 1 (DIVP off) - * 1 | 2 - * 2 | 3 - * 3 | 4 - * 4 | 5 - * 5 | 6 - * 6 | 8 - * 7 | 10 - * 8 | 12 - * 9 | 16 - * 10 | 12 - * 11 | 16 - * 12 | 20 - * 13 | 24 - * 14 | 32 - */ -static pllm_clk_config_t pllm_clk_config_table[] = -{ - // pll_osc_in, pll_out, pll_feedback_div, pll_input_div, pll_post_div. - {38400, 297600, 93, 4, 2}, // ((38400 / 4) * 93) / 3 - {38400, 400000, 125, 4, 2}, // ((38400 / 4) * 125) / 3 - {38400, 408000, 85, 4, 1}, // ((38400 / 4) * 85) / 2 - {38400, 532800, 111, 4, 1}, // ((38400 / 4) * 111) / 2 - {38400, 665600, 104, 3, 1}, // ((38400 / 3) * 104) / 2 - {38400, 800000, 125, 3, 1}, // ((38400 / 3) * 125) / 2 - {38400, 931200, 97, 4, 0}, // (38400 / 4) * 97 - {38400, 1065600, 111, 4, 0}, // (38400 / 4) * 111 - {38400, 1200000, 125, 4, 0}, // (38400 / 4) * 125 - {38400, 1331200, 104, 3, 0}, // (38400 / 3) * 104 - {38400, 1459200, 76, 2, 0}, // (38400 / 2) * 76 - {38400, 1600000, 125, 3, 0}, // (38400 / 3) * 125 - {38400, 1862400, 97, 2, 0}, // (38400 / 2) * 97 - {38400, 2131200, 111, 2, 0}, // (38400 / 2) * 111 - {0, 0, 0, 0, 0} -}; - -static const u32 burst_regs_emc_addr_table[221] = { - EMC_RC, - EMC_RFC, - EMC_RFCPB, - EMC_REFCTRL2, - EMC_RFC_SLR, - EMC_RAS, - EMC_RP, - EMC_R2W, - EMC_W2R, - EMC_R2P, - EMC_W2P, - EMC_R2R, - EMC_TPPD, - EMC_CCDMW, - EMC_RD_RCD, - EMC_WR_RCD, - EMC_RRD, - EMC_REXT, - EMC_WEXT, - EMC_WDV_CHK, - EMC_WDV, - EMC_WSV, - EMC_WEV, - EMC_WDV_MASK, - EMC_WS_DURATION, - EMC_WE_DURATION, - EMC_QUSE, - EMC_QUSE_WIDTH, - EMC_IBDLY, - EMC_OBDLY, - EMC_EINPUT, - EMC_MRW6, - EMC_EINPUT_DURATION, - EMC_PUTERM_EXTRA, - EMC_PUTERM_WIDTH, - EMC_QRST, - EMC_QSAFE, - EMC_RDV, - EMC_RDV_MASK, - EMC_RDV_EARLY, - EMC_RDV_EARLY_MASK, - EMC_REFRESH, - EMC_BURST_REFRESH_NUM, - EMC_PRE_REFRESH_REQ_CNT, - EMC_PDEX2WR, - EMC_PDEX2RD, - EMC_PCHG2PDEN, - EMC_ACT2PDEN, - EMC_AR2PDEN, - EMC_RW2PDEN, - EMC_CKE2PDEN, - EMC_PDEX2CKE, - EMC_PDEX2MRR, - EMC_TXSR, - EMC_TXSRDLL, - EMC_TCKE, - EMC_TCKESR, - EMC_TPD, - EMC_TFAW, - EMC_TRPAB, - EMC_TCLKSTABLE, - EMC_TCLKSTOP, - EMC_MRW7, - EMC_TREFBW, - EMC_ODT_WRITE, - EMC_FBIO_CFG5, - EMC_FBIO_CFG7, - EMC_CFG_DIG_DLL, - EMC_CFG_DIG_DLL_PERIOD, - EMC_PMACRO_IB_RXRT, - EMC_CFG_PIPE_1, - EMC_CFG_PIPE_2, - EMC_PMACRO_QUSE_DDLL_RANK0_4, - EMC_PMACRO_QUSE_DDLL_RANK0_5, - EMC_PMACRO_QUSE_DDLL_RANK1_4, - EMC_PMACRO_QUSE_DDLL_RANK1_5, - EMC_MRW8, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4, - EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5, - EMC_PMACRO_DDLL_LONG_CMD_0, - EMC_PMACRO_DDLL_LONG_CMD_1, - EMC_PMACRO_DDLL_LONG_CMD_2, - EMC_PMACRO_DDLL_LONG_CMD_3, - EMC_PMACRO_DDLL_LONG_CMD_4, - EMC_PMACRO_DDLL_SHORT_CMD_0, - EMC_PMACRO_DDLL_SHORT_CMD_1, - EMC_PMACRO_DDLL_SHORT_CMD_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3, - EMC_TXDSRVTTGEN, - EMC_FDPD_CTRL_DQ, - EMC_FDPD_CTRL_CMD, - EMC_FBIO_SPARE, - EMC_ZCAL_INTERVAL, - EMC_ZCAL_WAIT_CNT, - EMC_MRS_WAIT_CNT, - EMC_MRS_WAIT_CNT2, - EMC_AUTO_CAL_CHANNEL, - EMC_DLL_CFG_0, - EMC_DLL_CFG_1, - EMC_PMACRO_AUTOCAL_CFG_COMMON, - EMC_PMACRO_ZCTRL, - EMC_CFG, - EMC_CFG_PIPE, - EMC_DYN_SELF_REF_CONTROL, - EMC_QPOP, - EMC_DQS_BRLSHFT_0, - EMC_DQS_BRLSHFT_1, - EMC_CMD_BRLSHFT_2, - EMC_CMD_BRLSHFT_3, - EMC_PMACRO_PAD_CFG_CTRL, - EMC_PMACRO_DATA_PAD_RX_CTRL, - EMC_PMACRO_CMD_PAD_RX_CTRL, - EMC_PMACRO_DATA_RX_TERM_MODE, - EMC_PMACRO_CMD_RX_TERM_MODE, - EMC_PMACRO_CMD_PAD_TX_CTRL, - EMC_PMACRO_DATA_PAD_TX_CTRL, - EMC_PMACRO_COMMON_PAD_TX_CTRL, - EMC_PMACRO_VTTGEN_CTRL_0, - EMC_PMACRO_VTTGEN_CTRL_1, - EMC_PMACRO_VTTGEN_CTRL_2, - EMC_PMACRO_BRICK_CTRL_RFU1, - EMC_PMACRO_CMD_BRICK_CTRL_FDPD, - EMC_PMACRO_BRICK_CTRL_RFU2, - EMC_PMACRO_DATA_BRICK_CTRL_FDPD, - EMC_PMACRO_BG_BIAS_CTRL_0, - EMC_CFG_3, - EMC_PMACRO_TX_PWRD_0, - EMC_PMACRO_TX_PWRD_1, - EMC_PMACRO_TX_PWRD_2, - EMC_PMACRO_TX_PWRD_3, - EMC_PMACRO_TX_PWRD_4, - EMC_PMACRO_TX_PWRD_5, - EMC_CONFIG_SAMPLE_DELAY, - EMC_PMACRO_TX_SEL_CLK_SRC_0, - EMC_PMACRO_TX_SEL_CLK_SRC_1, - EMC_PMACRO_TX_SEL_CLK_SRC_2, - EMC_PMACRO_TX_SEL_CLK_SRC_3, - EMC_PMACRO_TX_SEL_CLK_SRC_4, - EMC_PMACRO_TX_SEL_CLK_SRC_5, - EMC_PMACRO_DDLL_BYPASS, - EMC_PMACRO_DDLL_PWRD_0, - EMC_PMACRO_DDLL_PWRD_1, - EMC_PMACRO_DDLL_PWRD_2, - EMC_PMACRO_CMD_CTRL_0, - EMC_PMACRO_CMD_CTRL_1, - EMC_PMACRO_CMD_CTRL_2, - EMC_TR_TIMING_0, - EMC_TR_DVFS, - EMC_TR_CTRL_1, - EMC_TR_RDV, - EMC_TR_QPOP, - EMC_TR_RDV_MASK, - EMC_MRW14, - EMC_TR_QSAFE, - EMC_TR_QRST, - EMC_TRAINING_CTRL, - EMC_TRAINING_SETTLE, - EMC_TRAINING_VREF_SETTLE, - EMC_TRAINING_CA_FINE_CTRL, - EMC_TRAINING_CA_CTRL_MISC, - EMC_TRAINING_CA_CTRL_MISC1, - EMC_TRAINING_CA_VREF_CTRL, - EMC_TRAINING_QUSE_CORS_CTRL, - EMC_TRAINING_QUSE_FINE_CTRL, - EMC_TRAINING_QUSE_CTRL_MISC, - EMC_TRAINING_QUSE_VREF_CTRL, - EMC_TRAINING_READ_FINE_CTRL, - EMC_TRAINING_READ_CTRL_MISC, - EMC_TRAINING_READ_VREF_CTRL, - EMC_TRAINING_WRITE_FINE_CTRL, - EMC_TRAINING_WRITE_CTRL_MISC, - EMC_TRAINING_WRITE_VREF_CTRL, - EMC_TRAINING_MPC, - EMC_MRW15 -}; - -static const u32 burst_reg_per_ch_emc01_addr_table[8] = { - EMC0_MRW10, - EMC1_MRW10, - EMC0_MRW11, - EMC1_MRW11, - EMC0_MRW12, - EMC1_MRW12, - EMC0_MRW13, - EMC1_MRW13 -}; - -static const u32 vref_perch_regs_emc01_addr_table[4] = { - EMC0_TRAINING_OPT_DQS_IB_VREF_RANK0, - EMC1_TRAINING_OPT_DQS_IB_VREF_RANK0, - EMC0_TRAINING_OPT_DQS_IB_VREF_RANK1, - EMC1_TRAINING_OPT_DQS_IB_VREF_RANK1 -}; - -static const u32 training_mod_regs_emc01_addr_table[20] = { - EMC0_TRAINING_RW_OFFSET_IB_BYTE0, - EMC1_TRAINING_RW_OFFSET_IB_BYTE0, - EMC0_TRAINING_RW_OFFSET_IB_BYTE1, - EMC1_TRAINING_RW_OFFSET_IB_BYTE1, - EMC0_TRAINING_RW_OFFSET_IB_BYTE2, - EMC1_TRAINING_RW_OFFSET_IB_BYTE2, - EMC0_TRAINING_RW_OFFSET_IB_BYTE3, - EMC1_TRAINING_RW_OFFSET_IB_BYTE3, - EMC0_TRAINING_RW_OFFSET_IB_MISC, - EMC1_TRAINING_RW_OFFSET_IB_MISC, - EMC0_TRAINING_RW_OFFSET_OB_BYTE0, - EMC1_TRAINING_RW_OFFSET_OB_BYTE0, - EMC0_TRAINING_RW_OFFSET_OB_BYTE1, - EMC1_TRAINING_RW_OFFSET_OB_BYTE1, - EMC0_TRAINING_RW_OFFSET_OB_BYTE2, - EMC1_TRAINING_RW_OFFSET_OB_BYTE2, - EMC0_TRAINING_RW_OFFSET_OB_BYTE3, - EMC1_TRAINING_RW_OFFSET_OB_BYTE3, - EMC0_TRAINING_RW_OFFSET_OB_MISC, - EMC1_TRAINING_RW_OFFSET_OB_MISC -}; - -static const u32 trim_regs_emc_addr_table[138] = { - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2, - EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1, - EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2, - EMC_PMACRO_IB_VREF_DQS_0, - EMC_PMACRO_IB_VREF_DQS_1, - EMC_PMACRO_IB_VREF_DQ_0, - EMC_PMACRO_IB_VREF_DQ_1, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1, - EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2, - EMC_PMACRO_QUSE_DDLL_RANK0_0, - EMC_PMACRO_QUSE_DDLL_RANK0_1, - EMC_PMACRO_QUSE_DDLL_RANK0_2, - EMC_PMACRO_QUSE_DDLL_RANK0_3, - EMC_PMACRO_QUSE_DDLL_RANK1_0, - EMC_PMACRO_QUSE_DDLL_RANK1_1, - EMC_PMACRO_QUSE_DDLL_RANK1_2, - EMC_PMACRO_QUSE_DDLL_RANK1_3 -}; - -static const u32 trim_perch_regs_emc01_addr_table[10] = { - EMC0_CMD_BRLSHFT_0, - EMC1_CMD_BRLSHFT_1, - EMC0_DATA_BRLSHFT_0, - EMC1_DATA_BRLSHFT_0, - EMC0_DATA_BRLSHFT_1, - EMC1_DATA_BRLSHFT_1, - EMC0_QUSE_BRLSHFT_0, - EMC1_QUSE_BRLSHFT_1, - EMC0_QUSE_BRLSHFT_2, - EMC1_QUSE_BRLSHFT_3 -}; - -static const u32 burst_mc_regs_addr_table[33] = { - MC_EMEM_ARB_CFG, - MC_EMEM_ARB_OUTSTANDING_REQ, - MC_EMEM_ARB_REFPB_HP_CTRL, - MC_EMEM_ARB_REFPB_BANK_CTRL, - MC_EMEM_ARB_TIMING_RCD, - MC_EMEM_ARB_TIMING_RP, - MC_EMEM_ARB_TIMING_RC, - MC_EMEM_ARB_TIMING_RAS, - MC_EMEM_ARB_TIMING_FAW, - MC_EMEM_ARB_TIMING_RRD, - MC_EMEM_ARB_TIMING_RAP2PRE, - MC_EMEM_ARB_TIMING_WAP2PRE, - MC_EMEM_ARB_TIMING_R2R, - MC_EMEM_ARB_TIMING_W2W, - MC_EMEM_ARB_TIMING_R2W, - MC_EMEM_ARB_TIMING_CCDMW, - MC_EMEM_ARB_TIMING_W2R, - MC_EMEM_ARB_TIMING_RFCPB, - MC_EMEM_ARB_DA_TURNS, - MC_EMEM_ARB_DA_COVERS, - MC_EMEM_ARB_MISC0, - MC_EMEM_ARB_MISC1, - MC_EMEM_ARB_MISC2, - MC_EMEM_ARB_RING1_THROTTLE, - MC_EMEM_ARB_DHYST_CTRL, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6, - MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 -}; - -static const u32 la_scale_regs_mc_addr_table[24] = { - MC_MLL_MPCORER_PTSA_RATE, - MC_FTOP_PTSA_RATE, - MC_PTSA_GRANT_DECREMENT, - MC_LATENCY_ALLOWANCE_XUSB_0, - MC_LATENCY_ALLOWANCE_XUSB_1, - MC_LATENCY_ALLOWANCE_TSEC_0, - MC_LATENCY_ALLOWANCE_SDMMCA_0, - MC_LATENCY_ALLOWANCE_SDMMCAA_0, - MC_LATENCY_ALLOWANCE_SDMMC_0, - MC_LATENCY_ALLOWANCE_SDMMCAB_0, - MC_LATENCY_ALLOWANCE_PPCS_0, - MC_LATENCY_ALLOWANCE_PPCS_1, - MC_LATENCY_ALLOWANCE_MPCORE_0, - MC_LATENCY_ALLOWANCE_HC_0, - MC_LATENCY_ALLOWANCE_HC_1, - MC_LATENCY_ALLOWANCE_AVPC_0, - MC_LATENCY_ALLOWANCE_GPU_0, - MC_LATENCY_ALLOWANCE_GPU2_0, - MC_LATENCY_ALLOWANCE_NVENC_0, - MC_LATENCY_ALLOWANCE_NVDEC_0, - MC_LATENCY_ALLOWANCE_VIC_0, - MC_LATENCY_ALLOWANCE_VI2_0, - MC_LATENCY_ALLOWANCE_ISP2_0, - MC_LATENCY_ALLOWANCE_ISP2_1 -}; - -static const u32 periodic_training_addr[10] = -{ - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2, - EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3, - EMC_DATA_BRLSHFT_0, - EMC_DATA_BRLSHFT_1 -}; - -static const u32 ram_pattern_dq_table[0x500] = { - /* DQ RAM Patterns Table 0 */ - 0x18181818, 0x61616161, 0x85858585, 0x14141414, 0x51515151, - 0x47474747, 0x1E1E1E1E, 0x79797979, 0xE5E5E5E5, 0x94949494, - 0x51515151, 0x46464646, 0x19191919, 0x67676767, 0x9C9C9C9C, - 0x71717171, 0xC5C5C5C5, 0x17171717, 0x5F5F5F5F, 0x7E7E7E7E, - 0xFBFBFBFB, 0xEDEDEDED, 0xB4B4B4B4, 0xD2D2D2D2, 0x48484848, - 0x21212121, 0x85858585, 0x16161616, 0x59595959, 0x66666666, - 0x9A9A9A9A, 0x69696969, 0xA4A4A4A4, 0x93939393, 0x4F4F4F4F, - 0x3F3F3F3F, 0xFCFCFCFC, 0xF3F3F3F3, 0xCDCDCDCD, 0x37373737, - 0xDCDCDCDC, 0x70707070, 0xC3C3C3C3, 0x0F0F0F0F, 0x3E3E3E3E, - 0xFAFAFAFA, 0xEBEBEBEB, 0xACACACAC, 0xB3B3B3B3, 0xCCCCCCCC, - 0x31313131, 0xC5C5C5C5, 0x15151515, 0x57575757, 0x5F5F5F5F, - 0x7F7F7F7F, 0xFDFDFDFD, 0xF4F4F4F4, 0xD0D0D0D0, 0x42424242, - 0x08080808, 0x23232323, 0x8F8F8F8F, 0x3F3F3F3F, 0x18181818, - 0x61616161, 0x85858585, 0x14141414, 0x51515151, 0x47474747, - 0x1E1E1E1E, 0x79797979, 0xE5E5E5E5, 0x94949494, 0x51515151, - 0x46464646, 0x19191919, 0x67676767, 0x9C9C9C9C, 0x71717171, - 0xC5C5C5C5, 0x17171717, 0x5F5F5F5F, 0x7E7E7E7E, 0xFBFBFBFB, - 0xEDEDEDED, 0xB4B4B4B4, 0xD2D2D2D2, 0x48484848, 0x21212121, - 0x85858585, 0x16161616, 0x59595959, 0x66666666, 0x9A9A9A9A, - 0x69696969, 0xA4A4A4A4, 0x93939393, 0x4F4F4F4F, 0x3F3F3F3F, - 0xFCFCFCFC, 0xF3F3F3F3, 0xCDCDCDCD, 0x37373737, 0xDCDCDCDC, - 0x70707070, 0xC3C3C3C3, 0x0F0F0F0F, 0x3E3E3E3E, 0xFAFAFAFA, - 0xEBEBEBEB, 0xACACACAC, 0xB3B3B3B3, 0xCCCCCCCC, 0x31313131, - 0xC5C5C5C5, 0x15151515, 0x57575757, 0x5F5F5F5F, 0x7F7F7F7F, - 0xFDFDFDFD, 0xF4F4F4F4, 0xD0D0D0D0, 0x42424242, 0x08080808, - 0x23232323, 0x8F8F8F8F, 0x3F3F3F3F, 0x06060606, 0x18181818, - 0x21212121, 0x05050505, 0x14141414, 0x11111111, 0x07070707, - 0x1E1E1E1E, 0x39393939, 0x25252525, 0x14141414, 0x11111111, - 0x06060606, 0x19191919, 0x27272727, 0x1C1C1C1C, 0x31313131, - 0x05050505, 0x17171717, 0x1F1F1F1F, 0x3E3E3E3E, 0x3B3B3B3B, - 0x2D2D2D2D, 0x34343434, 0x12121212, 0x08080808, 0x21212121, - 0x05050505, 0x16161616, 0x19191919, 0x26262626, 0x1A1A1A1A, - 0x29292929, 0x24242424, 0x13131313, 0x0F0F0F0F, 0x3F3F3F3F, - 0x3C3C3C3C, 0x33333333, 0x0D0D0D0D, 0x37373737, 0x1C1C1C1C, - 0x30303030, 0x03030303, 0x0F0F0F0F, 0x3E3E3E3E, 0x3A3A3A3A, - 0x2B2B2B2B, 0x2C2C2C2C, 0x33333333, 0x0C0C0C0C, 0x31313131, - 0x05050505, 0x15151515, 0x17171717, 0x1F1F1F1F, 0x3F3F3F3F, - 0x3D3D3D3D, 0x34343434, 0x10101010, 0x02020202, 0x08080808, - 0x23232323, 0x0F0F0F0F, 0x06060606, 0x18181818, 0x21212121, - 0x05050505, 0x14141414, 0x11111111, 0x07070707, 0x1E1E1E1E, - 0x39393939, 0x25252525, 0x14141414, 0x11111111, 0x06060606, - 0x19191919, 0x27272727, 0x1C1C1C1C, 0x31313131, 0x05050505, - 0x17171717, 0x1F1F1F1F, 0x3E3E3E3E, 0x3B3B3B3B, 0x2D2D2D2D, - 0x34343434, 0x12121212, 0x08080808, 0x21212121, 0x05050505, - 0x16161616, 0x19191919, 0x26262626, 0x1A1A1A1A, 0x29292929, - 0x24242424, 0x13131313, 0x0F0F0F0F, 0x3F3F3F3F, 0x3C3C3C3C, - 0x33333333, 0x0D0D0D0D, 0x37373737, 0x1C1C1C1C, 0x30303030, - 0x03030303, 0x0F0F0F0F, 0x3E3E3E3E, 0x3A3A3A3A, 0x2B2B2B2B, - 0x2C2C2C2C, 0x33333333, 0x0C0C0C0C, 0x31313131, 0x05050505, - 0x15151515, 0x17171717, 0x1F1F1F1F, 0x3F3F3F3F, 0x3D3D3D3D, - 0x34343434, 0x10101010, 0x02020202, 0x08080808, 0x23232323, - 0x0F0F0F0F, - - /* DQ RAM Patterns Table 1 */ - 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, - 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, - 0x00000000, - - /* DQ RAM Patterns Table 2 */ - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, - 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, - 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, - 0x3F3F3F3F, - - /* DQ RAM Patterns Table 3 */ - 0x80808080, 0x00000000, 0x80808080, 0x00000000, 0x80808080, - 0x00000000, 0x80808080, 0x40404040, 0x00000000, 0x40404040, - 0x00000000, 0x40404040, 0x00000000, 0x40404040, 0x20202020, - 0x00000000, 0x20202020, 0x00000000, 0x20202020, 0x00000000, - 0x20202020, 0x10101010, 0x00000000, 0x10101010, 0x00000000, - 0x10101010, 0x00000000, 0x10101010, 0x08080808, 0x00000000, - 0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x08080808, - 0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x04040404, - 0x00000000, 0x04040404, 0x02020202, 0x00000000, 0x02020202, - 0x00000000, 0x02020202, 0x00000000, 0x02020202, 0x01010101, - 0x00000000, 0x01010101, 0x00000000, 0x01010101, 0x00000000, - 0x01010101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80808080, - 0x00000000, 0x80808080, 0x00000000, 0x80808080, 0x00000000, - 0x80808080, 0x40404040, 0x00000000, 0x40404040, 0x00000000, - 0x40404040, 0x00000000, 0x40404040, 0x20202020, 0x00000000, - 0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x20202020, - 0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x10101010, - 0x00000000, 0x10101010, 0x08080808, 0x00000000, 0x08080808, - 0x00000000, 0x08080808, 0x00000000, 0x08080808, 0x04040404, - 0x00000000, 0x04040404, 0x00000000, 0x04040404, 0x00000000, - 0x04040404, 0x02020202, 0x00000000, 0x02020202, 0x00000000, - 0x02020202, 0x00000000, 0x02020202, 0x01010101, 0x00000000, - 0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x01010101, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20202020, - 0x00000000, 0x20202020, 0x00000000, 0x20202020, 0x00000000, - 0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x10101010, - 0x00000000, 0x10101010, 0x00000000, 0x10101010, 0x00000000, - 0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x08080808, - 0x00000000, 0x08080808, 0x00000000, 0x08080808, 0x00000000, - 0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x04040404, - 0x00000000, 0x04040404, 0x00000000, 0x04040404, 0x00000000, - 0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x02020202, - 0x00000000, 0x02020202, 0x00000000, 0x02020202, 0x00000000, - 0x02020202, 0x00000000, 0x02020202, 0x00000000, 0x01010101, - 0x00000000, 0x01010101, 0x00000000, 0x01010101, 0x00000000, - 0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x20202020, 0x00000000, - 0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x20202020, - 0x00000000, 0x20202020, 0x00000000, 0x10101010, 0x00000000, - 0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x10101010, - 0x00000000, 0x10101010, 0x00000000, 0x08080808, 0x00000000, - 0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x08080808, - 0x00000000, 0x08080808, 0x00000000, 0x04040404, 0x00000000, - 0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x04040404, - 0x00000000, 0x04040404, 0x00000000, 0x02020202, 0x00000000, - 0x02020202, 0x00000000, 0x02020202, 0x00000000, 0x02020202, - 0x00000000, 0x02020202, 0x00000000, 0x01010101, 0x00000000, - 0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x01010101, - 0x00000000, 0x01010101, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, - - /* DQ RAM Patterns Table 4 */ - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, - 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, - 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, - 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, - 0x33333333 -}; - -static const u32 ram_pattern_dmi_table[0x500] = { - /* DMI RAM Patterns Table 0 */ - 0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF, - 0x0, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF, - 0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0x0, 0x0, - 0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0x0, - 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0x0, - 0x0, 0xF, 0xF, 0x0, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, - 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0, - 0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF, - 0x0, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF, - 0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0x0, 0x0, - 0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0x0, - 0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0x0, - 0x0, 0xF, 0xF, 0x0, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, - 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* DMI RAM Patterns Table 1 */ - 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0xF, 0x0, - 0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF, - 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0, - 0xF, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0, - 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, - 0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, - 0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0, - 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0xF, 0x0, - 0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF, - 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0, - 0xF, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0, - 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, - 0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, - 0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* DMI RAM Patterns Table 2 */ - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* DMI RAM Patterns Table 3 */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* DMI RAM Patterns Table 4 */ - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3, - 0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3 -}; - -static void _usleep(u32 microseconds) -{ - u32 start = TMR(0x10); - while ((u32)(TMR(0x10) - start) <= microseconds) - ; -} - -static s32 _fceil(float var) -{ - s32 result = (s32)(var + 0.5f); - - return result; -} - -static u32 _actual_osc_clocks(u32 in) -{ - u32 actual_clock; - - actual_clock = 16 * in; - if (in > 63) - { - actual_clock = 2048; - if (in > 127) - { - if (in >= 192) - actual_clock = 8192; - else - actual_clock = 4096; - } - } - - return actual_clock; -} - -static void _ccfifo_write(u32 addr, u32 data_val, u32 delay) //addr and delay are u16 -{ - EMC(EMC_CCFIFO_DATA) = data_val; - EMC(EMC_CCFIFO_ADDR) = (addr & 0xffff) | ((delay & 0x7FFF) << 16) | (1 << 31); -} - -static bool _wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel) -{ - bool err = true; - - for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) - { - if (emc_channel) - { - if (emc_channel != 1) - goto done; - if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state) - { - err = false; - break; - } - } - else - { - if (((EMC(reg_offset) & bit_mask) != 0) == updated_state) - { - err = false; - break; - } - } - _usleep(1); - } -done: - return err; -} - -static void _request_mmr_data(u32 data, bool dual_channel) -{ - EMC(EMC_MRR) = data; - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CH0); - if (dual_channel) - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CH1); -} - -static u32 _start_periodic_compensation() -{ - EMC(EMC_MPC) = 0x4B; - - return EMC(EMC_MPC); -} - -static bool _timing_update(s32 dual_channel) -{ - bool err = 0; - - EMC(EMC_TIMING_CONTROL) = 1; - err = _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CH0); - if (dual_channel) - err |= _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CH1); - - return err; -} - -static s32 _get_dram_temperature() -{ - s32 mr4_0 = 0; - s32 mr4_1 = 0; - - bool channel1_enabled = (EMC(EMC_FBIO_CFG7) >> 2) & 1; - u32 emc_cfg_o = EMC(EMC_CFG); - - _wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, false, EMC_CH0); - - if (emc_cfg_o & 0x20000000) - { - EMC(EMC_CFG) = emc_cfg_o & 0xDFFFFFFF; - _timing_update(channel1_enabled); - } - - _request_mmr_data(0x80040000, EMC_CH0); - mr4_0 = EMC(EMC_MRR) & 0xFFFF; - - if (mr4_0 < 0xF001) - mr4_0 &= 0x7; - else - { - mr4_0 = -1; - goto out; - } - - if (channel1_enabled) - { - _request_mmr_data(0x40040000, channel1_enabled); - mr4_1 = EMC(EMC_MRR); - - if (mr4_1 < 0xF001) - mr4_1 &= 0x7; - else - goto out; - - if (mr4_1 > mr4_0) - mr4_0 = mr4_1; - } - -out: - if (emc_cfg_o & 0x20000000) - { - EMC(EMC_CFG) = emc_cfg_o; - _timing_update(channel1_enabled); - } - - return mr4_0; -} - -static u32 _pllm_clk_base_cfg(s32 rate_KHz, u32 clk_src_emc, s32 emc_2X_clk_src_is_PLLMB) -{ - u32 dividers = 0; - s32 i = 0; - s32 pll_ref = 38400; // Only 38.4MHz crystal is supported for T210. - - pllm_clk_config_t *pllm_clk_config; - - for (i = 0; pllm_clk_config_table[i].pll_osc_in; i++) - { - if (pllm_clk_config_table[i].pll_osc_in == pll_ref && pllm_clk_config_table[i].pll_out == rate_KHz) - break; - } - - pllm_clk_config = &pllm_clk_config_table[i]; - if (pllm_clk_config->pll_osc_in) - { - dividers = pllm_clk_config->pll_input_div | (pllm_clk_config->pll_feedback_div << 8) | ((pllm_clk_config->pll_post_div & 0x1F) << 20); - if (emc_2X_clk_src_is_PLLMB) - { - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) = dividers; - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) |= PLLM_ENABLE; - if ((clk_src_emc >> EMC_2X_CLK_SRC_SHIFT) == PLLM_UD) - clk_src_emc = (clk_src_emc & 0x1FFFFFFF) | (PLLMB_UD << EMC_2X_CLK_SRC_SHIFT); - else if (!(clk_src_emc >> EMC_2X_CLK_SRC_SHIFT)) - clk_src_emc |= (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT); - while (!(CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) & PLLM_LOCK)) - ; - } - else - { - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = dividers; - CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) |= 0x10u; // PLLM_EN_LCKDET. - CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) |= PLLM_ENABLE; - if ((clk_src_emc >> EMC_2X_CLK_SRC_SHIFT) == PLLM_UD) - clk_src_emc = (clk_src_emc & 0x1FFFFFFF) | (PLLM_UD << EMC_2X_CLK_SRC_SHIFT); - while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & PLLM_LOCK)) - ; - } - } - return clk_src_emc; -} - -static void _change_dll_src(emc_table_t *mtc_table_entry, u32 clk_src_emc) -{ - u32 emc_2x_clk_src = clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - - u32 dll_setting = ((((mtc_table_entry->dll_clk_src & 0x1FFFFFFF) - | (emc_2x_clk_src << EMC_2X_CLK_SRC_SHIFT)) & 0xFFFFFF00) - | (clk_src_emc & 0xFF)) & 0xFFFFF3FF; - - if (emc_2x_clk_src == PLLMB_UD) - dll_setting |= 0x400; // PLLM_VCOB. - else if (emc_2x_clk_src != PLLM_UD) - dll_setting |= 0x800; // EMC_DLL_SWITCH_OUT. - - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = dll_setting; - - //OLD - u32 clk_enb_emc_dll = ((mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll & 1) << 14) | (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) & 0xFFFFBFFF); - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = clk_enb_emc_dll; - - //NEW - // _usleep(2); - // if (mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll) - // CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) |= 0x4000; - // else - // CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_CLR) |= 0x4000; - // _usleep(2); -} - -static u32 _digital_dll_prelock(emc_table_t *mtc_table_entry, u32 needs_tristate_training, u32 selected_clk_src_emc) -{ - s32 dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); - - EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFF824) | 0x3C8; - - _timing_update(dual_channel); - - while (EMC(EMC_CFG_DIG_DLL) & 1) - ; - if (dual_channel) - while (EMC_CH1(EMC_CFG_DIG_DLL) & 1) - ; - - EMC(EMC_DLL_CFG_0) = mtc_table_entry->burst_regs.emc_dll_cfg_0_idx; - EMC(EMC_DLL_CFG_1) = mtc_table_entry->burst_regs.emc_dll_cfg_1_idx; - - _change_dll_src(mtc_table_entry, selected_clk_src_emc); - - EMC(EMC_CFG_DIG_DLL) |= 1; - - _timing_update(dual_channel); - - while (!(EMC(EMC_CFG_DIG_DLL) & 1)) - ; - if (dual_channel) - while (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1)) - ; - - while ((((EMC(EMC_DIG_DLL_STATUS) >> 17) & 1) ^ 1) | (((EMC(EMC_DIG_DLL_STATUS) >> 15) & 1) ^ 1)) - ; - - if (needs_tristate_training) - { - EMC(EMC_DBG) |= 2u; - EMC(EMC_CFG_DIG_DLL) &= 0xFFFFFFFE; //Disable CFG_DLL_EN: [PMC] Enable digital DLL. - EMC(EMC_DBG) &= 0xFFFFFFFD; - while (EMC(EMC_CFG_DIG_DLL) & 1) - ; - if (dual_channel) - while (EMC_CH1(EMC_CFG_DIG_DLL) & 1) - ; - } - - return EMC(EMC_DIG_DLL_STATUS) & 0x7FF; -} - -static void _digital_dll_disable() -{ - bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); - - EMC(EMC_CFG_DIG_DLL) &= 0xFFFFFFFE; - - _timing_update(dual_channel); - - while (EMC(EMC_CFG_DIG_DLL) & 1) - ; - if (dual_channel) - { - while (EMC_CH1(EMC_CFG_DIG_DLL) & 1) - ; - } -} - -static void _digital_dll_enable(s32 channel1_enabled) -{ - EMC(EMC_CFG_DIG_DLL) |= 1; - - _timing_update(channel1_enabled); - - while (!(EMC(EMC_CFG_DIG_DLL) & 1)) - ; - if (channel1_enabled) - { - while (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1)) - ; - } -} - -static void _digital_dll_enable_rs(s32 channel1_enabled) -{ - EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x89; - - _timing_update(channel1_enabled); - - while (!(EMC(EMC_CFG_DIG_DLL) & 1)) - ; - if (channel1_enabled) - { - while (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1)) - ; - } -} - -static u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, float src_clock_period) -{ - u32 pmacro_cmd_pad; - u32 pmacro_rfu1; - u32 pmacro_cfg5; - u32 pmacro_common_tx; - u32 pmacro_dq_pad; - - float src_clk_per_pc = (100.0f / src_clock_period) + 1.0f; - - if (flip_backward) - { - pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; - } - else - { - pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = (dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x101) | src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; - } - u32 pmacro_cmd_pad_drvforceon = pmacro_cmd_pad | 0x4000000; - - u32 ramp_down_wait = (u32)(float)(src_clock_period * 12.0f); - - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon, 0); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 | 0x100, 12); - - if (src_clock_period >= 1.0f) // Dvfs high speed threshold. - { - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, (u32)(float)(src_clk_per_pc + 19.0f)); - ramp_down_wait = (u32)(float)((float)ramp_down_wait + (100.0f + (src_clock_period * 20.0f))); - } - else - { - ramp_down_wait += 100; - if (src_clock_period >= 0.416666667) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)src_clk_per_pc); - else - { - pmacro_dq_pad = (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200; - pmacro_cmd_pad_drvforceon = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4010200; - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon, (u32)src_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, 0); - } - ramp_down_wait += 200; - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)src_clk_per_pc); - if (src_clock_period >= 0.416666667) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, (u32)src_clk_per_pc); - else - { - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon & 0xFEFEFDFD, (u32)src_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad & 0xFEFEFDFD, 0); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, 0); - } - } - if (src_clock_period >= 1.66666667) // Dvfs mid speed threshold. - { - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFF0, (u32)src_clk_per_pc); - } - else - { - ramp_down_wait += 400; - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFFA, (u32)src_clk_per_pc); - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xFFFFFFF0, (u32)src_clk_per_pc); - _ccfifo_write(0, 0, (u32)src_clk_per_pc); - } - - return ramp_down_wait; -} - -static u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u8 needs_training, float dst_clock_period) -{ - u32 pmacro_cmd_pad; - u32 pmacro_dq_pad; - u32 pmacro_rfu1; - u32 pmacro_cfg5; - u32 pmacro_common_tx; - u32 pmacro_cmd_pad_data; - u32 ramp_up_wait = 0; - - float dst_clk_per_pc = (100.0f / dst_clock_period) + 1.0f; - if (flip_backward) - { - pmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = src_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; - } - else if (needs_training & 3) - { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_ca_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_common_pad_tx_ctrl_idx; - } - else if (needs_training & 0xC) - { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_quse_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_common_pad_tx_ctrl_idx; - } - else if (needs_training & 0xF0) - { - pmacro_cmd_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->shadow_regs_rdwr_train.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_common_pad_tx_ctrl_idx; - } - else - { - pmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl_idx; - pmacro_dq_pad = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx; - pmacro_rfu1 = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1_idx; - pmacro_cfg5 = dst_emc_table_entry->burst_regs.emc_fbio_cfg5_idx; - pmacro_common_tx = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl_idx; - } - pmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4000000; - - if (dst_clock_period >= 1.66666667) // Dvfs mid speed threshold. - { - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx | 8, 0); - if (dst_clock_period >= 1.0) // Dvfs high speed threshold. - { - if (dst_clock_period >= 1.66666667) // Dvfs mid speed threshold. - { - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x600, 0); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, 12); - ramp_up_wait = (u32)((float)(dst_clock_period * 12.0f) + 0.0); - } - else - { - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x6000600, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(float)(dst_clk_per_pc + 9.0f)); - ramp_up_wait = (u32)(float)(100.0f + (float)(dst_clock_period * 10.0f)); - } - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5); - - return ramp_up_wait; - } - - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(float)(dst_clk_per_pc + 9.0f)); - ramp_up_wait = (u32)(float)((float)300 + (float)(100.0f + (float)(dst_clock_period * 10.0f))); - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5); - - return ramp_up_wait; - } - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xA, 0); - _ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xF, (u32)dst_clk_per_pc); - - if (dst_clock_period < 1.0) // Dvfs high speed threshold. - { - if (dst_clock_period >= 0.416666667) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)dst_clk_per_pc); - else - { - pmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFEFEFDFD) | 0x4010200; - pmacro_dq_pad = (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200; - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, 0); - } - - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)dst_clk_per_pc); - - if (dst_clock_period >= 0.416666667) // Iobrick dcc threshold. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, (u32)dst_clk_per_pc); - else - { - pmacro_cmd_pad_data |= 0x1010202u; - pmacro_dq_pad |= 0x1010202; - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, 0); - } - - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(float)(dst_clk_per_pc + 9.0f)); - ramp_up_wait = (u32)(float)((float)400 + (float)(100.0f + (float)(dst_clock_period * 10.0f))); - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5); - - return ramp_up_wait; - } - - // 1.0 > dst_clock_period < 1.66666667. - _ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x6000600, (u32)dst_clk_per_pc); - _ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, (u32)(float)(dst_clk_per_pc + 9.0f)); - - ramp_up_wait = (u32)(float)((float)100 + (float)(100.0f + (float)(dst_clock_period * 10.0f))); - _ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5); - - return ramp_up_wait; -} - -static u32 _minerva_update_clock_tree_delay(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, s32 dram_dev_num, s32 channel1_enabled, enum tree_update_mode_t update_type) -{ - s32 temp_ch0_0 = 0; - s32 temp_ch0_1 = 0; - s32 temp_ch1_0 = 0; - s32 temp_ch1_1 = 0; - - s32 dst_rate_mhz; - - u32 cval = 0; - s32 tdel0_0 = 0; - s32 tdel0_1 = 0; - s32 tdel1_0 = 0; - s32 tdel1_1 = 0; - s32 tmp_tdel0_0 = 0; - - temp_ch0_0 = 0x10624DD3; // div 1000 denominator - temp_ch0_1 = dst_emc_entry->rate_khz; - dst_rate_mhz = dst_emc_entry->rate_khz / 1000; - u32 upd_type_bits = 1 << update_type; - - u32 tval = 1000 * (1000 * _actual_osc_clocks(src_emc_entry->run_clocks) / (src_emc_entry->rate_khz / 1000)); - if (update_type <= PERIODIC_TRAINING_UPDATE) - { - temp_ch0_1 = 1 << update_type; - temp_ch0_0 = 0x5400; - if (upd_type_bits & 0x5400) - { - _request_mmr_data(0x80130000, channel1_enabled); // Dev0 MRR 19. - temp_ch0_0 = (EMC(EMC_MRR) & 0xFF) << 8; - temp_ch0_1 = EMC(EMC_MRR) & 0xFF00; - if (channel1_enabled) - { - temp_ch1_0 = (EMC_CH1(EMC_MRR) & 0xFF) << 8; - temp_ch1_1 = EMC_CH1(EMC_MRR) & 0xFF00; - } - - _request_mmr_data(0x80120000, channel1_enabled); // Dev0 MRR 18. - temp_ch0_0 |= EMC(EMC_MRR) & 0xFF; - temp_ch0_1 |= (EMC(EMC_MRR) & 0xFF00) >> 8; - if (channel1_enabled) - { - temp_ch1_0 |= EMC_CH1(EMC_MRR) & 0xFF; - temp_ch1_1 |= (EMC_CH1(EMC_MRR) & 0xFF00) >> 8; - } - } - } - - //u32 delay = (u64)((u64)_actual_osc_clocks(src_emc_entry->run_clocks) * 1000000) / (u64)(src_emc_entry->rate_khz * 2); - cval = tval / (2 * temp_ch0_0); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx += 100 * cval; - tdel0_0 = 0; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td0_0; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - tdel0_0 = 0; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td0_0; - break; - } - - tdel0_0 = dst_emc_entry->current_dram_clktree_c0d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / 100); - if (tdel0_0 < 0) - tdel0_0 = !tdel0_0; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel0_0 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx / 100; - -calc_td0_0: - cval = tval / (2 * temp_ch0_1); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td1_0; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td1_0; - break; - } - - tdel0_1 = dst_emc_entry->current_dram_clktree_c0d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / 100); - if (tdel0_1 < 0) - tdel0_1 = !tdel0_1; - if (tdel0_1 > tdel0_0) - tdel0_0 = tdel0_1; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel0_1 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx / 100; - -calc_td1_0: - if (channel1_enabled == 1) - { - cval = tval / (2 * temp_ch1_0); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td1_1; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_td1_1; - break; - } - - tdel1_0 = dst_emc_entry->current_dram_clktree_c1d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / 100); - if (tdel1_0 < 0) - tdel1_0 = !tdel1_0; - if (tdel1_0 > tdel0_0) - tdel0_0 = tdel1_0; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel1_0 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx / 100; - -calc_td1_1: - cval = tval / (2 * temp_ch1_1); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_dev2; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_dev2; - break; - } - - tdel1_1 = dst_emc_entry->current_dram_clktree_c1d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / 100); - if (tdel1_1 < 0) - tdel1_1 = !tdel1_1; - if (tdel1_1 > tdel0_0) - tdel0_0 = tdel1_1; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel1_1 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx / 100; - } - -calc_dev2: - if (dram_dev_num != TWO_RANK) - goto out; - - if (update_type <= PERIODIC_TRAINING_UPDATE && upd_type_bits & 0x5400) - { - _request_mmr_data(0x40130000, channel1_enabled); // Dev1 MRR 19. - temp_ch0_0 = (EMC(EMC_MRR) & 0xFF) << 8; - temp_ch0_1 = EMC(EMC_MRR) & 0xFF00; - if (channel1_enabled == 1) - { - temp_ch1_0 = (EMC_CH1(EMC_MRR) & 0xFF) << 8; - temp_ch1_1 = EMC_CH1(EMC_MRR) & 0xFF00; - } - - _request_mmr_data(0x40120000, channel1_enabled); // Dev1 MRR 18 - temp_ch0_0 |= EMC(EMC_MRR) & 0xFF; - temp_ch0_1 |= ((EMC(EMC_MRR) & 0xFF00) >> 8); - if (channel1_enabled == 1) - { - temp_ch1_0 |= EMC_CH1(EMC_MRR) & 0xFF; - temp_ch1_1 |= (EMC_CH1(EMC_MRR) & 0xFF00) >> 8; - } - - } - - cval = tval / (2 * temp_ch0_0); - switch (update_type ) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td0_1; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td0_1; - break; - } - - tmp_tdel0_0 = dst_emc_entry->current_dram_clktree_c0d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / 100); - if (tmp_tdel0_0 < 0) - tmp_tdel0_0 = !tmp_tdel0_0; - if (tmp_tdel0_0 > tdel0_0) - tdel0_0 = tmp_tdel0_0; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tmp_tdel0_0 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx / 100; - -calc_tmp_td0_1: - cval = tval / (2 * temp_ch0_1); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td1_0; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td1_0; - break; - } - - tdel0_1 = dst_emc_entry->current_dram_clktree_c0d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / 100); - if (tdel0_1 < 0) - tdel0_1 = !tdel0_1; - if (tdel0_1 > tdel0_0) - tdel0_0 = tdel0_1; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel0_1 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx / 100; - -calc_tmp_td1_0: - if (channel1_enabled == 1) - { - cval = tval / (2 * temp_ch1_0); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td1_1; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto calc_tmp_td1_1; - break; - } - - tdel1_0 = dst_emc_entry->current_dram_clktree_c1d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / 100); - if (tdel1_0 < 0) - tdel1_0 = !tdel1_0; - if (tdel1_0 > tdel0_0) - tdel0_0 = tdel1_0; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel1_0 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx / 100; - -calc_tmp_td1_1: - cval = tval / (2 * temp_ch1_1); - switch (update_type) - { - case DVFS_PT1: - case TRAINING_PT1: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx += 100 * cval; - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto out; - break; - case DVFS_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - break; - case TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / dst_emc_entry->ptfv_list.ptfv_write_samples_idx; - break; - case PERIODIC_TRAINING_UPDATE: - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = - (100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx) - / (dst_emc_entry->ptfv_list.ptfv_movavg_weight_idx + 1); - break; - default: - if (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800)) - goto out; - break; - } - - tdel1_1 = dst_emc_entry->current_dram_clktree_c1d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / 100); - if (tdel1_1 < 0) - tdel1_1 = !tdel1_1; - if (tdel1_1 > tdel0_0) - tdel0_0 = tdel1_1; - if (update_type == TRAINING_UPDATE || (dst_rate_mhz * tdel1_1 << 7) / 1000000 > dst_emc_entry->tree_margin) - dst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx / 100; - } - -out: - if (update_type == TRAINING_UPDATE) - { - dst_emc_entry->trained_dram_clktree_c0d0u0 = dst_emc_entry->current_dram_clktree_c0d0u0; - dst_emc_entry->trained_dram_clktree_c0d0u1 = dst_emc_entry->current_dram_clktree_c0d0u1; - dst_emc_entry->trained_dram_clktree_c0d1u0 = dst_emc_entry->current_dram_clktree_c0d1u0; - dst_emc_entry->trained_dram_clktree_c0d1u1 = dst_emc_entry->current_dram_clktree_c0d1u1; - dst_emc_entry->trained_dram_clktree_c1d0u0 = dst_emc_entry->current_dram_clktree_c1d0u0; - dst_emc_entry->trained_dram_clktree_c1d0u1 = dst_emc_entry->current_dram_clktree_c1d0u1; - dst_emc_entry->trained_dram_clktree_c1d1u0 = dst_emc_entry->current_dram_clktree_c1d1u0; - dst_emc_entry->trained_dram_clktree_c1d1u1 = dst_emc_entry->current_dram_clktree_c1d1u1; - } - - return (u32)tdel0_0; -} - -static u32 _minerva_periodic_compensation_handler(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, s32 dram_dev_num, s32 channel1_enabled, enum comp_seq_t seq_type) -{ - if (!dst_emc_entry->periodic_training) - return seq_type; - - u32 adel = 0; - u32 delay = 1000 * _actual_osc_clocks(src_emc_entry->run_clocks) / src_emc_entry->rate_khz + 2; - - if (seq_type == DVFS_SEQUENCE) - { - if (src_emc_entry->periodic_training && dst_emc_entry->ptfv_list.ptfv_config_ctrl_idx & 1) - { - u32 samples = dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx * samples; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx * samples; - } - else - { - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = 0; - - for (s32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_dvfs_samples_idx; i++) - { - _start_periodic_compensation(); - _usleep(delay); - _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_PT1); - } - } - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_UPDATE); - - return adel; - } - else if (seq_type == WRITE_TRAINING_SEQUENCE) - { - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0_idx = 0; - dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1_idx = 0; - - for (s32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_write_samples_idx; i++) - { - _start_periodic_compensation(); - _usleep(delay); - _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_PT1); - } - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_UPDATE); - - return adel; - } - else if (seq_type == PERIODIC_TRAINING_SEQUENCE) - { - _start_periodic_compensation(); - _usleep(delay); - adel = _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); - - return adel; - } - - return seq_type; -} - -#define STORE_TRIM_VAL(chan, rank, reg, byte) \ - ((mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank##rank##_##reg##_idx >> \ - EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE##byte##_SHIFT) & 0x7FF) \ - + \ - (((mtc_table_entry->trim_perch_regs.emc##chan##_data_brlshft_##rank##_idx >> \ - EMC_DATA_BRLSHFT_##rank##_RANK##rank##_BYTE##byte##_DATA_BRLSHFT_SHIFT) & 0x7) << 6) - -static u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_entry, u32 trim_emc_reg_addr) -{ - u32 trimmer = 0; - s32 tree_delta[4] = {0}; - s32 tree_delta_taps[4] = {0}; - s32 new_trim[] = { - // chan, rank, reg, byte. - STORE_TRIM_VAL(0, 0, 0, 0), - STORE_TRIM_VAL(0, 0, 0, 1), - STORE_TRIM_VAL(0, 0, 1, 2), - STORE_TRIM_VAL(0, 0, 1, 3), - - STORE_TRIM_VAL(1, 0, 2, 4), - STORE_TRIM_VAL(1, 0, 2, 5), - STORE_TRIM_VAL(1, 0, 3, 6), - STORE_TRIM_VAL(1, 0, 3, 7), - - STORE_TRIM_VAL(0, 1, 0, 0), - STORE_TRIM_VAL(0, 1, 0, 1), - STORE_TRIM_VAL(0, 1, 1, 2), - STORE_TRIM_VAL(0, 1, 1, 3), - - STORE_TRIM_VAL(1, 1, 2, 4), - STORE_TRIM_VAL(1, 1, 2, 5), - STORE_TRIM_VAL(1, 1, 3, 6), - STORE_TRIM_VAL(1, 1, 3, 7) - }; - - u32 dst_rate_mhz = mtc_table_entry->rate_khz / 1000; - - switch (trim_emc_reg_addr) - { - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3: - case EMC_DATA_BRLSHFT_0: - tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d0u0 - mtc_table_entry->trained_dram_clktree_c0d0u0) << 7; - tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d0u1 - mtc_table_entry->trained_dram_clktree_c0d0u1) << 7; - tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d0u0 - mtc_table_entry->trained_dram_clktree_c1d0u0) << 7; - tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d0u1 - mtc_table_entry->trained_dram_clktree_c1d0u1) << 7; - tree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000; - for (s32 i = 0; i < 4; i++) - { - if ((tree_delta_taps[i] > mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * mtc_table_entry->tree_margin))) - { - new_trim[i * 2] += tree_delta_taps[i]; - new_trim[i * 2 + 1] += tree_delta_taps[i]; - } - } - if (trim_emc_reg_addr == EMC_DATA_BRLSHFT_0) - { - for (s32 i = 0; i < 8; i++) - new_trim[i] /= 64; - } - else - { - for (s32 i = 0; i < 8; i++) - new_trim[i] %= 64; - } - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2: - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3: - case EMC_DATA_BRLSHFT_1: - tree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d1u0 - mtc_table_entry->trained_dram_clktree_c0d1u0) << 7; - tree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d1u1 - mtc_table_entry->trained_dram_clktree_c0d1u1) << 7; - tree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d1u0 - mtc_table_entry->trained_dram_clktree_c1d1u0) << 7; - tree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d1u1 - mtc_table_entry->trained_dram_clktree_c1d1u1) << 7; - tree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000; - tree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000; - for (s32 i = 0; i < 4; i++) - { - if ((tree_delta_taps[i] > mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * mtc_table_entry->tree_margin))) { - new_trim[8 + i * 2] += tree_delta_taps[i]; - new_trim[8 + i * 2 + 1] += tree_delta_taps[i]; - } - } - if (trim_emc_reg_addr == EMC_DATA_BRLSHFT_1) - { - for (s32 i = 0; i < 8; i++) - new_trim[i + 8] /= 64; - } - else - { - for (s32 i = 0; i < 8; i++) - new_trim[i + 8] %= 64; - } - break; - } - - switch (trim_emc_reg_addr) - { - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0: - trimmer = (new_trim[0] & 0x7FF) | ((new_trim[1] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1: - trimmer = (new_trim[2] & 0x7FF) | ((new_trim[3] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2: - trimmer = (new_trim[4] & 0x7FF) | ((new_trim[5] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3: - trimmer = (new_trim[6] & 0x7FF) | ((new_trim[7] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0: - trimmer = (new_trim[8] & 0x7FF) | ((new_trim[9] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1: - trimmer = (new_trim[10] & 0x7FF) | ((new_trim[11] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2: - trimmer = (new_trim[12] & 0x7FF) | ((new_trim[13] & 0x7FF) << 16); - break; - case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3: - trimmer = (new_trim[14] & 0x7FF) | ((new_trim[15] & 0x7FF) << 16); - break; - case EMC_DATA_BRLSHFT_0: - trimmer = (new_trim[0] & 7) - | ((new_trim[1] & 7) << 3) - | ((new_trim[2] & 7) << 6) - | ((new_trim[3] & 7) << 9) - | ((new_trim[4] & 7) << 12) - | ((new_trim[5] & 7) << 15) - | ((new_trim[6] & 7) << 18) - | ((new_trim[7] & 7) << 21); - break; - case EMC_DATA_BRLSHFT_1: - trimmer = (new_trim[8] & 7) - | ((new_trim[9] & 7) << 3) - | ((new_trim[10] & 7) << 6) - | ((new_trim[11] & 7) << 9) - | ((new_trim[12] & 7) << 12) - | ((new_trim[13] & 7) << 15) - | ((new_trim[14] & 7) << 18) - | ((new_trim[15] & 7) << 21); - break; - default: - break; - } - - return trimmer; -} - -static bool _check_freq_changed(u32 dst_entry_rate_KHz, u32 dst_entry_clk_src_emc, u32 src_entry_rate_KHz, u32 src_entry_clk_src_emc) -{ - float dst_div_clock; - float src_div_clock; - float src_end_div_clk_ratio; - - u32 src_entry_emc_2X_clk_src = src_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - u32 dst_entry_emc_2X_clk_src = dst_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - u32 src_entry_emc_2X_clk_src_div = src_entry_clk_src_emc & 0xFF; - u32 dst_entry_emc_2X_clk_src_div = dst_entry_clk_src_emc & 0xFF; - u32 pll_post_divider = 0; - switch (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) >> EMC_2X_CLK_SRC_SHIFT) - { - case PLLM_OUT0: - case PLLM_UD: - pll_post_divider = (CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) >> 20) & 0x1F; - break; - case PLLMB_UD: - case PLLMB_OUT0: - pll_post_divider = (CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) >> 20) & 0x1F; - break; - default: - break; - } - if (pll_post_divider > 5) - { - while (true) - ; - } - - if (src_entry_emc_2X_clk_src <= PLLMB_UD) - src_entry_emc_2X_clk_src_div = 0; - if (dst_entry_emc_2X_clk_src <= PLLMB_UD) - dst_entry_emc_2X_clk_src_div = 0; - - if (dst_entry_emc_2X_clk_src != src_entry_emc_2X_clk_src && (dst_entry_emc_2X_clk_src & 0xFFFFFFFB || src_entry_emc_2X_clk_src & 0xFFFFFFFB)) - return true; - - dst_div_clock = (double)dst_entry_rate_KHz - * ((double)((dst_entry_emc_2X_clk_src_div >> 1) + 1) - + (double)(dst_entry_emc_2X_clk_src_div & 1) * 0.5) - * (double)(pll_post_divider + 1); - src_div_clock = (double)src_entry_rate_KHz - * ((double)((src_entry_emc_2X_clk_src_div >> 1) + 1) - + (double)(src_entry_emc_2X_clk_src_div & 1) * 0.5) - * (double)(pll_post_divider + 1); - - src_end_div_clk_ratio = src_div_clock / dst_div_clock; - - if (src_end_div_clk_ratio > 1.01f || src_end_div_clk_ratio < 0.99f) - return true; - else - return false; -} - -static void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training, s32 dram_dev_num, bool channel1_enabled) -{ - bool needs_ca_training = needs_training & 1; - bool needs_ca_vref_training = (needs_training >> 1) & 1; - bool needs_quse_training = (needs_training >> 2) & 1; - bool needs_quse_vref_training = (needs_training >> 3) & 1; - bool needs_wr_training = (needs_training >> 4) & 1; - bool needs_wr_vref_training = (needs_training >> 5) & 1; - bool needs_rd_training = (needs_training >> 6) & 1; - bool needs_rd_vref_training = (needs_training >> 7) & 1; - bool needs_training_in_self_refresh = (needs_training >> 9) & 1; - - if (needs_ca_training) - { - mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_0_idx = EMC_CH0(EMC_CMD_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc_cmd_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_CMD_BRLSHFT_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) : 0; - - if (needs_training_in_self_refresh) - { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2); - } - } - - if (needs_ca_vref_training) - { - mtc_table_entry->burst_reg_per_ch.emc0_mrw10_idx = (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF) | 0x880C0000; - mtc_table_entry->burst_reg_per_ch.emc1_mrw10_idx = (channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF : 0) | 0x880C0000; - - u32 mrw11_dev_selectn = 0; - if (dram_dev_num == TWO_RANK) - mrw11_dev_selectn = 0x480C0000; - else - mrw11_dev_selectn = 0xC80C0000; - - mtc_table_entry->burst_reg_per_ch.emc0_mrw11_idx = - ((EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 16) & 0xFF) - | (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 24 << 8) - | (mrw11_dev_selectn & 0xFFFFFF00); - - mtc_table_entry->burst_reg_per_ch.emc1_mrw11_idx = - (((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 16) & 0xFF) - | ((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 24 << 8) - | (mrw11_dev_selectn & 0xFFFFFF00); - } - - if (needs_quse_training || needs_rd_training) - { - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_0_idx = EMC_CH0(EMC_QUSE_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_1) : 0; - - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_0_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_1_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_3) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_2_idx = EMC_CH0(EMC_QUSE_BRLSHFT_2); - mtc_table_entry->trim_perch_regs.emc_quse_brlshft_3_idx = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_3) : 0; - - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_0_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_1_idx = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_3) : 0; - } - } - - if (needs_quse_vref_training) - { - if (dram_dev_num == TWO_RANK) - { - u32 emc0_opt_dqs_array[4] = {0}; - u32 emc1_opt_dqs_array[4] = {0}; - u32 emc1_training_opt_dqs_ib_vref_rank0_val = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) : 0; - u32 emc1_training_opt_dqs_ib_vref_rank1_val = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) : 0; - - for (u32 i = 0; i < 4; i++) - { - emc0_opt_dqs_array[i] = (EMC_CH0(EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) >> (8 * i)) & 0xFF; - emc1_opt_dqs_array[i] = (emc1_training_opt_dqs_ib_vref_rank0_val >> (8 * i)) & 0xFF; - } - - u32 ib_vref_dqs_0 = 0; - u32 ib_vref_dqs_1 = 0; - for (u32 i = 0; i < 4; i++) - { - ib_vref_dqs_0 |= (emc0_opt_dqs_array[i] + ((EMC_CH0(EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) >> (8 * i)) & 0xFF)) >> 1 << (8 * i); - ib_vref_dqs_1 |= (emc1_opt_dqs_array[i] + ((emc1_training_opt_dqs_ib_vref_rank1_val >> (8 * i)) & 0xFF)) >> 1 << (8 * i); - } - - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0_idx = ib_vref_dqs_0; - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1_idx = ib_vref_dqs_1; - } - else - { - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0_idx = EMC(EMC_PMACRO_IB_VREF_DQS_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_VREF_DQS_1) : 0; - } - } - - if (needs_rd_training) - { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) : 0; - } - - if (needs_training_in_self_refresh) - { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; - } - } - - if (needs_rd_vref_training) - { - char ib_vref_dq_byte0_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[0] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[0] & 0x80000000) // < 0 check. - ib_vref_dq_byte0_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[0] & 0x7F); - - char ib_vref_dq_byte1_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[1] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[1] & 0x80000000) - ib_vref_dq_byte1_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[1] & 0x7F); - - char ib_vref_dq_byte2_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[2] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[2] & 0x80000000) - ib_vref_dq_byte2_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[2] & 0x7F); - - char ib_vref_dq_byte3_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[3] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[3] & 0x80000000) - ib_vref_dq_byte3_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[3] & 0x7F); - - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_0_idx = - ((ib_vref_dq_byte0_icr & 0x7F) - | (ib_vref_dq_byte1_icr & 0x7F) << 8) - | ((ib_vref_dq_byte2_icr & 0x7F) << 16) - | ((ib_vref_dq_byte3_icr & 0x7F) << 24); - - char ib_vref_dq_byte4_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[4] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[4] & 0x80000000) - ib_vref_dq_byte4_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[4] & 0x7F); - - char ib_vref_dq_byte5_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[5] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[5] & 0x80000000) - ib_vref_dq_byte5_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[5] & 0x7F); - - char ib_vref_dq_byte6_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[6] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[6] & 0x80000000) - ib_vref_dq_byte6_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[6] & 0x7F); - - char ib_vref_dq_byte7_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[7] & 0x7F); - if (mtc_table_entry->save_restore_mod_regs[7] & 0x80000000) - ib_vref_dq_byte7_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[7] & 0x7F); - - mtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_1_idx = - ((ib_vref_dq_byte4_icr & 0x7F) - | (ib_vref_dq_byte5_icr & 0x7F) << 8) - | ((ib_vref_dq_byte6_icr & 0x7F) << 16) - | ((ib_vref_dq_byte7_icr & 0x7F) << 24); - } - } - - if (needs_wr_training) - { - mtc_table_entry->trim_perch_regs.emc0_data_brlshft_0_idx = EMC_CH0(EMC_DATA_BRLSHFT_0); - mtc_table_entry->trim_perch_regs.emc1_data_brlshft_0_idx = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_0) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_perch_regs.emc0_data_brlshft_1_idx = EMC_CH0(EMC_DATA_BRLSHFT_1); - mtc_table_entry->trim_perch_regs.emc1_data_brlshft_1_idx = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_1) : 0; - } - - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) : 0; - } - - if (needs_training_in_self_refresh) - { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; - - if (dram_dev_num == TWO_RANK) - { - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2); - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; - mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; - } - } - - if (needs_wr_vref_training) // mode 12/13 (MRW). - { - u32 emc1_ranks_sub_partitions = 0; - emc1_ranks_sub_partitions = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQ_OB_VREF) : 0; - - u8 emc0_ib_vref_dq_byte8_modded_plus = mtc_table_entry->save_restore_mod_regs[8] + EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF); - if (mtc_table_entry->save_restore_mod_regs[8] & 0x80000000) // < 0 check. - emc0_ib_vref_dq_byte8_modded_plus = EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) - mtc_table_entry->save_restore_mod_regs[8]; - - u8 emc0_mrw12_op_sp1 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) + mtc_table_entry->save_restore_mod_regs[9]; - if (mtc_table_entry->save_restore_mod_regs[9] & 0x80000000) - emc0_mrw12_op_sp1 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) - mtc_table_entry->save_restore_mod_regs[9]; - - u8 emc0_mrw13_op_sp0 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) + mtc_table_entry->save_restore_mod_regs[8]; - if (mtc_table_entry->save_restore_mod_regs[8] & 0x80000000) - emc0_mrw13_op_sp0 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) - mtc_table_entry->save_restore_mod_regs[8]; - - u8 emc0_ib_vref_dq_byte9_modded_a_plus = mtc_table_entry->save_restore_mod_regs[9] + (EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 24); - if (mtc_table_entry->save_restore_mod_regs[9] & 0x80000000) - emc0_ib_vref_dq_byte9_modded_a_plus = (EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 24) - (u8)mtc_table_entry->save_restore_mod_regs[9]; - - u8 emc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions + mtc_table_entry->save_restore_mod_regs[10]; - if (mtc_table_entry->save_restore_mod_regs[10] & 0x80000000) - emc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions - mtc_table_entry->save_restore_mod_regs[10]; - - u8 emc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) + mtc_table_entry->save_restore_mod_regs[11]; - if (mtc_table_entry->save_restore_mod_regs[11] & 0x80000000) - emc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) - mtc_table_entry->save_restore_mod_regs[11]; - - u8 emc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) + mtc_table_entry->save_restore_mod_regs[10]; - if (mtc_table_entry->save_restore_mod_regs[10] & 0x80000000) - emc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) - mtc_table_entry->save_restore_mod_regs[10]; - - u8 emc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) + mtc_table_entry->save_restore_mod_regs[11]; - if (mtc_table_entry->save_restore_mod_regs[11] & 0x80000000) - emc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) - mtc_table_entry->save_restore_mod_regs[11]; - - u32 mr13_dev_ext_cnt_sp_addr = 0xC80E0000; - if (dram_dev_num == TWO_RANK) - mr13_dev_ext_cnt_sp_addr = 0x480E0000; - - mtc_table_entry->burst_reg_per_ch.emc1_mrw12_idx = (u8)emc0_ib_vref_dq_byte10_modded_plus | 0x880E0000 | (emc0_ib_vref_dq_byte11_modded_plus << 8); - mtc_table_entry->burst_reg_per_ch.emc0_mrw12_idx = emc0_ib_vref_dq_byte8_modded_plus | 0x880E0000 | (emc0_mrw12_op_sp1 << 8); - mtc_table_entry->burst_reg_per_ch.emc0_mrw13_idx = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; - mtc_table_entry->burst_reg_per_ch.emc1_mrw13_idx = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr; - - } - } -} - -s32 _minerva_set_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 needs_training, u32 selected_clk_src_emc) -{ - u32 emc_dbg_o; - u32 emc_pin_o; - u32 emc_cfg_pipe_clk_o; - u32 emc_sel_dpd_ctrl; - u32 emc_cfg; - u32 emc_dbg_val; - u32 emc_zq_cal = 0; - u32 ramp_up_wait; - u32 ramp_down_wait; - u32 bg_regulator_mode_change; - u32 mr13_flip_fspop = 0; - u32 mr13_flip_fspwr = 0; //float - u32 mr13_catr_enable; //float - bool opt_zcal_en_cc; - - /* needs_training LOBYTE table var */ - /* - | bit | Description | - |-----|----------------------------| - | 0 | Needs CA training | - | 1 | Needs CA_VREF training | - | 2 | Needs QUSE training | - | 3 | Needs QUSE_VREF training | - | 4 | Needs WR training | - | 5 | Needs WR_VREF training | - | 6 | Needs RD training | - | 7 | Needs RD_VREF training | - */ - - bool opt_dll_mode = false; - bool is_lpddr3_dram = false; - bool compensate_trimmer_applicable = false; - bool needs_ca_or_cavref_training = (needs_training & 3) != 0; - bool needs_tristate_training = (needs_training & 0xF7) != 0; - bool needs_ca_training = needs_training & 1; - bool needs_ca_vref_training = (needs_training >> 1) & 1; - bool needs_quse_training = (needs_training >> 2) & 1; - bool needs_quse_vref_training = (needs_training >> 3) & 1; - bool needs_wr_training = (needs_training >> 4) & 1; - bool needs_wr_vref_training = (needs_training >> 5) & 1; - bool needs_rd_training = (needs_training >> 6) & 1; - bool needs_rd_vref_training = (needs_training >> 7) & 1; - bool needs_swap_rank_training = (needs_training >> 8) & 1; - - bool zcal_resistor_shared = (src_emc_entry->burst_regs.emc_zcal_wait_cnt_idx >> 31) & 1; - bool enable_bg_regulator = (dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 1) ^ 1; - bool channel1_enabled = (src_emc_entry->burst_regs.emc_fbio_cfg7_idx >> 2) & 1; - s32 dram_type = EMC(EMC_FBIO_CFG5) & 3; - s32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; - - float src_clock_period = 1000000.0 / (double)src_emc_entry->rate_khz; - float dst_clock_period = 1000000.0 / (double)dst_emc_entry->rate_khz; - - fsp_for_src_freq = !fsp_for_src_freq; - - if (dst_emc_entry->burst_regs.emc_zcal_interval_idx && !src_emc_entry->burst_regs.emc_zcal_interval_idx) - opt_zcal_en_cc = true; - else - opt_zcal_en_cc = dram_type == DRAM_TYPE_LPDDR4; - - switch(dram_type) - { - case DRAM_TYPE_DDR2: - case DRAM_TYPE_LPDDR4: - break; - case DRAM_TYPE_DDR3: - opt_dll_mode = (dst_emc_entry->emc_emrs & 1) ^ 1; - break; - - case DRAM_TYPE_LPDDR2: - if ((dst_emc_entry->burst_regs.emc_fbio_cfg5_idx >> 25) & 1) //LPDDR3_DRAM bit - is_lpddr3_dram = true; - break; - } - - u32 tFC_lpddr4 = dst_emc_entry->dram_timings.t_fc_lpddr4; - float tZQCAL_lpddr4 = 1000.0f; - if (src_clock_period <= 2.0) - tZQCAL_lpddr4 = (float)(1000 - tFC_lpddr4); - s32 tZQCAL_lpddr4_fc_adj = (s32)(float)(tZQCAL_lpddr4 / dst_clock_period); - - // Step 1 - Pre DVFS SW sequence. - EPRINTF("Step 1"); - emc_dbg_o = EMC(EMC_DBG); - emc_pin_o = EMC(EMC_PIN); - emc_cfg = dst_emc_entry->burst_regs.emc_cfg_idx & 0xFFFFFFF; - emc_sel_dpd_ctrl = dst_emc_entry->emc_sel_dpd_ctrl & 0xFFFFFEC3; - emc_cfg_pipe_clk_o = EMC(EMC_CFG_PIPE_CLK); - _digital_dll_disable(); - - // Step 1.2 - Disable AUTOCAL temporarily. - EPRINTF("Step 1.2"); - EMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FF) | 0x600; - - // Step 1.3 - Disable other power features. - EPRINTF("Step 1.3"); - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = emc_cfg; - EMC(EMC_SEL_DPD_CTRL) = emc_sel_dpd_ctrl; - EMC(EMC_DBG) = emc_dbg_o; - - if (!needs_tristate_training && dst_emc_entry->periodic_training) - { - if (dram_dev_num == TWO_RANK) - { - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, false, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, false, channel1_enabled); - } - else - { - _wait_emc_status(EMC_EMC_STATUS, 0x10, false, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, 0x10, false, channel1_enabled); - } - - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, channel1_enabled); - - // Reset clock tree delays. - dst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->trained_dram_clktree_c0d0u0; - dst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->trained_dram_clktree_c0d0u1; - dst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->trained_dram_clktree_c0d1u0; - dst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->trained_dram_clktree_c0d1u1; - dst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->trained_dram_clktree_c1d0u0; - dst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->trained_dram_clktree_c1d0u1; - dst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->trained_dram_clktree_c1d1u0; - dst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->trained_dram_clktree_c1d1u1; - - u32 adel = _minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_SEQUENCE); - - if (((dst_emc_entry->rate_khz / 1000) << 7) * adel / 1000000 > dst_emc_entry->tree_margin) - compensate_trimmer_applicable = true; - } - - EMC(EMC_INTSTATUS) = CLKCHANGE_COMPLETE_INT; - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = emc_cfg; - EMC(EMC_SEL_DPD_CTRL) = emc_sel_dpd_ctrl; - EMC(EMC_CFG_PIPE_CLK) = emc_cfg_pipe_clk_o | 1; // CLK_ALWAYS_ON. - EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp & 0xFFFFFFFE; - - bg_regulator_mode_change = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx ^ dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx; - bg_regulator_mode_change = (bg_regulator_mode_change | (bg_regulator_mode_change >> 2)) & 1; - - if (bg_regulator_mode_change) - { - EMC(EMC_DBG) = emc_dbg_o | 2; - if (enable_bg_regulator) - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE; - else - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB; - } - - // Check if we need to turn on VREF generator. - if ((!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x100) - && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0x100)) - || (!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1) - && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1))) - { - EMC(EMC_PMACRO_DATA_PAD_TX_CTRL) = - (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 1) | (src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx & 0xFFFFFFFE)) & 0xFFFFFEFF) - | (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl_idx >> 8) & 0x1) << 8); - _usleep(1); - } - else if (bg_regulator_mode_change) - _usleep(1); - - EMC(EMC_DBG) = emc_dbg_o; - - // Step 2 - Prelock the DLL. - EPRINTF("Step 2"); - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx & 1) - _digital_dll_prelock(dst_emc_entry, needs_tristate_training, selected_clk_src_emc); //Prelock enabled for target frequency. - else - { - _change_dll_src(dst_emc_entry, selected_clk_src_emc); - _digital_dll_disable(); // Disabling DLL for target frequency. - } - - // Step 3 - Prepare autocal for the clock change. - EPRINTF("Step 3"); - EMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FF) | 0x600; - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_AUTO_CAL_CONFIG2) = dst_emc_entry->emc_auto_cal_config2; - EMC(EMC_AUTO_CAL_CONFIG3) = dst_emc_entry->emc_auto_cal_config3; - EMC(EMC_AUTO_CAL_CONFIG4) = dst_emc_entry->emc_auto_cal_config4; - EMC(EMC_AUTO_CAL_CONFIG5) = dst_emc_entry->emc_auto_cal_config5; - EMC(EMC_AUTO_CAL_CONFIG6) = dst_emc_entry->emc_auto_cal_config6; - EMC(EMC_AUTO_CAL_CONFIG7) = dst_emc_entry->emc_auto_cal_config7; - EMC(EMC_AUTO_CAL_CONFIG8) = dst_emc_entry->emc_auto_cal_config8; - EMC(EMC_DBG) = emc_dbg_o; - EMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FE) | 0x601; - - // Step 4 - Update EMC_CFG. - EPRINTF("Step 4"); - if (src_clock_period <= 50.0f || dram_type != 1) - EMC(EMC_CFG_2) = dst_emc_entry->emc_cfg_2; - else - _ccfifo_write(EMC_SELF_REF, 1, 0); - - // Step 5 - Prepare reference variables for ZQCAL regs. - EPRINTF("Step 5"); - // u32 zq_wait_long = 0; - // u32 zq_wait_short = 0; - - // if (dram_type == DRAM_TYPE_LPDDR4) - // zq_wait_long = _fceil(1000.0f / dst_clock_period); - // else if (is_lpddr3_dram || dram_type == DRAM_TYPE_LPDDR2) - // zq_wait_long = _fceil(360.0f / dst_clock_period); - // else if (!dram_type) - // zq_wait_long = _fceil(320.0f / dst_clock_period); - - // if (is_lpddr3_dram || dram_type == DRAM_TYPE_LPDDR2) - // zq_wait_short = _fceil(90.0f / dst_clock_period); - // else if (!dram_type) - // zq_wait_short = _fceil(80.0f / dst_clock_period); - - // Step 7 - Bug 200024907 - Patch RP R2P. - EPRINTF("Step 7"); - if (needs_ca_or_cavref_training && dram_dev_num == TWO_RANK) - EMC(EMC_PIN) = 0x107; - - if (dram_type == DRAM_TYPE_LPDDR4) - { - u32 R2P_war = 0; - u32 TRPab_war = 0; - u32 RP_war = 0; - u32 W2P_war = 0; - - s32 nRTP = 8; // <= 1066MHz. - if (src_clock_period < 3.7593985 // 1000 / 266MHz. - && src_clock_period < 1.87617261 // 1000 / 533MHz. - && src_clock_period < 1.25 // 1000 / 800MHz. - && src_clock_period < 0.938086304) // 1000 / 1066MHz. - nRTP = 10; // 1067MHz < x <= 1333MHz. - if (src_clock_period < 0.750187547) // 1000 / 1333MHz. - nRTP = 12; // 1333MHz < x <= 1333MHz. - if (src_clock_period < 0.625) // 1000 / 1600MHz. - nRTP = 14; // 1600MHz < x <= 1866MHz. - if (src_clock_period < 0.535905681) // 1000 / 1866MHz. - nRTP = 16; // > 1866MHz - - float tRPST = (float)((src_emc_entry->emc_mrw >> 7) & 1) + 0.5f; - - s32 deltaTWATM = _fceil(7.5f / src_clock_period); - if (deltaTWATM < 8) - deltaTWATM = 8; - - u32 tRTM = (u32)_fceil((float)((((float)src_emc_entry->dram_timings.rl + _fceil(3.6f / src_clock_period) + (float)deltaTWATM) + tRPST) + (float)nRTP)); - - if (tRTM <= src_emc_entry->burst_regs.emc_rp_idx + src_emc_entry->burst_regs.emc_r2p_idx) - { - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; - R2P_war = src_emc_entry->burst_regs.emc_r2p_idx; - RP_war = src_emc_entry->burst_regs.emc_rp_idx; - } - else - { - R2P_war = tRTM - src_emc_entry->burst_regs.emc_rp_idx; - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; - RP_war = src_emc_entry->burst_regs.emc_rp_idx; - if (R2P_war > 63) - { - RP_war = tRTM - 63; - R2P_war = 63; - if (src_emc_entry->burst_regs.emc_trpab_idx < tRTM - 63) - TRPab_war = tRTM - 63; - else - TRPab_war = src_emc_entry->burst_regs.emc_trpab_idx; - } - } - - if (RP_war >= deltaTWATM) - W2P_war = src_emc_entry->burst_regs.emc_w2p_idx; - else - { - u32 W2P_war_temp = deltaTWATM + src_emc_entry->burst_regs.emc_w2p_idx; - W2P_war = W2P_war_temp - RP_war; - if (W2P_war > 63) - { - RP_war = W2P_war_temp - 63; - W2P_war = 63; - if (TRPab_war < RP_war) - TRPab_war = RP_war; - } - } - - if ( src_emc_entry->burst_regs.emc_w2p_idx != W2P_war - || src_emc_entry->burst_regs.emc_rp_idx != RP_war - || src_emc_entry->burst_regs.emc_r2p_idx != R2P_war - || src_emc_entry->burst_regs.emc_trpab_idx != TRPab_war) - { - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_RP) = RP_war; - EMC(EMC_R2P) = R2P_war; - EMC(EMC_W2P) = W2P_war; - EMC(EMC_TRPAB) = TRPab_war; - EMC(EMC_DBG) = emc_dbg_o; - _usleep(1); - } - } - - // Step 7.2 - Program FSP reference registers and send MRWs to new FSPWR. - EPRINTF("Step 7.2"); - mr13_catr_enable = 0; - if (fsp_for_src_freq) - { - mr13_flip_fspop = dst_emc_entry->emc_mrw3 | 0xC0; - mr13_flip_fspwr = (dst_emc_entry->emc_mrw3 & 0xFFFFFF3F) | 0x40; - } - else - { - mr13_flip_fspop = dst_emc_entry->emc_mrw3 & 0xFFFFFF3F; - mr13_flip_fspwr = mr13_flip_fspop | 0x80; - } - - if (needs_ca_or_cavref_training && dram_dev_num == TWO_RANK) - { - if (needs_swap_rank_training) - { - mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x80000000; - mr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF)| 0x40000001; - } - else - { - mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x40000000; - mr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x80000001; - } - } - else if (dram_dev_num == TWO_RANK) - { - if (needs_swap_rank_training) - mr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x40000001; - else - mr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x80000001; - } - else - mr13_catr_enable = mr13_flip_fspwr | 1; - - if (dram_type == DRAM_TYPE_LPDDR4) - { - EMC(EMC_MRW3) = mr13_flip_fspwr; - EMC(EMC_MRW) = dst_emc_entry->emc_mrw; - EMC(EMC_MRW2) = dst_emc_entry->emc_mrw2; - } - - // Step 8 - Program the shadow registers. - EPRINTF("Step 8"); - // Writing burst_regs. - u32 reg_addr = 0; - u32 reg_val = 0; - u32 reg_check = false; - burst_regs_table_t *dst_burst_regs = (burst_regs_table_t *)&dst_emc_entry->burst_regs; - - for (u32 i = 0; dst_emc_entry->num_burst > i; i++) - { - reg_check = false; - reg_addr = burst_regs_emc_addr_table[i]; - if (needs_tristate_training) - { - if (needs_ca_or_cavref_training) - reg_val = dst_burst_regs->shadow_regs_ca_train[i]; - else if (needs_training & 0xC) - reg_val = dst_burst_regs->shadow_regs_quse_train[i]; - else if (needs_training & 0xF0) - reg_val = dst_burst_regs->shadow_regs_rdwr_train[i]; - else - continue; - } - else - reg_val = dst_burst_regs->burst_regs[i]; - - if ((reg_addr & 0xFFF7) != EMC_MRW6 - && (reg_addr - EMC_MRW7) & 0xFFFF7 - //&& (reg_addr & 0xEFF7) != 0x34B4 // EMC_MRW10. - && ((reg_addr & 0xEFFF) - 0x34B8) & 0xFFF7 // EMC_MRW11. - && reg_addr != EMC_TRAINING_CTRL - && reg_addr != EMC_MRW14 - && reg_addr != EMC_MRW15) - { - reg_check = true; - } - - if (reg_check && reg_addr == EMC_CFG) - { - if (dram_type == DRAM_TYPE_LPDDR4) - reg_val &= 0xFFFFFFF; - else - reg_val &= 0xCFFFFFFF; - EMC(reg_addr) = reg_val; - continue; - } - if (!reg_check && dram_type != DRAM_TYPE_LPDDR4) - continue; - - if (reg_addr != EMC_CFG)// EMC_CFG - { - if (reg_addr != EMC_ZCAL_INTERVAL || !opt_zcal_en_cc) - { - switch ( reg_addr ) - { - case EMC_PMACRO_AUTOCAL_CFG_COMMON: - reg_val |= 0x10000; - break; - case EMC_PMACRO_DATA_PAD_TX_CTRL: - reg_val &= 0xFEFEFDFD; - break; - case EMC_PMACRO_CMD_PAD_TX_CTRL: - reg_val = (reg_val & 0xFAFEFDFD) | 0x4000000; - break; - case EMC_PMACRO_BRICK_CTRL_RFU1: - reg_val &= 0xF800F800; - break; - case EMC_PMACRO_COMMON_PAD_TX_CTRL: - reg_val &= 0xFFFFFFF0; - break; - case EMC_TRAINING_CTRL: - reg_val |= needs_swap_rank_training << 14;// bit15 is TR_IN_SELF_REFRESH - break; - } - } - else - reg_val = 0; - } - else - reg_val &= 0xFFFFFFF; - - EMC(reg_addr) = reg_val; - } - - if (needs_tristate_training) - EMC(EMC_MRW) = (src_emc_entry->run_clocks & 0xFF) | 0x170000; - else - EMC(EMC_MRW) = (dst_emc_entry->run_clocks & 0xFF) | 0x170000; - - // Writing burst_regs_per_ch. - for (u32 i = 0; dst_emc_entry->num_burst_per_ch > i; i++) - { - reg_addr = burst_reg_per_ch_emc01_addr_table[i]; - if (reg_addr - && (((((reg_addr & 0xFFF) - 0x4B8) & 0xFFFFFFF7) //EMC0_MRW11 - && (reg_addr & 0xFFF) != 0x4B4 //EMC0_MRW10 - ALways true, because of constant table. - && (reg_addr & 0xFFFFFFF7) != EMC_MRW6 - && reg_addr != EMC_MRW15 - && reg_addr != EMC_MRW14 - && ((reg_addr - EMC_MRW7) & 0xFFFFFFF7)) - || dram_type == DRAM_TYPE_LPDDR4) - && (channel1_enabled || ((reg_addr - 0x4000) > 0xFFF))) - { - EMC(reg_addr) = dst_burst_regs->burst_reg_per_ch[i]; - } - } - - // Writing vref_regs. - trim_regs_table_t *trim_regs_table = (trim_regs_table_t *)&dst_emc_entry->trim_regs; - for (u32 i = 0; dst_emc_entry->vref_num > i; i++) - { - reg_addr = vref_perch_regs_emc01_addr_table[i]; - if (reg_addr && (channel1_enabled || (reg_addr - 0x4000) > 0xFFF)) - EMC(reg_addr) = trim_regs_table->vref_perch_regs[i]; - } - - // Writing training mod regs. - if (needs_tristate_training) - { - for (u32 i = 0; dst_emc_entry->training_mod_num > i; i++) - { - reg_addr = training_mod_regs_emc01_addr_table[i]; - if (reg_addr && (channel1_enabled || (reg_addr - 0x4000) > 0xFFF)) - EMC(reg_addr) = dst_emc_entry->training_mod_regs[i]; - } - } - - // Writing trim_regs - for (u32 i = 0; dst_emc_entry->num_trim > i; i++) - { - reg_addr = trim_regs_emc_addr_table[i]; - if (reg_addr) - { - if (((reg_addr & 0xFFFFFFF3) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 - || (reg_addr & 0xFFFFFFF3) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 - || (reg_addr & 0xFFFFFFFB) == EMC_DATA_BRLSHFT_0) - && compensate_trimmer_applicable) - { - EMC(reg_addr) = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr); - } - else - EMC(reg_addr) = trim_regs_table->trim_regs[i]; - } - } - - // Writing trim_regs_per_ch - reg_val = 0; - for (u32 i = 0; dst_emc_entry->num_trim_per_ch > i; i++) - { - reg_addr = trim_perch_regs_emc01_addr_table[i]; - if (reg_addr && (channel1_enabled || reg_addr - 0x4000 > 0xFFF)) - { - if (((reg_addr & 0xFFFFFFF3) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 - || (reg_addr & 0xFFFFFFF3) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 - || (reg_addr & 0xFFFFFFFB) == EMC_DATA_BRLSHFT_0) - && compensate_trimmer_applicable ) - { - reg_val = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr & 0xFFF); - } - else if (((reg_addr & 0xFFFFFFFB) == 0x3660 - || (reg_addr & 0xFFFFFFDF) == 0x3648 - || (reg_addr & 0xFFFFFFF7) == 0x3644 - || reg_addr == 0x366C - || reg_addr == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 - || (reg_addr & 0xFFFFFFFB) == 0x3588) - && compensate_trimmer_applicable ) - { - reg_val = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr & 0xFFF); - } - else if (((reg_addr & 0xFFFFFFF3) == 0x4660 - || (reg_addr & 0xFFFFFFF3) == 0x4640 - || (reg_addr & 0xFFFFFFFB) == 0x4588) - && compensate_trimmer_applicable) - { - reg_val = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr & 0xFFF); - } - else - { - reg_val = trim_regs_table->trim_perch_regs[i]; - } - EMC(reg_addr) = reg_val; - } - } - - if (needs_tristate_training) - { - // Check delta wrt previous values (save value if margin exceeds what is set in table). - if (needs_wr_training && dst_emc_entry->periodic_training) - _minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, WRITE_TRAINING_SEQUENCE); - } - else - { - // Writing burst_mc_regs. - for (u32 i = 0; dst_emc_entry->num_mc_regs > i; i++) - MC(burst_mc_regs_addr_table[i]) = dst_emc_entry->burst_mc_regs[i]; - } - - // Writing la_scale_regs. - //if ((dst_emc_entry->rate_khz < src_emc_entry->rate_khz) && dst_emc_entry->num_up_down) //NEW TODO - if ((dst_emc_entry->rate_khz < src_emc_entry->rate_khz) > needs_tristate_training) - { - for (u32 i = 0; dst_emc_entry->num_up_down > i; i++) - MC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i]; - } - - // Step 9 - LPDDR4. - EPRINTF("Step 9"); - if (dram_type == DRAM_TYPE_LPDDR4) - { - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx & 0xFF000000; - EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt_idx & 0xFFFFF800; - EMC(EMC_DBG) = emc_dbg_o | 0x40000002; - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx & 0xFF000000; - EMC(EMC_DBG) = emc_dbg_o; - if (needs_tristate_training) - { - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common_idx | 0x10000; - if (needs_ca_or_cavref_training) - EMC(EMC_FBIO_CFG5) = src_emc_entry->burst_regs.emc_fbio_cfg5_idx | 0x8000000; - EMC(EMC_DBG) = emc_dbg_o; - if (channel1_enabled) - _ccfifo_write(EMC_CFG_SYNC, 0, 0); - _ccfifo_write(EMC_DBG, (emc_dbg_o & 0xF3FFFFFF) | 0x4000000, 0); - } - } - - // Step 10 - Self refresh - EPRINTF("Step 10"); - u32 emc_self_ref_val = 1; - if (!opt_dll_mode && dram_type == DRAM_TYPE_DDR3) - _ccfifo_write(EMC_EMRS, dst_emc_entry->emc_emrs, 0); - else if (dram_type == DRAM_TYPE_LPDDR4) - emc_self_ref_val = 0x101; - - _ccfifo_write(EMC_SELF_REF, emc_self_ref_val, 0); - - if (needs_ca_or_cavref_training < ((src_clock_period <= 2.0f) && dram_type == DRAM_TYPE_LPDDR4)) - { - _ccfifo_write(EMC_MRW3, mr13_flip_fspwr ^ 0x40, 0); - _ccfifo_write(EMC_MRW6, (src_emc_entry->burst_regs.emc_mrw6_idx & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw6_idx & 0xFFFF3F3F), 0); - _ccfifo_write(EMC_MRW14, (src_emc_entry->burst_regs.emc_mrw14_idx & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw14_idx & 0xFFFF0707), 0); - if (dram_dev_num == TWO_RANK) - { - _ccfifo_write(EMC_MRW7, (src_emc_entry->burst_regs.emc_mrw7_idx & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw7_idx & 0xFFFF3F3F), 0); - _ccfifo_write(EMC_MRW15, (src_emc_entry->burst_regs.emc_mrw15_idx & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw15_idx & 0xFFFF0707), 0); - } - if (opt_zcal_en_cc) - { - if (dram_dev_num == ONE_RANK || zcal_resistor_shared) - emc_zq_cal = 0x80000001; - else - emc_zq_cal = 1; - _ccfifo_write(EMC_ZQ_CAL, emc_zq_cal, 0); - } - } - - emc_dbg_val = emc_dbg_o; - float tRP_src_timing = (float)((float)src_emc_entry->dram_timings.t_rp / src_clock_period); - float tRFC_src_timing = (float)((float)src_emc_entry->dram_timings.t_rfc / src_clock_period); - bool in_self_refresh = false; - u32 ref_delay = 0; - - if (dram_type == DRAM_TYPE_LPDDR4) - { - if (needs_tristate_training) - { - emc_dbg_val = (emc_dbg_o & 0xF3FFFFFF) | 0x44000000; - _ccfifo_write(EMC_DBG, emc_dbg_val, 0); - } - if (needs_ca_or_cavref_training) - { - _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode_idx & 0xFFFFFCCC, 0); - if (dram_dev_num == TWO_RANK && needs_swap_rank_training) - { - _ccfifo_write(EMC_MRW3, mr13_flip_fspop | 8, (u32)tRP_src_timing); - _ccfifo_write(EMC_MRW3, mr13_catr_enable | 8, 0); - } - else - _ccfifo_write(EMC_MRW3, mr13_catr_enable | 8, (u32)tRP_src_timing); - - _ccfifo_write(EMC_TR_CTRL_0, 0x15A, 0); - ref_delay = (u32)(1000.0 / src_clock_period); - } - else - { - _ccfifo_write(EMC_MRW3, mr13_flip_fspop | 8, (u32)tRP_src_timing); - ref_delay = (u32)(float)((float)tFC_lpddr4 / src_clock_period); - } - _ccfifo_write(EMC_INTSTATUS, 0, ref_delay); - _ccfifo_write(EMC_PIN, emc_pin_o & 0xFFFFFFF8, 30); - } - else - { - in_self_refresh = true; - _ccfifo_write(EMC_SELF_REF, 0x1, 0); - } - - // Step 11 - Ramp down. - EPRINTF("Step 11"); - ref_delay = 0; - if (dram_type != DRAM_TYPE_LPDDR4) - ref_delay = (u32)(float)(tRP_src_timing + tRFC_src_timing + 20.0f); - _ccfifo_write(EMC_CFG_SYNC, 0, ref_delay); - _ccfifo_write(EMC_DBG, emc_dbg_val | 0x40000002, 0); // WRITE_MUX_ACTIVE | WRITE_ACTIVE_ONLY - ramp_down_wait = _dvfs_power_ramp_down(false, src_emc_entry, dst_emc_entry, src_clock_period); - - // Step 12 - Trigger clock change. - EPRINTF("Step 12"); - _ccfifo_write(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); - if (!needs_tristate_training) - _ccfifo_write(EMC_DBG, (emc_dbg_val & 0xBFFFFFFF) | 2, 0); - - // Step 13 - Ramp up. - EPRINTF("Step 13"); - ramp_up_wait = _dvfs_power_ramp_up(false, src_emc_entry, dst_emc_entry, needs_training & 0xFF, dst_clock_period); - _ccfifo_write(EMC_DBG, emc_dbg_val, 0); - - // Step 14 - Bringup CKE pins. - EPRINTF("Step 14"); - if (dram_type == DRAM_TYPE_LPDDR4) - { - u32 emc_pin_val_final = 0; - if (needs_ca_or_cavref_training) - { - emc_pin_val_final = emc_pin_o & 0xFFFFFFF8; - if (dram_dev_num == TWO_RANK) - { - if (needs_swap_rank_training) - emc_pin_val_final |= 5; - else - emc_pin_val_final |= 6; - } - } - else if (dram_dev_num == TWO_RANK) - emc_pin_val_final = emc_pin_o | 7; - else - emc_pin_val_final = (emc_pin_o & 0xFFFFFFF8) | 1; - - _ccfifo_write(EMC_PIN, emc_pin_val_final, 0); - } - - // Step 15 - Zqlatch. - EPRINTF("Step 15"); - if (dram_type == DRAM_TYPE_LPDDR4 && !needs_ca_or_cavref_training && opt_zcal_en_cc) - { - s32 zq_latch_dvfs_wait_time = 0; - s32 T_PDEX_timing_final = 0; - s32 T_PDEX_timing = _fceil((float)dst_emc_entry->dram_timings.t_pdex / dst_clock_period); - - if (src_clock_period > 2.0) - zq_latch_dvfs_wait_time = (s32)(tZQCAL_lpddr4_fc_adj - T_PDEX_timing); - else - zq_latch_dvfs_wait_time = - (s32)(tZQCAL_lpddr4_fc_adj - (s32)((float)(ramp_up_wait + ramp_down_wait) / dst_clock_period)); - - if (dram_dev_num == ONE_RANK) - { - if (T_PDEX_timing < 0) - T_PDEX_timing = 0; - - if (src_clock_period > 2.0) - _ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing); - - if (!needs_tristate_training) - { - _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } - emc_zq_cal = 0x80000002; - if (zq_latch_dvfs_wait_time < 0) - zq_latch_dvfs_wait_time = 0; - } - else if (zcal_resistor_shared) - { - if (src_clock_period > 2.0) - { - T_PDEX_timing_final = T_PDEX_timing; - if (T_PDEX_timing < 0) - T_PDEX_timing_final = 0; - _ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing_final); - } - T_PDEX_timing_final = zq_latch_dvfs_wait_time + T_PDEX_timing; - if ((zq_latch_dvfs_wait_time + T_PDEX_timing) < 0) - T_PDEX_timing_final = 0; - _ccfifo_write(EMC_ZQ_CAL, 0x80000002, T_PDEX_timing_final); - _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); - if (!needs_tristate_training) - { - _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, 0); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } - emc_zq_cal = 0x40000002; - zq_latch_dvfs_wait_time = (s32)(float)(1000.0f / dst_clock_period); - } - else - { - if (T_PDEX_timing < 0) - T_PDEX_timing = 0; - - if (src_clock_period > 2.0) - _ccfifo_write(EMC_ZQ_CAL, 1, T_PDEX_timing); - if (!needs_tristate_training) - { - _ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing); - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - _ccfifo_write(EMC_REF, 0, 0); - } - emc_zq_cal = 2; - - if (zq_latch_dvfs_wait_time < 0) - zq_latch_dvfs_wait_time = 0; - } - _ccfifo_write(EMC_ZQ_CAL, emc_zq_cal, (u32)zq_latch_dvfs_wait_time); - } - - _ccfifo_write(EMC_INTSTATUS, 0, 10); // WAR: delay for zqlatch. - - // Step 16 - LPDDR4 Conditional training kickoff. - EPRINTF("Step 16"); - if (needs_tristate_training && dram_type == DRAM_TYPE_LPDDR4) - { - _ccfifo_write(EMC_INTSTATUS, 0, (u32)(1020.0f / dst_clock_period)); - - u32 training_command = 0; - - if (needs_ca_training) - training_command |= (1 << 1); // CA: Initiates CA Training. - if (needs_ca_vref_training) - training_command |= (1 << 5); // CA_VREF: Initiates CA_VREF Training. - if (needs_quse_training) - training_command |= (1 << 4); // QUSE: Initiates QUSE Training. - if (needs_quse_vref_training) - training_command |= (1 << 8); // QUSE_VREF: Initiates DQS_VREF Training. - if (needs_wr_training) - training_command |= (1 << 3); // WR: Initiates WR Training. - if (needs_wr_vref_training) - training_command |= (1 << 6); // WR_VREF: Initiates OB (wrire) DRAM_VREF Training. - if (needs_rd_training) - training_command |= (1 << 2); // RD: Initiates RD Training. - if (needs_rd_vref_training) - training_command |= (1 << 7); // RD_VREF: Initiates IB_DQ_VREF Training. - training_command |= (1 << 31); // GO: Start the Training. - - _ccfifo_write(EMC_TRAINING_CMD, training_command, 0); - - if (bg_regulator_mode_change) - { - if (enable_bg_regulator) - _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE, 0); - else - _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB, 0); - } - - _ccfifo_write(EMC_SWITCH_BACK_CTRL, 1, 0); - - if (!needs_ca_or_cavref_training || needs_swap_rank_training) - { - _ccfifo_write(EMC_MRW3, mr13_flip_fspop ^ 0xC0, 0); - _ccfifo_write(EMC_INTSTATUS, 0, (u32)(1000.0f / dst_clock_period)); - } - - _ccfifo_write(EMC_PIN, emc_pin_o & 0xFFFFFFF8, 0); - _ccfifo_write(EMC_CFG_SYNC, 0, 0); - _ccfifo_write(EMC_DBG, emc_dbg_val | 0x40000002, 0); - - _dvfs_power_ramp_down(true, src_emc_entry, dst_emc_entry, dst_clock_period); - - _ccfifo_write(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); - _ccfifo_write(EMC_DBG, (emc_dbg_val & 0xBFFFFFFF) | 2, 0); - - _dvfs_power_ramp_up(true, src_emc_entry, dst_emc_entry, needs_training, src_clock_period); - - _ccfifo_write(EMC_DBG, emc_dbg_val, 0); - - if (dram_dev_num == TWO_RANK) - _ccfifo_write(EMC_PIN, emc_pin_o | 7, 0); - else - _ccfifo_write(EMC_PIN, (emc_pin_o & 0xFFFFFFF8) | 1, 0); - - if (needs_ca_or_cavref_training) - { - _ccfifo_write(EMC_TR_CTRL_0, 0x4A, (u32)(float)(200.0f / src_clock_period)); - _ccfifo_write(EMC_TR_CTRL_0, 0x40, (u32)(float)(1000.0f / src_clock_period)); - _ccfifo_write(EMC_MRW3, mr13_catr_enable & 0xFFFFFFFE, 0); - _ccfifo_write(EMC_INTSTATUS, 0, (u32)(float)(1000.0f / src_clock_period)); - _ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode_idx, 0); - } - _ccfifo_write(EMC_DBG, emc_dbg_o, 0); - - if (opt_zcal_en_cc) - { - _ccfifo_write(EMC_ZQ_CAL, 0x80000001, 0); - _ccfifo_write(EMC_ZQ_CAL, 0x80000002, (u32)(float)(1000.0f / src_clock_period)); - - if (zcal_resistor_shared && dram_dev_num == TWO_RANK) - { - if (!needs_ca_or_cavref_training || needs_swap_rank_training) - { - _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); - _ccfifo_write(EMC_ZQ_CAL, 0x40000002, (u32)(float)(1000.0f / src_clock_period)); - if (!needs_ca_or_cavref_training) - _ccfifo_write(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); - } - - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - - goto step_19_2; - } - else if (dram_dev_num == TWO_RANK) - { - if (needs_ca_or_cavref_training && !needs_swap_rank_training) - { - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - - goto step_19_2; - } - - _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); - _ccfifo_write(EMC_ZQ_CAL, 0x40000002, (u32)(float)(1000.0f / src_clock_period)); - } - } - - if (!needs_ca_or_cavref_training) - _ccfifo_write(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); - - _ccfifo_write(EMC_SELF_REF, 0x100, 0); - } - - if (dram_type != DRAM_TYPE_LPDDR4) - { - // Step 17 - MANSR exit self refresh. - EPRINTF("Step 17"); - _ccfifo_write(EMC_SELF_REF, 0, 0); - - if (dram_type != DRAM_TYPE_LPDDR2) - { - if (dram_type == DRAM_TYPE_DDR3) - { - if (opt_dll_mode) - _ccfifo_write(EMC_EMRS, dst_emc_entry->emc_emrs & 0xFBFFFFFF, 0); - - _ccfifo_write(EMC_EMRS2, dst_emc_entry->emc_emrs2 & 0xFBFFFFFF, 0); - _ccfifo_write(EMC_MRS, dst_emc_entry->emc_mrs | 0x4000000, 0); - - if (opt_zcal_en_cc) - { - _ccfifo_write(EMC_ZQ_CAL, 0x80000001, 0); - if (dram_dev_num == TWO_RANK) - _ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0); - } - } - - if (dram_type == DRAM_TYPE_LPDDR2 && opt_zcal_en_cc) - { - _ccfifo_write(EMC_MRW, 0x880A0056, 0); - if (dram_dev_num == TWO_RANK) - _ccfifo_write(EMC_MRW, 0x480A0056, 0); - } - - goto step_19_2; - } - - // Step 18 - Send MRWs to LPDDR3/DDR3. - EPRINTF("Step 18"); - _ccfifo_write(EMC_MRW2, dst_emc_entry->emc_mrw2, 0); - _ccfifo_write(EMC_MRW, dst_emc_entry->emc_mrw, 0); - if (is_lpddr3_dram) - _ccfifo_write(EMC_MRW4, dst_emc_entry->emc_mrw4, 0); - - // Step 19 - ZQCAL for LPDDR3/DDR3. - EPRINTF("Step 19"); - if (opt_zcal_en_cc) - { - u32 zcal_wait_time_clocks = _fceil(90.0f / dst_clock_period); - _ccfifo_write(EMC_MRS_WAIT_CNT2, ((zcal_wait_time_clocks & 0xB) << 16) | (zcal_wait_time_clocks & 0x3FF), 0); //WTFF - _ccfifo_write(EMC_MRW, 0x880A0056, 0); - if (dram_dev_num == TWO_RANK) - _ccfifo_write(EMC_MRW, 0x480A0056, 0); - } - } - -step_19_2: - // Step 19.2. - EPRINTF("Step 19.2"); - if (bg_regulator_mode_change) - { - _ccfifo_write(EMC_DBG, emc_dbg_o | 2, 0); - - u32 bg_regulator_switch_complete_wait_clks = 0; - if (needs_tristate_training) - { - bg_regulator_switch_complete_wait_clks = (u32)(float)(1250.0f / src_clock_period); - _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx, bg_regulator_switch_complete_wait_clks); - } - else - { - if (ramp_up_wait <= 1250) - bg_regulator_switch_complete_wait_clks = (u32)(float)((float)((s32)1250 - ramp_up_wait) / dst_clock_period); - _ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0, - dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx, bg_regulator_switch_complete_wait_clks); - } - - _ccfifo_write(EMC_DBG, emc_dbg_o, 0); - } - - // Step 20 - Issue ref and optional QRST. - EPRINTF("Step 20"); - if (needs_tristate_training || dram_type != DRAM_TYPE_LPDDR4) - _ccfifo_write(EMC_REF, 0, 0); - - // Step 21 - Restore ZCAL and ZCAL interval. - EPRINTF("Step 21"); - _ccfifo_write(EMC_DBG, emc_dbg_o | 2, 0); - - if (opt_zcal_en_cc) - { - if (needs_tristate_training) - _ccfifo_write(EMC_ZCAL_INTERVAL, src_emc_entry->burst_regs.emc_zcal_interval_idx, 0); - else if (dram_type != DRAM_TYPE_LPDDR4) - _ccfifo_write(EMC_ZCAL_INTERVAL, dst_emc_entry->burst_regs.emc_zcal_interval_idx, 0); - } - - _ccfifo_write(EMC_CFG, dst_emc_entry->burst_regs.emc_cfg_idx & 0xEFFFFFFF, 0); - - // Step 22 - Restore EMC_CFG_PIPE_CLK. - EPRINTF("Step 22"); - if (needs_tristate_training && dram_type == DRAM_TYPE_LPDDR4) - _ccfifo_write(EMC_SEL_DPD_CTRL, src_emc_entry->emc_sel_dpd_ctrl, 0); - _ccfifo_write(EMC_DBG, emc_dbg_o, 0); - _ccfifo_write(EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o, 0); - if (bg_regulator_mode_change) - { - if (enable_bg_regulator) - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFB; - else - EMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0_idx & 0xFFFFFFFE; - } - - // Step 23 - Clock Change. - EPRINTF("Step 23"); - if (needs_tristate_training) - { - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE) = (u32)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); - _change_dll_src(src_emc_entry, (u32)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC)); - } - EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x88; - - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = selected_clk_src_emc; - if (_wait_emc_status(EMC_INTSTATUS, CLKCHANGE_COMPLETE_INT, true, 0)) - return 4; // Clkchange handshake timeout error. - - // Step 24 - Save training results. - EPRINTF("Step 24"); - if (needs_tristate_training) - { - emc_dbg_val = EMC(EMC_DBG); - EMC(EMC_DBG) |= 1; - - _save_train_results(dst_emc_entry, needs_training, dram_dev_num, channel1_enabled); - - EMC(EMC_DBG) = emc_dbg_val; - } - - // Step 25 - Program MC updown regs. - EPRINTF("Step 25"); - //if (dst_emc_entry->rate_khz > src_emc_entry->rate_khz) //NEW TODO - if ((dst_emc_entry->rate_khz > src_emc_entry->rate_khz) > needs_tristate_training) - { - for (u32 i = 0; dst_emc_entry->num_up_down > i; i++) - MC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i]; - - bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); - if (_timing_update(dual_channel)) - return 4; - } - - // Step 26 - Restore ZCAL regs. - EPRINTF("Step 26"); - if (!in_self_refresh) - { - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt_idx; - EMC(EMC_ZCAL_INTERVAL) = dst_emc_entry->burst_regs.emc_zcal_interval_idx; - EMC(EMC_DBG) = emc_dbg_o; - } - - // Step 27 - Restore EMC_CFG, FDPD regs. - EPRINTF("Step 27"); - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg_idx; - EMC(EMC_DBG) = emc_dbg_o; - EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp; - EMC(EMC_SEL_DPD_CTRL) = dst_emc_entry->emc_sel_dpd_ctrl; - - // Step 28 - Training recover. - EPRINTF("Step 28"); - if (needs_tristate_training && dram_type == DRAM_TYPE_LPDDR4) - { - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg_idx; - EMC(EMC_SEL_DPD_CTRL) = dst_emc_entry->emc_sel_dpd_ctrl; - EMC(EMC_ZCAL_WAIT_CNT) = src_emc_entry->burst_regs.emc_zcal_wait_cnt_idx; - EMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval_idx; - EMC(EMC_AUTO_CAL_CONFIG2) = src_emc_entry->emc_auto_cal_config2; - EMC(EMC_AUTO_CAL_CONFIG3) = src_emc_entry->emc_auto_cal_config3; - EMC(EMC_AUTO_CAL_CONFIG4) = src_emc_entry->emc_auto_cal_config4; - EMC(EMC_AUTO_CAL_CONFIG5) = src_emc_entry->emc_auto_cal_config5; - EMC(EMC_AUTO_CAL_CONFIG6) = src_emc_entry->emc_auto_cal_config6; - EMC(EMC_AUTO_CAL_CONFIG7) = src_emc_entry->emc_auto_cal_config7; - EMC(EMC_AUTO_CAL_CONFIG8) = src_emc_entry->emc_auto_cal_config8; - EMC(EMC_DBG) = emc_dbg_o; - EMC(EMC_TR_DVFS) = dst_emc_entry->burst_regs.emc_tr_dvfs_idx & 0xFFFFFFFE; - } - - EMC(EMC_DBG) = emc_dbg_o | 2; - EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common_idx; - EMC(EMC_DBG) = emc_dbg_o; - - // Step 29 - Power fix WAR. - EPRINTF("Step 29"); - EMC(EMC_PMACRO_CFG_PM_GLOBAL_0) = 0xFF0000; - EMC(EMC_PMACRO_TRAINING_CTRL_0) = CH0_TRAINING_E_WRPTR; - EMC(EMC_PMACRO_TRAINING_CTRL_1) = CH0_TRAINING_E_WRPTR; - EMC(EMC_PMACRO_CFG_PM_GLOBAL_0) = 0; - - // Step 30 - Re-enable autocal and Restore FSP to account for switch back (training). - EPRINTF("Step 30"); - if (needs_tristate_training) - { - EMC(EMC_AUTO_CAL_CONFIG) = src_emc_entry->emc_auto_cal_config; - fsp_for_src_freq = !fsp_for_src_freq; - } - else - { - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx & 1) - _digital_dll_enable_rs(channel1_enabled); - EMC(EMC_AUTO_CAL_CONFIG) = dst_emc_entry->emc_auto_cal_config; - } - - return 0; -} - -static void _minerva_train_patterns(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, bool switch_rate, u32 selected_clk_src_emc) -{ - u32 needs_training_idx = 0; - u32 emc_cfg_dig_dll_val = 0; - u32 needs_training_emc_table[8] = {0}; - - u32 needs_training = dst_emc_entry->needs_training; - u32 dram_type = dst_emc_entry->burst_regs.emc_fbio_cfg5_idx & 3; - bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1); - - // Must start as true. - if (train_ram_patterns) - { - u32 train_table_off = dst_emc_entry->training_pattern * 256; - for (u32 i = 0; i < 256; i++) - { - EMC(EMC_TRAINING_PATRAM_DQ) = ram_pattern_dq_table[train_table_off + i]; - EMC(EMC_TRAINING_PATRAM_DMI) = ram_pattern_dmi_table[train_table_off + i] & 0xF; - EMC(EMC_TRAINING_PATRAM_CTRL) = 0x80000000 + i; - } - train_ram_patterns = false; - } - - if (needs_training && !dst_emc_entry->trained) - { - needs_training_idx = needs_training & 3; - - if (needs_training & 3) - { - needs_training_idx = 1; - needs_training_emc_table[0] = needs_training & 0x203; - if (MC(MC_EMEM_ADR_CFG) & 1) // if mapping W8 (1KB page). - { - needs_training_idx = 2; - needs_training_emc_table[1] = needs_training & 0x303; - } - } - - if (MC(MC_EMEM_ADR_CFG) & 1 && needs_training & 0xC) - { - needs_training_emc_table[needs_training_idx] = needs_training & 0x20C; - needs_training_emc_table[needs_training_idx + 1] = needs_training & 0x204; - needs_training_idx += 2; - } - else if (needs_training & 0xC) - needs_training_emc_table[needs_training_idx++] = needs_training & 0x20C; - - if (needs_training & 0xF0) - needs_training_emc_table[needs_training_idx++] = needs_training & 0x2F0; - - for (u32 i = 0; needs_training_idx > i; i++) // Runs more than once for needs_training & 0xF - { - _minerva_set_clock(src_emc_entry, dst_emc_entry, needs_training_emc_table[i], selected_clk_src_emc); - - EMC(EMC_DBG) = (EMC(EMC_DBG) & 0xF3FFFFFF) | 0x8000000; - EMC(EMC_CFG_UPDATE) = (EMC(EMC_CFG_UPDATE) & 0xFFFFFFF9) | 4; - _timing_update(dual_channel); - - EMC(EMC_CFG_UPDATE) &= 0xFFFFFFF9; - EMC(EMC_DBG) &= 0xF3FFFFFF; - EMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF3E) | 0x80; - _timing_update(dual_channel); - - emc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) & 0xFFFFFFFE; - if (dst_emc_entry->burst_regs.emc_cfg_dig_dll_idx == 1) - emc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) | 1; - EMC(EMC_CFG_DIG_DLL) = (emc_cfg_dig_dll_val & 0xFFFFFF3F) | 0x80; - _timing_update(dual_channel); - - while (!(EMC(EMC_DIG_DLL_STATUS) & 0x8000)) - ; - - // Bug 200024907. - if (dram_type == DRAM_TYPE_LPDDR4) - { - EMC(EMC_RP) = src_emc_entry->burst_regs.emc_rp_idx; - EMC(EMC_R2P) = src_emc_entry->burst_regs.emc_r2p_idx; - EMC(EMC_W2P) = src_emc_entry->burst_regs.emc_w2p_idx; - EMC(EMC_TRPAB) = src_emc_entry->burst_regs.emc_trpab_idx; - } - _timing_update(dual_channel); - - } - dst_emc_entry->trained = 1; - EPRINTF("Trained"); - } - - if (switch_rate) - _minerva_set_clock(src_emc_entry, dst_emc_entry, 0, selected_clk_src_emc); -} - -void minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg) -{ - s32 dram_type = EMC(EMC_FBIO_CFG5) & 3; - - // Only LPDDR chips are supported. - if (dram_type != DRAM_TYPE_LPDDR2 && dram_type != DRAM_TYPE_LPDDR4) - return; - - s32 dram_temp = _get_dram_temperature(); - - if (mtc_cfg->prev_temp == dram_temp || dram_temp < 0) - return; - - u32 refr = mtc_cfg->current_emc_table->burst_regs.emc_refresh_idx; - u32 pre_refr = mtc_cfg->current_emc_table->burst_regs.emc_pre_refresh_req_cnt_idx; - u32 dyn_self_ref = mtc_cfg->current_emc_table->burst_regs.emc_dyn_self_ref_control_idx; - - switch (dram_temp) - { - // Normal temp (<= 85 oC). - case 0: - case 1: - case 2: - case 3: - if (mtc_cfg->prev_temp < 4) - { - mtc_cfg->prev_temp = dram_temp; - return; - } - break; - // Over temp (> 85 oC). - case 4: // - refr = (refr & 0xFFFF0000) | ((refr & 0xFFFF) >> REFRESH_X2); - pre_refr = (pre_refr & 0xFFFF0000) | ((pre_refr & 0xFFFF) >> REFRESH_X2); - dyn_self_ref = (dyn_self_ref & 0xFFFF0000) | ((dyn_self_ref & 0xFFFF) >> REFRESH_X2); - break; - case 5: - case 6: // Temp 6 normally needs a derating emc table. - refr = (refr & 0xFFFF0000) | ((refr & 0xFFFF) >> REFRESH_X4); - pre_refr = (pre_refr & 0xFFFF0000) | ((pre_refr & 0xFFFF) >> REFRESH_X4); - dyn_self_ref = (dyn_self_ref & 0xFFFF0000) | ((dyn_self_ref & 0xFFFF) >> REFRESH_X4); - break; - default: - break; - } - - mtc_cfg->prev_temp = dram_temp; - - EMC(EMC_REFRESH) = refr; - EMC(EMC_PRE_REFRESH_REQ_CNT) = pre_refr; - EMC(EMC_DYN_SELF_REF_CONTROL) = dyn_self_ref; -} - -u32 minerva_do_periodic_compensation(emc_table_t *mtc_table_entry) -{ - if (mtc_table_entry && mtc_table_entry->periodic_training) - { - u32 val = 0; - s32 dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1; - bool channel1_enabled = (mtc_table_entry->burst_regs.emc_fbio_cfg7_idx >> 2) & 1; - - //u32 emc_dbg_o = EMC(EMC_DBG); - u32 emc_cfg_o = EMC(EMC_CFG); - u32 emc_cfg = emc_cfg_o & 0xFFFFFFF; - - // Step 1 - Disable other power features. - EMC(EMC_CFG) = emc_cfg; - - _digital_dll_disable(); - - if (dram_dev_num == TWO_RANK) - { - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, 0, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_MASK, 0, channel1_enabled); - } - else - { - _wait_emc_status(EMC_EMC_STATUS, 0x10, 0, 0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, 0x10, 0, channel1_enabled); - } - - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CH0); - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, channel1_enabled); - - _wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, EMC_CH0); //v1.6 - if (channel1_enabled) - _wait_emc_status(EMC_EMC_STATUS, REQ_FIFO_EMPTY, 0, channel1_enabled); //v1.6 - - u32 emc_cfg_update = EMC(EMC_CFG_UPDATE); - EMC(EMC_CFG_UPDATE) = (emc_cfg_update & 0xFFFFF9FF) | 0x400; - - // Step 2 - Osc kick off - this assumes training and dvfs have set correct MR23. - _start_periodic_compensation(); - - // Step 3 - Let dram capture its clock tree delays. - _usleep(1000 * _actual_osc_clocks(mtc_table_entry->run_clocks) / mtc_table_entry->rate_khz + 1); - - // Step 4 - Check delta wrt previous values (save value if margin exceeds what is set in table). - u32 adel = _minerva_update_clock_tree_delay(mtc_table_entry, mtc_table_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE); - - // Step 5 - Apply compensation w.r.t. trained values (if clock tree has drifted more than the set margin). - if (adel && ((mtc_table_entry->rate_khz / 1000) << 7) * adel / 1000000 > mtc_table_entry->tree_margin) - { - for (u32 i = 0; i < 10; i++) - { - val = _minerva_apply_periodic_compensation_trimmer(mtc_table_entry, periodic_training_addr[i]); - EMC(periodic_training_addr[i]) = val; - } - } - - EMC(EMC_CFG) = emc_cfg_o; - - // Step 6 - Timing update to apply the new trimmers. - _timing_update(channel1_enabled); - - // Step 6.1 - Restore the UPDATE_DLL_IN_UPDATE field. - EMC(EMC_CFG_UPDATE) = emc_cfg_update; - - // Step 6.2 - Restore the DLL. - _digital_dll_enable(channel1_enabled); - } - - return 0; -} - -s32 _minerva_set_rate(mtc_config_t *mtc_cfg) -{ - s32 src_emc_entry_idx = 0; - s32 dst_emc_entry_idx = 999; - s32 table_entry_rate; - u32 selected_clk_src_emc; - u32 selected_emc_2x_clk_src; - bool freq_changed = false; - emc_table_t *src_emc_entry; - emc_table_t *dst_emc_entry; - - for (s32 i = 0; i < mtc_cfg->table_entries; i++) - { - table_entry_rate = mtc_cfg->mtc_table[i].rate_khz; - if (mtc_cfg->rate_from == table_entry_rate) - src_emc_entry_idx = i; - if (mtc_cfg->rate_to == table_entry_rate) - dst_emc_entry_idx = i; - } - src_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[src_emc_entry_idx]; - dst_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[dst_emc_entry_idx]; - s32 src_rate_khz = src_emc_entry->rate_khz; - s32 dst_rate_khz = dst_emc_entry->rate_khz; - u32 src_clk_src_emc = src_emc_entry->clk_src_emc; - u32 dst_clk_src_emc = dst_emc_entry->clk_src_emc; - if (mtc_cfg->table_entries > 900) - return 4; - - freq_changed = _check_freq_changed(dst_rate_khz, dst_clk_src_emc, src_rate_khz, src_clk_src_emc); - EPRINTFARGS("Requested freq change from %d to %d.", src_rate_khz, dst_rate_khz); - - if (freq_changed) - { - selected_emc_2x_clk_src = src_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - if (selected_emc_2x_clk_src & 3) - { - if (selected_emc_2x_clk_src - PLLMB_UD <= 1) - emc_2X_clk_src_is_pllmb = 0; - } - else - { - emc_2X_clk_src_is_pllmb = !emc_2X_clk_src_is_pllmb; - } - selected_clk_src_emc = _pllm_clk_base_cfg(dst_rate_khz, dst_clk_src_emc, emc_2X_clk_src_is_pllmb); - } - else - { - selected_clk_src_emc = dst_clk_src_emc; - selected_emc_2x_clk_src = selected_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT; - if (selected_emc_2x_clk_src != PLLMB_OUT0 && selected_emc_2x_clk_src) - { - if (selected_emc_2x_clk_src - PLLM_UD <= PLLC_OUT0 && emc_2X_clk_src_is_pllmb) - selected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_UD << EMC_2X_CLK_SRC_SHIFT); - } - else if (emc_2X_clk_src_is_pllmb) - { - selected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT); - } - } - - switch (mtc_cfg->train_mode) - { - case OP_SWITCH: - _minerva_set_clock(src_emc_entry, dst_emc_entry, 0, selected_clk_src_emc); - mtc_cfg->current_emc_table = dst_emc_entry; - mtc_cfg->rate_from = dst_emc_entry->rate_khz; - if (dst_emc_entry->periodic_training) - minerva_do_periodic_compensation(dst_emc_entry); - return 0; - case OP_TRAIN: - _minerva_train_patterns(src_emc_entry, dst_emc_entry, false, selected_clk_src_emc); - if (freq_changed) - emc_2X_clk_src_is_pllmb = !emc_2X_clk_src_is_pllmb; - return 0; - case OP_TRAIN_SWITCH: - _minerva_train_patterns(src_emc_entry, dst_emc_entry, true, selected_clk_src_emc); - mtc_cfg->current_emc_table = dst_emc_entry; - mtc_cfg->rate_from = dst_emc_entry->rate_khz; - if (dst_emc_entry->periodic_training) - minerva_do_periodic_compensation(dst_emc_entry); - return 0; - default: - return 4; - } -} - -void minerva_main(mtc_config_t *mtc_cfg) -{ - EPRINTF("-- Minerva Training Cell --"); - - train_ram_patterns = mtc_cfg->train_ram_patterns; - fsp_for_src_freq = mtc_cfg->fsp_for_src_freq; - emc_2X_clk_src_is_pllmb = mtc_cfg->emc_2X_clk_src_is_pllmb; - - switch (mtc_cfg->train_mode) - { - case OP_SWITCH: - EPRINTF("Switching.."); - _minerva_set_rate(mtc_cfg); - break; - case OP_TRAIN: - EPRINTF("Training.."); - _minerva_set_rate(mtc_cfg); - break; - case OP_TRAIN_SWITCH: - EPRINTF("Training and switching.."); - _minerva_set_rate(mtc_cfg); - break; - case OP_PERIODIC_TRAIN: - EPRINTF("Periodic training.."); - minerva_do_periodic_compensation(mtc_cfg->current_emc_table); - break; - case OP_TEMP_COMP: - EPRINTF("Over temperature compensation.."); - minerva_do_over_temp_compensation(mtc_cfg); - break; - } - - mtc_cfg->train_ram_patterns = train_ram_patterns; - mtc_cfg->fsp_for_src_freq = fsp_for_src_freq; - mtc_cfg->emc_2X_clk_src_is_pllmb = emc_2X_clk_src_is_pllmb; -} diff --git a/ariane/src/minerva_tc/mtc/mtc.h b/ariane/src/minerva_tc/mtc/mtc.h deleted file mode 100644 index fc9734b..0000000 --- a/ariane/src/minerva_tc/mtc/mtc.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Minerva Training Cell - * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. - * - * Copyright (c) 2018 CTCaer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _MTC_H_ -#define _MTC_H_ - -#include "mtc_table.h" -#include "types.h" - -/* Address bases and access macros - Change these for mapped access */ -#define TMR_BASE 0x60005000 -#define CLOCK_BASE 0x60006000 -#define MC_BASE 0x70019000 -#define EMC_BASE 0x7001B000 -#define EMC0_BASE 0x7001E000 -#define EMC1_BASE 0x7001F000 - -#define _REG(base, off) *(vu32 *)((base) + (off)) - -#define TMR(off) _REG(TMR_BASE, off) -#define CLOCK(off) _REG(CLOCK_BASE, off) -#define MC(off) _REG(MC_BASE, off) -#define EMC(off) _REG(EMC_BASE, off) -#define EMC_CH0(off) _REG(EMC0_BASE, off) -#define EMC_CH1(off) _REG(EMC1_BASE, off) -/* End of addresses and access macros */ - -#define EMC_TABLE_SIZE_R7 49280 -#define EMC_TABLE_ENTRY_SIZE_R7 4928 -#define EMC_STATUS_UPDATE_TIMEOUT 1000 -#define EMC_PERIODIC_TRAIN_MS 100 -#define EMC_TEMP_COMP_MS 1000 - -typedef struct -{ - s32 rate_to; - s32 rate_from; - emc_table_t *mtc_table; - u32 table_entries; - emc_table_t *current_emc_table; - u32 train_mode; - u32 sdram_id; - u32 prev_temp; - bool emc_2X_clk_src_is_pllmb; - bool fsp_for_src_freq; - bool train_ram_patterns; -} mtc_config_t; - -enum train_mode_t -{ - OP_SWITCH = 0, - OP_TRAIN = 1, - OP_TRAIN_SWITCH = 2, - OP_PERIODIC_TRAIN = 3, - OP_TEMP_COMP = 4 -}; - -enum comp_seq_t -{ - DVFS_SEQUENCE = 1, - WRITE_TRAINING_SEQUENCE = 2, - PERIODIC_TRAINING_SEQUENCE = 3 -}; - -enum tree_update_mode_t -{ - DVFS_PT1 = 10, - DVFS_UPDATE = 11, - TRAINING_PT1 = 12, - TRAINING_UPDATE = 13, - PERIODIC_TRAINING_UPDATE = 14 -}; - -enum emc_channels -{ - EMC_CH0 = 0, - EMC_CH1 = 1 -}; - -enum EMC_2X_CLK_SRC -{ - PLLM_OUT0 = 0x0, - PLLC_OUT0 = 0x1, - PLLP_OUT0 = 0x2, - CLK_M = 0x3, - PLLM_UD = 0x4, - PLLMB_UD = 0x5, - PLLMB_OUT0 = 0x6, - PLLP_UD = 0x7 -}; - -enum DRAM_TYPE -{ - DRAM_TYPE_DDR3 = 0, - DRAM_TYPE_LPDDR4 = 1, - DRAM_TYPE_LPDDR2 = 2, - DRAM_TYPE_DDR2 = 3 -}; - -enum DRAM_DEV_NO -{ - ONE_RANK = 1, - TWO_RANK = 2 -}; - -enum DRAM_OVER_TEMP_REF -{ - REFRESH_X2 = 1, - REFRESH_X4 = 2 -}; - -/* Timers for the below two compensation functions should be paused when changing timings. */ - -/* Change refresh rate based on dram temps. Run every 1000ms. */ -/* Timer should be run only when another component reports over temperature. */ -void minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg); - -/* Periodic compensation only for tight timings that need it. Run every 100ms. */ -/* Over temp and periodic compensation, should not access EMC_MRR at the same time. */ -u32 minerva_do_periodic_compensation(emc_table_t *mtc_table_entry); - -/* Main function used to access all Minerva functions. */ -void minerva_main(mtc_config_t *mtc_cfg); - -#endif diff --git a/ariane/src/minerva_tc/mtc/mtc_mc_emc_regs.h b/ariane/src/minerva_tc/mtc/mtc_mc_emc_regs.h deleted file mode 100644 index 735c626..0000000 --- a/ariane/src/minerva_tc/mtc/mtc_mc_emc_regs.h +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Minerva Training Cell - * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. - * - * Copyright (c) 2018 CTCaer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _MTC_MC_EMC_REGS_H_ -#define _MTC_MC_EMC_REGS_H_ - -/* Clock controller registers */ -#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 -#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C -#define PLLM_ENABLE (1 << 30) -#define PLLM_LOCK (1 << 27) - -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C -#define EMC_2X_CLK_SRC_SHIFT 29 - -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 -#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 -#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 -#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE 0x724 - -/* Memory controller registers */ -#define MC_EMEM_ADR_CFG 0x54 -#define MC_EMEM_ARB_CFG 0x90 -#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 -#define MC_EMEM_ARB_TIMING_RCD 0x98 -#define MC_EMEM_ARB_TIMING_RP 0x9C -#define MC_EMEM_ARB_TIMING_RC 0xA0 -#define MC_EMEM_ARB_TIMING_RAS 0xA4 -#define MC_EMEM_ARB_TIMING_FAW 0xA8 -#define MC_EMEM_ARB_TIMING_RRD 0xAC -#define MC_EMEM_ARB_TIMING_RAP2PRE 0xB0 -#define MC_EMEM_ARB_TIMING_WAP2PRE 0xB4 -#define MC_EMEM_ARB_TIMING_R2R 0xB8 -#define MC_EMEM_ARB_TIMING_W2W 0xBC -#define MC_EMEM_ARB_TIMING_R2W 0xC0 -#define MC_EMEM_ARB_TIMING_W2R 0xC4 -#define MC_EMEM_ARB_MISC2 0xC8 -#define MC_EMEM_ARB_DA_TURNS 0xD0 -#define MC_EMEM_ARB_DA_COVERS 0xD4 -#define MC_EMEM_ARB_MISC0 0xD8 -#define MC_EMEM_ARB_MISC1 0xDC -#define MC_EMEM_ARB_RING1_THROTTLE 0xE0 - -#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2E4 -#define MC_LATENCY_ALLOWANCE_HC_0 0x310 -#define MC_LATENCY_ALLOWANCE_HC_1 0x314 -#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320 -#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328 -#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344 -#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348 -#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370 -#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374 -#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37C -#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380 -#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390 -#define MC_LATENCY_ALLOWANCE_VIC_0 0x394 -#define MC_LATENCY_ALLOWANCE_VI2_0 0x398 -#define MC_LATENCY_ALLOWANCE_GPU_0 0x3AC -#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3B8 -#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3BC -#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3C0 -#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3C4 -#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3D8 -#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3E8 - -#define MC_MLL_MPCORER_PTSA_RATE 0x44C -#define MC_FTOP_PTSA_RATE 0x50C - -#define MC_EMEM_ARB_TIMING_RFCPB 0x6C0 -#define MC_EMEM_ARB_TIMING_CCDMW 0x6C4 -#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6F0 -#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6F4 - -#define MC_PTSA_GRANT_DECREMENT 0x960 - -#define MC_EMEM_ARB_DHYST_CTRL 0xBCC -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xBD0 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xBD4 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xBD8 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xBDC -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xBE0 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xBE4 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xBE8 -#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC - -/* External Memory controller registers */ -#define EMC_INTSTATUS 0x0 -#define CLKCHANGE_COMPLETE_INT (1 << 4) - -#define EMC_DBG 0x8 -#define EMC_CFG 0xC -#define EMC_PIN 0x24 -#define EMC_TIMING_CONTROL 0x28 -#define EMC_RC 0x2C -#define EMC_RFC 0x30 -#define EMC_RAS 0x34 -#define EMC_RP 0x38 -#define EMC_R2W 0x3C -#define EMC_W2R 0x40 -#define EMC_R2P 0x44 -#define EMC_W2P 0x48 -#define EMC_RD_RCD 0x4C -#define EMC_WR_RCD 0x50 -#define EMC_RRD 0x54 -#define EMC_REXT 0x58 -#define EMC_WDV 0x5C -#define EMC_QUSE 0x60 -#define EMC_QRST 0x64 -#define EMC_QSAFE 0x68 -#define EMC_RDV 0x6C -#define EMC_REFRESH 0x70 -#define EMC_BURST_REFRESH_NUM 0x74 -#define EMC_PDEX2WR 0x78 -#define EMC_PDEX2RD 0x7C -#define EMC_PCHG2PDEN 0x80 -#define EMC_ACT2PDEN 0x84 -#define EMC_AR2PDEN 0x88 -#define EMC_RW2PDEN 0x8C -#define EMC_TXSR 0x90 -#define EMC_TCKE 0x94 -#define EMC_TFAW 0x98 -#define EMC_TRPAB 0x9C -#define EMC_TCLKSTABLE 0xA0 -#define EMC_TCLKSTOP 0xA4 -#define EMC_TREFBW 0xA8 -#define EMC_TPPD 0xAC -#define EMC_ODT_WRITE 0xB0 -#define EMC_PDEX2MRR 0xB4 -#define EMC_WEXT 0xB8 -#define EMC_RFC_SLR 0xC0 -#define EMC_MRS_WAIT_CNT2 0xC4 -#define EMC_MRS_WAIT_CNT 0xC8 -#define EMC_MRS 0xCC -#define EMC_EMRS 0xD0 -#define EMC_REF 0xD4 -#define EMC_MRW 0xE8 -#define EMC_SELF_REF 0xE0 -#define EMC_MRR 0xEC -#define EMC_FBIO_SPARE 0x100 -#define EMC_FBIO_CFG5 0x104 -#define EMC_PDEX2CKE 0x118 -#define EMC_CKE2PDEN 0x11C -#define EMC_MPC 0x128 -#define EMC_EMRS2 0x12C -#define EMC_MRW2 0x134 -#define EMC_MRW3 0x138 -#define EMC_MRW4 0x13C -#define EMC_R2R 0x144 -#define EMC_EINPUT 0x14C -#define EMC_EINPUT_DURATION 0x150 -#define EMC_PUTERM_EXTRA 0x154 -#define EMC_TCKESR 0x158 -#define EMC_TPD 0x15C -#define EMC_AUTO_CAL_CONFIG 0x2A4 - -#define EMC_EMC_STATUS 0x2B4 -#define TIMING_UPDATE_STALLED (1 << 23) -#define MRR_DIVLD (1 << 20) -#define IN_SELF_REFRESH_MASK (3 << 8) -#define IN_POWERDOWN_MASK (3 << 4) -#define REQ_FIFO_EMPTY (1 << 0) - -#define EMC_CFG_2 0x2B8 -#define EMC_CFG_DIG_DLL 0x2BC -#define EMC_CFG_DIG_DLL_PERIOD 0x2C0 -#define EMC_DIG_DLL_STATUS 0x2C4 -#define EMC_RDV_MASK 0x2CC -#define EMC_WDV_MASK 0x2D0 -#define EMC_RDV_EARLY_MASK 0x2D4 -#define EMC_RDV_EARLY 0x2D8 -#define EMC_AUTO_CAL_CONFIG8 0x2DC -#define EMC_ZCAL_INTERVAL 0x2E0 -#define EMC_ZCAL_WAIT_CNT 0x2E4 -#define EMC_ZQ_CAL 0x2EC -#define EMC_FDPD_CTRL_DQ 0x310 -#define EMC_FDPD_CTRL_CMD 0x314 -#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318 -#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31C -#define EMC_SCRATCH0 0x324 -#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330 -#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334 -#define EMC_TR_TIMING_0 0x3B4 -#define EMC_TR_CTRL_0 0x3B8 -#define EMC_TR_CTRL_1 0x3BC -#define EMC_SWITCH_BACK_CTRL 0x3C0 -#define EMC_TR_RDV 0x3C4 -#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3CC -#define EMC_SEL_DPD_CTRL 0x3D8 -#define EMC_PRE_REFRESH_REQ_CNT 0x3DC -#define EMC_DYN_SELF_REF_CONTROL 0x3E0 -#define EMC_TXSRDLL 0x3E4 -#define EMC_CCFIFO_ADDR 0x3E8 -#define EMC_CCFIFO_DATA 0x3EC -#define EMC_CCFIFO_STATUS 0x3F0 -#define EMC_TR_QPOP 0x3F4 -#define EMC_TR_RDV_MASK 0x3F8 -#define EMC_TR_QSAFE 0x3FC -#define EMC_TR_QRST 0x400 -#define EMC_AUTO_CAL_CONFIG2 0x458 -#define EMC_AUTO_CAL_CONFIG3 0x45C -#define EMC_TR_DVFS 0x460 -#define EMC_AUTO_CAL_CHANNEL 0x464 -#define EMC_IBDLY 0x468 -#define EMC_OBDLY 0x46c -#define EMC_TXDSRVTTGEN 0x480 -#define EMC_WE_DURATION 0x48C -#define EMC_WS_DURATION 0x490 -#define EMC_WEV 0x494 -#define EMC_WSV 0x498 -#define EMC_CFG_3 0x49C -#define EMC_MRW6 0x4A4 -#define EMC_MRW7 0x4A8 -#define EMC_MRW8 0x4AC -#define EMC_MRW14 0x4C4 -#define EMC_MRW15 0x4D0 -#define EMC_CFG_SYNC 0x4D4 -#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4D8 -#define EMC_WDV_CHK 0x4E0 -#define EMC_CFG_PIPE_2 0x554 -#define EMC_CFG_PIPE_CLK 0x558 -#define EMC_CFG_PIPE_1 0x55C -#define EMC_CFG_PIPE 0x560 -#define EMC_QPOP 0x564 -#define EMC_QUSE_WIDTH 0x568 -#define EMC_PUTERM_WIDTH 0x56C -#define EMC_AUTO_CAL_CONFIG7 0x574 -#define EMC_REFCTRL2 0x580 -#define EMC_FBIO_CFG7 0x584 - -#define EMC_DATA_BRLSHFT_0 0x588 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT 0 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT 3 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT 6 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT 9 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT 12 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT 15 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT 18 -#define EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT 21 - -#define EMC_DATA_BRLSHFT_1 0x58C -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT 0 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT 3 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT 6 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT 9 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT 12 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT 15 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT 18 -#define EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT 21 - -#define EMC_RFCPB 0x590 -#define EMC_DQS_BRLSHFT_0 0x594 -#define EMC_DQS_BRLSHFT_1 0x598 -#define EMC_CMD_BRLSHFT_0 0x59C -#define EMC_CMD_BRLSHFT_1 0x5A0 -#define EMC_CMD_BRLSHFT_2 0x5A4 -#define EMC_CMD_BRLSHFT_3 0x5A8 -#define EMC_QUSE_BRLSHFT_0 0x5AC -#define EMC_AUTO_CAL_CONFIG4 0x5B0 -#define EMC_AUTO_CAL_CONFIG5 0x5B4 -#define EMC_QUSE_BRLSHFT_1 0x5B8 -#define EMC_QUSE_BRLSHFT_2 0x5BC -#define EMC_CCDMW 0x5C0 -#define EMC_QUSE_BRLSHFT_3 0x5C4 -#define EMC_AUTO_CAL_CONFIG6 0x5CC -#define EMC_DLL_CFG_0 0x5E4 -#define EMC_DLL_CFG_1 0x5E8 -#define EMC_CONFIG_SAMPLE_DELAY 0x5F0 -#define EMC_CFG_UPDATE 0x5F4 - -#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600 -#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604 -#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608 -#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60C -#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610 -#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614 -#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630 -#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634 -#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620 -#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624 -#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628 -#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62C - -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64C -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66C -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674 - -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68C -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6A0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6A4 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6A8 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6AC -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6B0 -#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6B4 - -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6C0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6C4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6C8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6CC -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6E0 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6E4 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6E8 -#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6EC - -#define EMC_PMACRO_TX_PWRD_0 0x720 -#define EMC_PMACRO_TX_PWRD_1 0x724 -#define EMC_PMACRO_TX_PWRD_2 0x728 -#define EMC_PMACRO_TX_PWRD_3 0x72C -#define EMC_PMACRO_TX_PWRD_4 0x730 -#define EMC_PMACRO_TX_PWRD_5 0x734 - -#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740 -#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744 -#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74C -#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748 -#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750 -#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754 - -#define EMC_PMACRO_DDLL_BYPASS 0x760 -#define EMC_PMACRO_DDLL_PWRD_0 0x770 -#define EMC_PMACRO_DDLL_PWRD_1 0x774 -#define EMC_PMACRO_DDLL_PWRD_2 0x778 - -#define EMC_PMACRO_CMD_CTRL_0 0x780 -#define EMC_PMACRO_CMD_CTRL_1 0x784 -#define EMC_PMACRO_CMD_CTRL_2 0x788 - -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87C - -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8A0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8A4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8A8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8AC -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8B0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8B4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8B8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8BC - -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97C - -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99C -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9A0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9A4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9A8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9AC -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9B0 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9B4 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9B8 -#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9BC - -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xA00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xA04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xA08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xA10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xA14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xA18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xA20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xA24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xA28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xA30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xA34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xA38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xA40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xA44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xA48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xA50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xA54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xA58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xA60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xA64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xA68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xA70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xA74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xA78 - -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xB00 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xB04 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xB08 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xB10 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xB14 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xB18 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xB20 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xB24 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xB28 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xB30 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xB34 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xB38 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xB40 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xB44 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xB48 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xB50 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xB54 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xB58 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xB60 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xB64 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xB68 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xB70 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xB74 -#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xB78 - -#define EMC_PMACRO_IB_VREF_DQ_0 0xBE0 -#define EMC_PMACRO_IB_VREF_DQ_1 0xBE4 -#define EMC_PMACRO_IB_VREF_DQS_0 0xBF0 -#define EMC_PMACRO_IB_VREF_DQS_1 0xBF4 - -#define EMC_PMACRO_DDLL_LONG_CMD_0 0xC00 -#define EMC_PMACRO_DDLL_LONG_CMD_1 0xC04 -#define EMC_PMACRO_DDLL_LONG_CMD_2 0xC08 -#define EMC_PMACRO_DDLL_LONG_CMD_3 0xC0C -#define EMC_PMACRO_DDLL_LONG_CMD_4 0xC10 - -#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xC20 -#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xC24 -#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xC28 - -#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xC30 -#define EMC_PMACRO_VTTGEN_CTRL_0 0xC34 -#define EMC_PMACRO_VTTGEN_CTRL_1 0xC38 -#define EMC_PMACRO_BG_BIAS_CTRL_0 0xC3C -#define EMC_PMACRO_PAD_CFG_CTRL 0xC40 -#define EMC_PMACRO_ZCTRL 0xC44 -#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xC50 -#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xC54 -#define EMC_PMACRO_CMD_RX_TERM_MODE 0xC58 -#define EMC_PMACRO_DATA_RX_TERM_MODE 0xC5C -#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xC60 -#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xC64 -#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xC68 -#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xC78 -#define EMC_PMACRO_VTTGEN_CTRL_2 0xCF0 -#define EMC_PMACRO_IB_RXRT 0xCF4 -#define EMC_PMACRO_TRAINING_CTRL_0 0xCF8 -#define CH0_TRAINING_E_WRPTR (1 << 3) -#define EMC_PMACRO_TRAINING_CTRL_1 0xCFC - -#define EMC_TRAINING_CMD 0xE00 -#define EMC_TRAINING_CTRL 0xE04 -#define EMC_TRAINING_STATUS 0xE08 -#define EMC_TRAINING_QUSE_CORS_CTRL 0xE0C -#define EMC_TRAINING_QUSE_FINE_CTRL 0xE10 -#define EMC_TRAINING_QUSE_CTRL_MISC 0xE14 -#define EMC_TRAINING_WRITE_FINE_CTRL 0xE18 -#define EMC_TRAINING_WRITE_CTRL_MISC 0xE1C -#define EMC_TRAINING_WRITE_VREF_CTRL 0xE20 -#define EMC_TRAINING_READ_FINE_CTRL 0xE24 -#define EMC_TRAINING_READ_CTRL_MISC 0xE28 -#define EMC_TRAINING_READ_VREF_CTRL 0xE2C -#define EMC_TRAINING_CA_FINE_CTRL 0xE30 -#define EMC_TRAINING_CA_CTRL_MISC 0xE34 -#define EMC_TRAINING_CA_CTRL_MISC1 0xE38 -#define EMC_TRAINING_CA_VREF_CTRL 0xE3C -#define EMC_TRAINING_SETTLE 0xE44 -#define EMC_TRAINING_MPC 0xE5C -#define EMC_TRAINING_PATRAM_CTRL 0xE60 -#define EMC_TRAINING_PATRAM_DQ 0xE64 -#define EMC_TRAINING_PATRAM_DMI 0xE68 -#define EMC_TRAINING_VREF_SETTLE 0xE6C -#define EMC_TRAINING_OPT_CA_VREF 0xEC0 -#define EMC_TRAINING_OPT_DQ_OB_VREF 0xEC4 -#define EMC_TRAINING_QUSE_VREF_CTRL 0xED0 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xED4 -#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xED8 - -/* Per channel registers offsets. Should be used with EMC_BASE */ -#define EMC0_MRW10 0x34B4 -#define EMC0_MRW11 0x34B8 -#define EMC0_MRW12 0x34BC -#define EMC0_MRW13 0x34C0 -#define EMC0_DATA_BRLSHFT_0 0x3588 -#define EMC0_DATA_BRLSHFT_1 0x358C -#define EMC0_CMD_BRLSHFT_0 0x359C -#define EMC0_QUSE_BRLSHFT_0 0x35AC -#define EMC0_QUSE_BRLSHFT_2 0x35BC -#define EMC0_TRAINING_RW_OFFSET_IB_BYTE0 0x3E98 -#define EMC0_TRAINING_RW_OFFSET_IB_BYTE1 0x3E9C -#define EMC0_TRAINING_RW_OFFSET_IB_BYTE2 0x3EA0 -#define EMC0_TRAINING_RW_OFFSET_IB_BYTE3 0x3EA4 -#define EMC0_TRAINING_RW_OFFSET_IB_MISC 0x3EA8 -#define EMC0_TRAINING_RW_OFFSET_OB_BYTE0 0x3EAC -#define EMC0_TRAINING_RW_OFFSET_OB_BYTE1 0x3EB0 -#define EMC0_TRAINING_RW_OFFSET_OB_BYTE2 0x3EB4 -#define EMC0_TRAINING_RW_OFFSET_OB_BYTE3 0x3EB8 -#define EMC0_TRAINING_RW_OFFSET_OB_MISC 0x3EBC -#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK0 0x3ED4 -#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK1 0x3ED8 - -#define EMC1_MRW10 0x44B4 -#define EMC1_MRW11 0x44B8 -#define EMC1_MRW12 0x44BC -#define EMC1_MRW13 0x44C0 -#define EMC1_DATA_BRLSHFT_0 0x4588 -#define EMC1_DATA_BRLSHFT_1 0x458C -#define EMC1_CMD_BRLSHFT_1 0x45A0 -#define EMC1_QUSE_BRLSHFT_1 0x45B8 -#define EMC1_QUSE_BRLSHFT_3 0x45C4 -#define EMC1_TRAINING_RW_OFFSET_IB_BYTE0 0x4E98 -#define EMC1_TRAINING_RW_OFFSET_IB_BYTE1 0x4E9C -#define EMC1_TRAINING_RW_OFFSET_IB_BYTE2 0x4EA0 -#define EMC1_TRAINING_RW_OFFSET_IB_BYTE3 0x4EA4 -#define EMC1_TRAINING_RW_OFFSET_IB_MISC 0x4EA8 -#define EMC1_TRAINING_RW_OFFSET_OB_BYTE0 0x4EAC -#define EMC1_TRAINING_RW_OFFSET_OB_BYTE1 0x4EB0 -#define EMC1_TRAINING_RW_OFFSET_OB_BYTE2 0x4EB4 -#define EMC1_TRAINING_RW_OFFSET_OB_BYTE3 0x4EB8 -#define EMC1_TRAINING_RW_OFFSET_OB_MISC 0x4EBC -#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK0 0x4ED4 -#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK1 0x4ED8 - -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE0_SHIFT 0 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE1_SHIFT 16 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE2_SHIFT 0 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE3_SHIFT 16 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE4_SHIFT 0 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE5_SHIFT 16 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE6_SHIFT 0 -#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE7_SHIFT 16 - -#endif diff --git a/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram0_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin b/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram0_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin deleted file mode 100644 index 6fef58d94d80e668abcd8dc9f79059062b0a7f4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49280 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 diff --git a/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram1_nx_abca2_2_0_10NoCfgVersion_V9.8.7_V1.6.bin b/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram1_nx_abca2_2_0_10NoCfgVersion_V9.8.7_V1.6.bin deleted file mode 100644 index 0d054b419f9574af90828050f90e773d55292363..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49280 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 diff --git a/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram2_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin b/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram2_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin deleted file mode 100644 index 6fef58d94d80e668abcd8dc9f79059062b0a7f4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49280 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 diff --git a/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram3_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin b/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram3_nx_abca2_0_3_10NoCfgVersion_V9.8.7_V1.6.bin deleted file mode 100644 index 6fef58d94d80e668abcd8dc9f79059062b0a7f4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49280 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 diff --git a/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram4_nx_abca2_1_0_10NoCfgVersion_V9.8.7_V1.6.bin b/ariane/src/minerva_tc/mtc_tables/nintendo_switch/sdram4_nx_abca2_1_0_10NoCfgVersion_V9.8.7_V1.6.bin deleted file mode 100644 index 6fef58d94d80e668abcd8dc9f79059062b0a7f4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49280 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 diff --git a/ariane/src/panic_color.h b/ariane/src/panic_color.h deleted file mode 100644 index a310b13..0000000 --- a/ariane/src/panic_color.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef EXOSPHERE_PANIC_COLOR_H -#define EXOSPHERE_PANIC_COLOR_H - -#define COLOR_0 0x00F00003 -#define COLOR_1 0x0F000003 -#define COLOR_2 0xF0000003 -#define COLOR_3 0x0FF00003 -#define COLOR_4 0xF0F00003 -#define COLOR_5 0xFF000003 -#define COLOR_6 0xFFF00003 -#define COLOR_7 0xAAF00003 -#define COLOR_8 0xAFA00003 -#define COLOR_9 0xFAA00003 -#define COLOR_A 0x33300003 -#define COLOR_B 0x06F00003 -#define COLOR_C 0x14800003 -#define COLOR_D 0x00300003 -#define COLOR_E 0x03000003 -#define COLOR_F 0xB6000003 - -#define PANIC_REBOOT 0x20 - -#endif \ No newline at end of file diff --git a/ariane/src/rcm_usb.c b/ariane/src/rcm_usb.c index 7203646..62e1e49 100644 --- a/ariane/src/rcm_usb.c +++ b/ariane/src/rcm_usb.c @@ -20,7 +20,7 @@ static const struct { int (*usb_device_write_ep1_in_sync)(const unsigned char* buf, unsigned int len, unsigned int* outTransferred); //0 on success, len clamped at 4096 int (*usb_device_reset_ep1)(void); //returns 0 -} *rcm_transport = (void*)0x40003114; +} *rcm_transport = (void*)0x40003114; bool rcm_usb_device_ready() { @@ -50,9 +50,9 @@ void rcm_usb_device_reset_ep1(void) rcm_transport->usb_device_reset_ep1(); } -static const char READY_NOTICE[] = "READY.\n"; +//static const unsigned char READY_NOTICE[] = "READY.\n"; void rcm_ready_notice() { unsigned int b; - rcm_usb_device_write_ep1_in_sync(READY_NOTICE, 7, &b); -} \ No newline at end of file + rcm_usb_device_write_ep1_in_sync((const unsigned char*)"READY.\n", 7, &b); +} diff --git a/ariane/src/rcm_usb.h b/ariane/src/rcm_usb.h index 2d79640..75ad711 100644 --- a/ariane/src/rcm_usb.h +++ b/ariane/src/rcm_usb.h @@ -9,4 +9,4 @@ int rcm_usb_device_write_ep1_in_sync(const unsigned char* buf, unsigned int len, void rcm_usb_device_reset_ep1(void); void rcm_ready_notice(); -#endif \ No newline at end of file +#endif diff --git a/ariane/src/start.s b/ariane/src/start.s index 91b5282..269f2c7 100644 --- a/ariane/src/start.s +++ b/ariane/src/start.s @@ -1,72 +1,77 @@ -.macro CLEAR_GPR_REG_ITER - mov r\@, #0 -.endm +/* +* Copyright (c) 2018 naehrwert +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ -.section .text.start +.section .text._start .arm -.align 5 -.global _start + +.extern _reloc_ipl +.type _reloc_ipl, %function + +.extern memset +.type memset, %function + +.extern _irq_setup +.type _irq_setup, %function + +.globl _start +.type _start, %function _start: - /* Insert NOPs for convenience (i.e. to use Nintendo's BCTs, for example) */ - .rept 16 - nop - .endr - /* Switch to supervisor mode, mask all interrupts, clear all flags */ - msr cpsr_cxsf, #0xDF + ADR R0, _start + LDR R1, =__ipl_start + CMP R0, R1 + BEQ _real_start - /* Relocate ourselves if necessary */ - ldr r0, =__start__ - adr r1, _start - cmp r0, r1 - beq _after_relocation + /* If we are not in the right location already, copy a relocator to upper IRAM. */ + ADR R2, _reloc_ipl + LDR R3, =0x4003FF00 + MOV R4, #(_real_start - _reloc_ipl) +_copy_loop: + LDMIA R2!, {R5} + STMIA R3!, {R5} + SUBS R4, #4 + BNE _copy_loop - adr r2, _relocator - ldr r3, =__stack - adr r4, _relocator_end - mov r12, r3 - _copy_relocator_loop: - ldr r5, [r2], #4 - str r5, [r3], #4 - cmp r2, r4 - bne _copy_relocator_loop + /* Use the relocator to copy ourselves into the right place. */ + LDR R2, =__ipl_end + SUB R2, R2, R1 + LDR R3, =_real_start + LDR R4, =0x4003FF00 + BX R4 - ldr r2, =__bss_start__ - sub r2, r2, r0 - bx r12 +_reloc_ipl: + LDMIA R0!, {R4-R7} + STMIA R1!, {R4-R7} + SUBS R2, #0x10 + BNE _reloc_ipl + /* Jump to the relocated entry. */ + BX R3 - _after_relocation: - /* Set the stack pointer */ - ldr sp, =__stack - mov fp, #0 +_real_start: + /* Initially, we place our stack in IRAM but will move it to SDRAM later. */ + LDR SP, =0x4003FF00 + LDR R0, =__bss_start + EOR R1, R1, R1 + LDR R2, =__bss_end + SUB R2, R2, R0 + BL memset + BL _irq_setup + B . - /* Clear .bss */ - ldr r0, =__bss_start__ - mov r1, #0 - ldr r2, =__bss_end__ - sub r2, r2, r0 - bl memset - - /* Call global constructors */ - bl __libc_init_array - - /* Set r0 to r12 to 0 (because why not?) & call main */ - .rept 13 - CLEAR_GPR_REG_ITER - .endr - bl main - b . -_relocator: - mov r12, r0 - _relocation_loop: - ldmia r1!, {r3-r10} - stmia r0!, {r3-r10} - subs r2, #0x20 - bne _relocation_loop - bx r12 -_relocator_end: - b . .globl pivot_stack .type pivot_stack, %function pivot_stack: MOV SP, R0 - BX LR \ No newline at end of file + BX LR diff --git a/ariane/src/storage.c b/ariane/src/storage.c deleted file mode 100644 index 9043dc7..0000000 --- a/ariane/src/storage.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "storage.h" -#include "lib/ffconf.h" - -sdmmc_t* get_controller_for_index(u8 pdrv) -{ - static sdmmc_t controllers[FF_VOLUMES] = {0}; - if (pdrv >= FF_VOLUMES) - return NULL; - - return &controllers[pdrv]; -} - -sdmmc_storage_t* get_storage_for_index(u8 pdrv) -{ - static sdmmc_storage_t storages[FF_VOLUMES] = {0}; - if (pdrv >= FF_VOLUMES) - return NULL; - - return &storages[pdrv]; -} \ No newline at end of file diff --git a/ariane/src/storage.h b/ariane/src/storage.h deleted file mode 100644 index 14c60cc..0000000 --- a/ariane/src/storage.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _STORAGE_H_ -#define _STORAGE_H_ - -#include "hwinit/sdmmc.h" - -sdmmc_t* get_controller_for_index(u8 pdrv); -sdmmc_storage_t* get_storage_for_index(u8 pdrv); - -#endif \ No newline at end of file diff --git a/ariane/src/storage/emummc.c b/ariane/src/storage/emummc.c new file mode 100644 index 0000000..5751e7c --- /dev/null +++ b/ariane/src/storage/emummc.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "emummc.h" +#include +#include "../libs/hekate_config.h" +#include +#include +#include +#include +#include "../storage/nx_emmc.h" +#include +#include +#include +#include "../gfx/gfx.h" + +extern hekate_config h_cfg; +extern emummc_cfg_t emu_cfg; + +void emummc_load_cfg() +{ + emu_cfg.enabled = 0; + emu_cfg.path = NULL; + emu_cfg.sector = 0; + emu_cfg.id = 0; + emu_cfg.file_based_part_size = 0; + emu_cfg.active_part = 0; + emu_cfg.fs_ver = 0; + if (!emu_cfg.nintendo_path) + emu_cfg.nintendo_path = (char *)malloc(0x80); + if (!emu_cfg.emummc_file_based_path) + emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + + emu_cfg.nintendo_path[0] = 0; + emu_cfg.emummc_file_based_path[0] = 0; + + LIST_INIT(ini_sections); + if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (ini_sec->type == INI_CHOICE) + { + if (strcmp(ini_sec->name, "emummc")) + continue; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("enabled", kv->key)) + emu_cfg.enabled = atoi(kv->val); + else if (!strcmp("sector", kv->key)) + emu_cfg.sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_cfg.id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + emu_cfg.path = kv->val; + else if (!strcmp("nintendo_path", kv->key)) + strcpy(emu_cfg.nintendo_path, kv->val); + } + break; + } + } + } +} + +bool emummc_set_path(char *path) +{ + FIL fp; + bool found = false; + + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/raw_based"); + + if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + if (!f_read(&fp, &emu_cfg.sector, 4, NULL)) + if (emu_cfg.sector) + found = true; + } + else + { + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/file_based"); + + if (!f_stat(emu_cfg.emummc_file_based_path, NULL)) + { + emu_cfg.sector = 0; + emu_cfg.path = path; + + found = true; + } + } + + if (found) + { + emu_cfg.enabled = 1; + emu_cfg.id = 0; + strcpy(emu_cfg.nintendo_path, path); + strcat(emu_cfg.nintendo_path, "/Nintendo"); + } + + return found; +} + +static int emummc_raw_get_part_off(int part_idx) +{ + switch (part_idx) + { + case 0: + return 2; + case 1: + return 0; + case 2: + return 1; + } + return 2; +} + +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +{ + FILINFO fno; + emu_cfg.active_part = 0; + + // Always init eMMC even when in emuMMC. eMMC is needed from theh emuMMC driver anyway. + if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400)) + return 2; + + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return 0; + + if (!sd_mount()) + goto out; + + if (!emu_cfg.sector) + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + gfx_printf("Failed to open eMMC folder."); + goto out; + } + f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC); + + strcat(emu_cfg.emummc_file_based_path, "/00"); + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + gfx_printf("Failed to open emuMMC rawnand."); + goto out; + } + emu_cfg.file_based_part_size = fno.fsize >> 9; + } + + return 0; + +out: + return 1; +} + +int emummc_storage_end(sdmmc_storage_t *storage) +{ + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + sdmmc_storage_end(storage); + else + sd_end(); + + return 1; +} + +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_read(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + EPRINTF("Failed to open emuMMC image."); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_read(&fp, buf, (u64)num_sectors << 9, NULL)) + { + EPRINTF("Failed to read emuMMC image."); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } + + return 1; +} + +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_write(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE)) + { + gfx_printf("e5\n"); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_write(&fp, buf, (u64)num_sectors << 9, NULL)) + { + gfx_printf("e6\n"); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } +} + +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +{ + emu_cfg.active_part = partition; + + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + sdmmc_storage_set_mmc_partition(storage, partition); + else if (emu_cfg.sector) + return 1; + else + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + switch (partition) + { + case 0: + strcat(emu_cfg.emummc_file_based_path, "/00"); + break; + case 1: + strcat(emu_cfg.emummc_file_based_path, "/BOOT0"); + break; + case 2: + strcat(emu_cfg.emummc_file_based_path, "/BOOT1"); + break; + } + + return 1; + } + + return 1; +} + +int emummc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) +{ + + // The last LBA is inclusive. + if (part->lba_start + sector_off > part->lba_end) + return 0; + + return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); +} diff --git a/ariane/src/storage/emummc.h b/ariane/src/storage/emummc.h new file mode 100644 index 0000000..e8c8867 --- /dev/null +++ b/ariane/src/storage/emummc.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EMUMMC_H +#define EMUMMC_H + +#include +#include +#include "nx_emmc.h" + +typedef enum +{ + EMUMMC_TYPE_NONE = 0, + EMUMMC_TYPE_PARTITION = 1, + EMUMMC_TYPE_FILES = 2, +} emummc_type_t; + +typedef enum { + EMUMMC_MMC_NAND = 0, + EMUMMC_MMC_SD = 1, + EMUMMC_MMC_GC = 2, +} emummc_mmc_t; + +typedef struct _emummc_cfg_t +{ + int enabled; + u64 sector; + u16 id; + char *path; + char *nintendo_path; + // Internal. + char *emummc_file_based_path; + u32 file_based_part_size; + u32 active_part; + int fs_ver; +} emummc_cfg_t; + +extern emummc_cfg_t emu_cfg; + +void emummc_load_cfg(); +bool emummc_set_path(char *path); +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); +int emummc_storage_end(sdmmc_storage_t *storage); +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +int emummc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); + +#endif diff --git a/ariane/src/storage/nx_emmc.c b/ariane/src/storage/nx_emmc.c new file mode 100644 index 0000000..fa36e59 --- /dev/null +++ b/ariane/src/storage/nx_emmc.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include "nx_emmc.h" +#include +#include + +sdmmc_t emmc_sdmmc; +sdmmc_storage_t emmc_storage; +FATFS emmc_fs; + +void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) +{ + gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE); + + sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf); + + for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++) + { + emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1); + + if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba) + continue; + + part->index = i; + part->lba_start = gpt_buf->entries[i].lba_start; + part->lba_end = gpt_buf->entries[i].lba_end; + part->attrs = gpt_buf->entries[i].attrs; + + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. + for (u32 j = 0; j < 36; j++) + part->name[j] = gpt_buf->entries[i].name[j]; + part->name[35] = 0; + + list_append(gpt, &part->link); + } + + free(gpt_buf); +} + +void nx_emmc_gpt_free(link_t *gpt) +{ + LIST_FOREACH_SAFE(iter, gpt) + free(CONTAINER_OF(iter, emmc_part_t, link)); +} + +emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name) +{ + LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link) + if (!strcmp(part->name, name)) + return part; + return NULL; +} + +int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) +{ + // The last LBA is inclusive. + if (part->lba_start + sector_off > part->lba_end) + return 0; + return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); +} + +int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) +{ + // The last LBA is inclusive. + if (part->lba_start + sector_off > part->lba_end) + return 0; + return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf); +} diff --git a/ariane/src/storage/nx_emmc.h b/ariane/src/storage/nx_emmc.h new file mode 100644 index 0000000..5db6a1f --- /dev/null +++ b/ariane/src/storage/nx_emmc.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _NX_EMMC_H_ +#define _NX_EMMC_H_ + +#include +#include +#include +#include + +#define NX_GPT_FIRST_LBA 1 +#define NX_GPT_NUM_BLOCKS 33 +#define NX_EMMC_BLOCKSIZE 512 + +typedef struct _emmc_part_t +{ + u32 index; + u32 lba_start; + u32 lba_end; + u64 attrs; + char name[37]; + link_t link; +} emmc_part_t; + +extern sdmmc_t emmc_sdmmc; +extern sdmmc_storage_t emmc_storage; +extern FATFS emmc_fs; + +void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage); +void nx_emmc_gpt_free(link_t *gpt); +emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name); +int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); +int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); + +#endif diff --git a/ariane/src/storage/nx_emmc_bis.c b/ariane/src/storage/nx_emmc_bis.c new file mode 100644 index 0000000..63b19cc --- /dev/null +++ b/ariane/src/storage/nx_emmc_bis.c @@ -0,0 +1,232 @@ +/* + * eMMC BIS driver for Nintendo Switch + * + * Copyright (c) 2019 shchmue + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "../storage/nx_emmc.h" +#include "../libs/hekate_config.h" +#include +#include +#include "emummc.h" +#include "../gfx/gfx.h" + +extern hekate_config h_cfg; +extern emummc_cfg_t emu_cfg; + +#define MAX_SEC_CACHE_ENTRIES 1500 + +typedef struct _sector_cache_t +{ + u32 sector; + u32 visit_cnt; + u8 tweak[0x10]; + u8 data[0x200]; + u8 align[8]; +} sector_cache_t; + +static u8 ks_crypt = 0; +static u8 ks_tweak = 0; +static u32 sector_cache_cnt = 0; +static emmc_part_t *system_part = NULL; +static sector_cache_t *sector_cache = (sector_cache_t *)NX_BIS_CACHE_ADDR; + +static void _gf256_mul_x_le(u8 *block) +{ + u8 *pdata = (u8 *)block; + u32 carry = 0; + + for (u32 i = 0; i < 0x10; i++) + { + u8 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 7; + } + + if (carry) + pdata[0x0] ^= 0x87; +} + +static int _nx_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 sec_size) +{ + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + if (regen_tweak) + { + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) + return 0; + } + + for (u32 i = 0; i < (tweak_exp << 5); i++) + _gf256_mul_x_le(tweak); + + u8 tmp_tweak[0x10]; + memcpy(tmp_tweak, tweak, 0x10); + + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = psrc[j] ^ tweak[j]; + + _gf256_mul_x_le(tweak); + psrc += 0x10; + pdst += 0x10; + } + + se_aes_crypt_ecb(ks2, enc, dst, sec_size, src, sec_size); + + memcpy(tweak, tmp_tweak, 0x10); + + pdst = (u8 *)dst; + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = pdst[j] ^ tweak[j]; + + _gf256_mul_x_le(tweak); + pdst += 0x10; + } + + return 1; +} + +static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) +{ + if (!system_part) + return 3; // Not ready. + + static u32 prev_cluster = -1; + static u32 prev_sector = 0; + static u8 tweak[0x10]; + + u32 cache_idx = 0; + u32 tweak_exp = 0; + bool regen_tweak = true; + bool cache_sector = false; + + if (count == 1) + { + for ( ; cache_idx < sector_cache_cnt; cache_idx++) + { + if (sector_cache[cache_idx].sector == sector) + { + sector_cache[cache_idx].visit_cnt++; + memcpy(buff, sector_cache[cache_idx].data, 0x200); + memcpy(tweak, sector_cache[cache_idx].tweak, 0x10); + prev_sector = sector; + prev_cluster = sector >> 5; + + return 0; + } + } + // add to cache + if (cache_idx == sector_cache_cnt && cache_idx < MAX_SEC_CACHE_ENTRIES) + { + sector_cache[cache_idx].sector = sector; + sector_cache[cache_idx].visit_cnt++; + cache_sector = true; + sector_cache_cnt++; + } + } + + //if (nx_emmc_part_read(&emmc_storage, system_part, sector, count, buff)) + int res = emu_cfg.enabled && !h_cfg.emummc_force_disable ? emummc_part_read(&emmc_storage, system_part, sector, count, buff) : nx_emmc_part_read(&emmc_storage, system_part, sector, count, buff); + if (res) + { + if (prev_cluster != sector >> 5) // Sector in different cluster than last read. + { + prev_cluster = sector >> 5; + tweak_exp = sector % 0x20; + } + else if (sector > prev_sector) // Sector in same cluster and past last sector. + { + tweak_exp = sector - prev_sector - 1; + regen_tweak = false; + } + else // Sector in same cluster and before or same as last sector. + tweak_exp = sector % 0x20; + + // Maximum one cluster (1 XTS crypto block 16KB). + _nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count << 9); + if (cache_sector) + { + memcpy(sector_cache[cache_idx].data, buff, 0x200); + memcpy(sector_cache[cache_idx].tweak, tweak, 0x10); + } + prev_sector = sector + count - 1; + + return 0; + } + + // Error occurred. + return 1; +} + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff) +{ + int res = 1; + u8 *buf = (u8 *)buff; + u32 curr_sct = sector; + + while (count) + { + u32 sct_cnt = MIN(count, 0x20); + res = nx_emmc_bis_read_block(curr_sct, sct_cnt, buf); + if (res) + return 1; + + count -= sct_cnt; + curr_sct += sct_cnt; + buf += 512 * sct_cnt; + } + + return res; +} + +void nx_emmc_bis_init(emmc_part_t *part) +{ + + system_part = part; + sector_cache_cnt = 0; + + switch (part->index) + { + case 0: // PRODINFO. + case 1: // PRODINFOF. + ks_crypt = 0; + ks_tweak = 1; + break; + case 8: // SAFE. + ks_crypt = 2; + ks_tweak = 3; + break; + case 9: // SYSTEM. + case 10: // USER. + ks_crypt = 4; + ks_tweak = 5; + break; + } +} diff --git a/ariane/src/storage/nx_emmc_bis.h b/ariane/src/storage/nx_emmc_bis.h new file mode 100644 index 0000000..70ec895 --- /dev/null +++ b/ariane/src/storage/nx_emmc_bis.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2019 shchmue + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NX_EMMC_BIS_H +#define NX_EMMC_BIS_H + +#include "../storage/nx_emmc.h" +#include + +typedef struct _nx_emmc_cal0_spk_t +{ + u16 unk0; + u16 unk1; + u16 eq_bw_lop; + u16 eq_gn_lop; + u16 eq_fc_bp1; + u16 eq_bw_bp1; + u16 eq_gn_bp1; + u16 eq_fc_bp2; + u16 eq_bw_bp2; + u16 eq_gn_bp2; + u16 eq_fc_bp3; + u16 eq_bw_bp3; + u16 eq_gn_bp3; + u16 eq_fc_bp4; + u16 eq_bw_bp4; + u16 eq_gn_bp4; + u16 eq_fc_hip1; + u16 eq_gn_hip1; + u16 eq_fc_hip2; + u16 eq_bw_hip2; + u16 eq_gn_hip2; + u16 eq_pre_vol; + u16 eq_pst_vol; + u16 eq_ctrl2; + u16 eq_ctrl1; + u16 drc_agc_2; + u16 drc_agc_3; + u16 drc_agc_1; + u16 spk_vol; + u16 hp_vol; + u16 dac1_min_vol_spk; + u16 dac1_max_vol_spk; + u16 dac1_min_vol_hp; + u16 dac1_max_vol_hp; + u16 in1_in2; + u16 adc_vol_min; + u16 adc_vol_max; + u8 unk4[16]; +} __attribute__((packed)) nx_emmc_cal0_spk_t; + +typedef struct _nx_emmc_cal0_t +{ + u32 magic; // 'CAL0'. + u32 version; + u32 body_size; + u16 model; + u16 update_cnt; + u8 pad_crc16_0[0x10]; + u8 body_sha256[0x20]; + char cfg_id1[0x1E]; + u8 crc16_pad1[2]; + u8 rsvd0[0x20]; + u32 wlan_cc_num; + u32 wlan_cc_last; + char wlan_cc[128][3]; + u8 crc16_pad2[8]; + u8 wlan_mac[6]; + u8 crc16_pad3[2]; + u8 rsvd1[8]; + u8 bd_mac[6]; + u8 crc16_pad4[2]; + u8 rsvd2[8]; + u8 acc_offset[6]; + u8 crc16_pad5[2]; + u8 acc_scale[6]; + u8 crc16_pad6[2]; + u8 gyro_offset[6]; + u8 crc16_pad7[2]; + u8 gyro_scale[6]; + u8 crc16_pad8[2]; + char serial_number[0x18]; + u8 crc16_pad9[8]; + + u8 ecc_p256_device_key[0x30]; + u8 crc16_pad10[0x10]; + u8 ecc_p256_device_cert[0x180]; + u8 crc16_pad11[0x10]; + u8 ecc_p233_device_key[0x30]; + u8 crc16_pad12[0x10]; + u8 ecc_p33_device_cert[0x180]; + u8 crc16_pad13[0x10]; + u8 ecc_p256_ticket_key[0x30]; + u8 crc16_pad14[0x10]; + u8 ecc_p256_ticket_cert[0x180]; + u8 crc16_pad15[0x10]; + u8 ecc_p233_ticket_key[0x30]; + u8 crc16_pad16[0x10]; + u8 ecc_p33_ticket_cert[0x180]; + u8 crc16_pad17[0x10]; + u8 ssl_key[0x110]; + u8 crc16_pad18[0x10]; + u32 ssl_cert_size; + u8 crc16_pad19[0xC]; + u8 ssl_cert[0x800]; + u8 ssl_sha256[0x20]; + u8 random_number[0x1000]; + u8 random_number_sha256[0x20]; + u8 gc_key[0x110]; + u8 crc16_pad20[0x10]; + u8 gc_cert[0x400]; + u8 gc_cert_sha256[0x20]; + u8 rsa2048_eticket_key[0x220]; + u8 crc16_pad21[0x10]; + u8 rsa2048_eticket_cert[0x240]; + u8 crc16_pad22[0x10]; + + char battery_lot[0x1E]; + u8 crc16_pad23[2]; + nx_emmc_cal0_spk_t spk_cal; + u8 spk_cal_rsvd[0x800 - sizeof(nx_emmc_cal0_spk_t)]; + u8 crc16_pad24[0x10]; + u32 region_code; + u8 crc16_pad25[0xC]; + + u8 amiibo_key[0x50]; + u8 crc16_pad26[0x10]; + u8 amiibo_ecqv_cert[0x14]; + u8 crc16_pad27[0xC]; + u8 amiibo_ecqdsa_cert[0x70]; + u8 crc16_pad28[0x10]; + u8 amiibo_ecqv_bls_key[0x40]; + u8 crc16_pad29[0x10]; + u8 amiibo_ecqv_bls_cert[0x20]; + u8 crc16_pad30[0x10]; + u8 amiibo_ecqv_bls_root_cert[0x90]; + u8 crc16_pad31[0x10]; + + u32 product_model; // 1: Nx, 2: Copper, 4: Hoag. + u8 crc16_pad32[0xC]; + u8 home_menu_scheme_main_color[6]; + u8 crc16_pad33[0xA]; + u32 lcd_bl_brightness_mapping[3]; // Floats. Normally 100%, 0% and 2%. + u8 crc16_pad34[0x4]; + + u8 ext_ecc_b233_device_key[0x50]; + u8 crc16_pad35[0x10]; + u8 ext_ecc_p256_eticket_key[0x50]; + u8 crc16_pad36[0x10]; + u8 ext_ecc_b233_eticket_key[0x50]; + u8 crc16_pad37[0x10]; + u8 ext_ecc_rsa2048_eticket_key[0x240]; + u8 crc16_pad38[0x10]; + u8 ext_ssl_key[0x130]; + u8 crc16_pad39[0x10]; + u8 ext_gc_key[0x130]; + u8 crc16_pad40[0x10]; + + u32 lcd_vendor; + u8 crc16_pad41[0xC]; + + // 5.0.0 and up. + u8 ext_rsa2048_device_key[0x240]; + u8 crc16_pad42[0x10]; + u8 rsa2048_device_cert[0x240]; + u8 crc16_pad43[0x10]; + + u8 usbc_pwr_src_circuit_ver; + u8 crc16_pad44[0xF]; + + // 9.0.0 and up. + u32 home_menu_scheme_sub_color; + u8 crc16_pad45[0xC]; + u32 home_menu_scheme_bezel_color; + u8 crc16_pad46[0xC]; + u32 home_menu_scheme_main_color1; + u8 crc16_pad47[0xC]; + u32 home_menu_scheme_main_color2; + u8 crc16_pad48[0xC]; + u32 home_menu_scheme_main_color3; + u8 crc16_pad49[0xC]; + + u8 analog_stick_type_l; + u8 crc16_pad50[0xF]; + u8 analog_stick_param_l[0x12]; + u8 crc16_pad51[0xE]; + u8 analog_stick_cal_l[0x9]; + u8 crc16_pad52[0x7]; + u8 analog_stick_type_r; + u8 crc16_pad53[0xF]; + u8 analog_stick_param_r[0x12]; + u8 crc16_pad54[0xE]; + u8 analog_stick_cal_r[0x9]; + u8 crc16_pad55[0x7]; + u8 console_6axis_sensor_type; + u8 crc16_pad56[0xF]; + u8 console_6axis_sensor_hor_off[0x6]; + u8 crc16_pad57[0xA]; + + // 6.0.0 and up. + u8 battery_ver; + u8 crc16_pad58[0x1F]; + + // 9.0.0 and up. + u32 home_menu_scheme_model; + u8 crc16_pad59[0xC]; + + // 10.0.0 and up. + u8 console_6axis_sensor_mount_type; +} __attribute__((packed)) nx_emmc_cal0_t; + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff); +void nx_emmc_bis_init(emmc_part_t *part); + +#endif \ No newline at end of file diff --git a/ariane/src/storage/nx_sd.c b/ariane/src/storage/nx_sd.c new file mode 100644 index 0000000..834cd8d --- /dev/null +++ b/ariane/src/storage/nx_sd.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +static bool sd_mounted = false; +static bool sd_init_done = false; +static u16 sd_errors[3] = { 0 }; // Init and Read/Write errors. +static u32 sd_mode = SD_UHS_SDR104; + +sdmmc_t sd_sdmmc; +sdmmc_storage_t sd_storage; +FATFS sd_fs; + +bool sdmounted() { return sd_mounted; } + +void sd_error_count_increment(u8 type) +{ + switch (type) + { + case SD_ERROR_INIT_FAIL: + sd_errors[0]++; + break; + case SD_ERROR_RW_FAIL: + sd_errors[1]++; + break; + case SD_ERROR_RW_RETRY: + sd_errors[2]++; + break; + } +} + +u16 *sd_get_error_count() +{ + return sd_errors; +} + +bool sd_get_card_removed() +{ + if (sd_init_done && !sdmmc_get_sd_inserted()) + return true; + + return false; +} + +u32 sd_get_mode() +{ + return sd_mode; +} + +int sd_init_retry(bool power_cycle) +{ + u32 bus_width = SDMMC_BUS_WIDTH_4; + u32 type = SDHCI_TIMING_UHS_SDR104; + + // Power cycle SD card. + if (power_cycle) + { + sd_mode--; + sdmmc_storage_end(&sd_storage); + } + + // Get init parameters. + switch (sd_mode) + { + case SD_INIT_FAIL: // Reset to max. + return 0; + case SD_1BIT_HS25: + bus_width = SDMMC_BUS_WIDTH_1; + type = SDHCI_TIMING_SD_HS25; + break; + case SD_4BIT_HS25: + type = SDHCI_TIMING_SD_HS25; + break; + case SD_UHS_SDR82: + type = SDHCI_TIMING_UHS_SDR82; + break; + case SD_UHS_SDR104: + type = SDHCI_TIMING_UHS_SDR104; + break; + default: + sd_mode = SD_UHS_SDR104; + } + + return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type); +} + +bool sd_initialize(bool power_cycle) +{ + if (power_cycle) + sdmmc_storage_end(&sd_storage); + + int res = !sd_init_retry(false); + + while (true) + { + if (!res) + return true; + else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted. + { + sd_mode = SD_UHS_SDR104; + break; + } + else + { + sd_errors[SD_ERROR_INIT_FAIL]++; + + if (sd_mode == SD_INIT_FAIL) + break; + else + res = !sd_init_retry(true); + } + } + + sdmmc_storage_end(&sd_storage); + + return false; +} + +bool sd_mount() +{ + if (sd_mounted) + return true; + + int res = 0; + + if (!sd_init_done) + res = !sd_initialize(false); + + if (res) + { + gfx_con.mute = false; + EPRINTF("Failed to init SD card."); + if (!sdmmc_get_sd_inserted()) + EPRINTF("Make sure that it is inserted."); + else + EPRINTF("SD Card Reader is not properly seated!"); + } + else + { + sd_init_done = true; + res = f_mount(&sd_fs, "sd:", 1); + if (res == FR_OK) + { + sd_mounted = true; + return true; + } + else + { + gfx_con.mute = false; + EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); + } + } + + return false; +} + +static void _sd_deinit(bool deinit) +{ + if (sd_mode == SD_INIT_FAIL) + sd_mode = SD_UHS_SDR104; + + if (sd_init_done && sd_mounted) + { + f_mount(NULL, "sd:", 1); + sd_mounted = false; + } + if (sd_init_done && deinit) + { + sdmmc_storage_end(&sd_storage); + sd_init_done = false; + } +} + +void sd_unmount() { _sd_deinit(false); } +void sd_end() { _sd_deinit(true); } + +void *sd_file_read(const char *path, u32 *fsize) +{ + FIL fp; + if (f_open(&fp, path, FA_READ) != FR_OK) + return NULL; + + u32 size = f_size(&fp); + if (fsize) + *fsize = size; + + void *buf = malloc(size); + + if (f_read(&fp, buf, size, NULL) != FR_OK) + { + free(buf); + f_close(&fp); + + return NULL; + } + + f_close(&fp); + + return buf; +} + +int sd_save_to_file(void *buf, u32 size, const char *filename) +{ + FIL fp; + u32 res = 0; + res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); + if (res) + { + EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); + return res; + } + + f_write(&fp, buf, size, NULL); + f_close(&fp); + + return 0; +} diff --git a/ariane/src/usb_command.h b/ariane/src/usb_command.h index 74e4304..dfe67fc 100644 --- a/ariane/src/usb_command.h +++ b/ariane/src/usb_command.h @@ -13,8 +13,12 @@ typedef unsigned long long int u64; #define MAX_FILE_SIZE 0x6400000 //100MB #define SUCCESS 0 #define USB_BUFFER_LENGTH 0x1000 +#define COMMAND_MAX_SIZE 0x120 #define RESPONSE_MAX_SIZE 0x20 +#define FILEBASED 2 +#define RAWBASED 1 + typedef enum _UC_CommandType { NONE, @@ -26,7 +30,12 @@ typedef enum _UC_CommandType GET_DEVICE_INFO, GET_STATUS, SET_AUTORCM_ON, - SET_AUTORCM_OFF + SET_AUTORCM_OFF, + SIZE_SD_FILE, + ISDIR_SD, + MKDIR_SD, + MKPATH_SD, + GET_KEYS } UC_CommandType; @@ -67,17 +76,27 @@ typedef struct _UC_BlockHeader typedef struct _UC_DeviceInfo { - u16 signature; // UC signature - u32 battery_capacity; // Fuel gauge - bool autoRCM; // autoRCM state - u32 burnt_fuses; // Number of burnt fuses - bool sdmmc_initialized; // MMC FS initialized - u8 emmc_fs_type; // 3 is FAT32, 4 is exFAT - u16 emmc_fs_cl_size; // Cluster size in sectors (always 512B per sectors) - DWORD emmc_fs_last_cl; // Last allocated cluster - DWORD emmc_fs_free_cl; // Number of free cluster - bool cfw_sxos; // SX OS bootloader - bool cfw_ams; // AMS fusee - bool cbl_hekate; // Hekate + u16 signature; // UC signature + char deviceId[21]; // Console unique ID + u32 battery_capacity; // Fuel gauge + bool autoRCM; // autoRCM state + u32 burnt_fuses; // Number of burnt fuses + bool sdmmc_initialized; // MMC FS initialized + u8 mmc_fs_type; // 3 for FAT32, 4 for exFAT + u16 mmc_fs_cl_size; // Cluster size in sectors (always 512B per sectors) + DWORD mmc_fs_last_cl; // Last allocated cluster + DWORD mmc_fs_free_cl; // Number of free cluster + bool cfw_sxos; // SX OS bootloader + bool cfw_ams; // AMS fusee + bool cbl_hekate; // Hekate + bool cbl_nyx; // Nyx + u8 nyx_version[3]; // Nyx version str (major, minor, micro) + u8 ams_version[3]; // AMS version str (major, minor, micro) + char fw_version[10]; // sysNAND firmware version + bool exFat_driver; // sysNAND exFat driver + char emu_fw_version[10]; // emuNAND firmware version + bool emu_exFat_driver; // emuNAND exFat driver + bool emunand_enabled; // Is EmuNAND enabled ? + int emunand_type; } UC_DeviceInfo; diff --git a/ariane/src/usb_output.h b/ariane/src/usb_output.h deleted file mode 100644 index dcae738..0000000 --- a/ariane/src/usb_output.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _USB_OUTPUT_H_ -#define _USB_OUTPUT_H_ - -enum -{ - //commands - USB_OUTPUT_COMMAND_SEND_SYNC = 0x01, - USB_OUTPUT_COMMAND_HALT_BPMP = 0xFE, - USB_OUTPUT_COMMAND_MASK = 0xFF, - //status - USB_OUTPUT_STATUS_OP_STARTED = 1u << 30, - USB_OUTPUT_STATUS_OP_COMPLETE = 1u << 31 -}; - -typedef struct usb_output_mbox -{ - unsigned int statcmd; - unsigned int buf; - unsigned int len; - int retVal; -} usb_output_mbox_t; - -inline volatile usb_output_mbox_t* get_usb_output_mbox_addr() -{ - const unsigned int IRAM_START = 0x40000000; - const unsigned int IRAM_SIZE = 256*1024; - - return (volatile usb_output_mbox_t*)(IRAM_START + IRAM_SIZE - sizeof(usb_output_mbox_t)); -} - -#endif \ No newline at end of file diff --git a/ariane/src/utils.c b/ariane/src/utils.c deleted file mode 100644 index c8f1237..0000000 --- a/ariane/src/utils.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "utils.h" -#include "fuse.h" -#include "hwinit/t210.h" -#include "hwinit/pmc.h" -#include "panic_color.h" - -#include "hwinit/btn.h" - -__attribute__ ((noreturn)) void panic(uint32_t code) { - /* Set Panic Code for NX_BOOTLOADER. */ - if (PMC(APBDEV_PMC_SCRATCH200) == 0) { - PMC(APBDEV_PMC_SCRATCH200) = code; - } - - /* TODO: Custom Panic Driver, which displays to screen without rebooting. */ - /* For now, just use NX BOOTLOADER's panic. */ - fuse_disable_programming(); - PMC(APBDEV_PMC_CRYPTO_OP) = 1; /* Disable all SE operations. */ - - /* FIXME: clean up and use this instead of replacing things */ - while(btn_read() != BTN_POWER); - - /* Ensure we boot back into RCM, for development. */ - PMC(APBDEV_PMC_SCRATCH0) = (1 << 1); - - /* Reset the processor. */ - PMC(0) = (1 << 4); - while(1); -} - -__attribute__ ((noreturn)) void generic_panic(void) { - panic(0xFF000006); -} - -__attribute__ ((noreturn)) void panic_predefined(uint32_t which) { - static const uint32_t codes[0x10] = {COLOR_0, COLOR_1, COLOR_2, COLOR_3, COLOR_4, COLOR_5, COLOR_6, COLOR_7, COLOR_8, COLOR_9, COLOR_A, COLOR_B, COLOR_C, COLOR_D, COLOR_E, COLOR_F}; - panic(codes[which & 0xF]); -} - -__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be) -{ - if(as <= bs && bs <= ae) - return true; - if(bs <= as && as <= be) - return true; - return false; -} diff --git a/ariane/src/utils.h b/ariane/src/utils.h deleted file mode 100644 index fe11ae2..0000000 --- a/ariane/src/utils.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef FUSEE_UTILS_H -#define FUSEE_UTILS_H - -#include -#include -#include -#include - -#define BIT(n) (1u << (n)) -#define BITL(n) (1ull << (n)) -#define MASK(n) (BIT(n) - 1) -#define MASKL(n) (BITL(n) - 1) -#define MASK2(a,b) (MASK(a) & ~MASK(b)) -#define MASK2L(a,b) (MASKL(a) & ~MASKL(b)) - -#define MAKE_REG32(a) (*(volatile uint32_t *)(a)) - -#define ALIGNED(m) __attribute__((aligned(m))) -#define PACKED __attribute__((packed)) - -#define ALINLINE __attribute__((always_inline)) -#define NOINLINE __attribute__((noinline)) - -#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false) - -static inline uintptr_t get_physical_address(const void *addr) { - return (uintptr_t)addr; -} - -static inline uint32_t read32le(const volatile void *dword, size_t offset) { - uintptr_t addr = (uintptr_t)dword + offset; - volatile uint32_t *target = (uint32_t *)addr; - return *target; -} - -static inline uint32_t read32be(const volatile void *dword, size_t offset) { - return __builtin_bswap32(read32le(dword, offset)); -} - -static inline uint64_t read64le(const volatile void *qword, size_t offset) { - uintptr_t addr = (uintptr_t)qword + offset; - volatile uint64_t *target = (uint64_t *)addr; - return *target; -} - -static inline uint64_t read64be(const volatile void *qword, size_t offset) { - return __builtin_bswap64(read64le(qword, offset)); -} - -static inline void write32le(volatile void *dword, size_t offset, uint32_t value) { - uintptr_t addr = (uintptr_t)dword + offset; - volatile uint32_t *target = (uint32_t *)addr; - *target = value; -} - -static inline void write32be(volatile void *dword, size_t offset, uint32_t value) { - write32le(dword, offset, __builtin_bswap32(value)); -} - -static inline void write64le(volatile void *qword, size_t offset, uint64_t value) { - uintptr_t addr = (uintptr_t)qword + offset; - volatile uint64_t *target = (uint64_t *)addr; - *target = value; -} - -static inline void write64be(volatile void *qword, size_t offset, uint64_t value) { - write64le(qword, offset, __builtin_bswap64(value)); -} - -static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) { - return __builtin_add_overflow_p(a, b, (uint32_t)0); -} - -void panic(uint32_t code); -void generic_panic(void); -void panic_predefined(uint32_t which); -bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be); - -#endif diff --git a/kourou/.gitignore b/kourou/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/kourou/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/kourou/kourou.cpp b/kourou/kourou.cpp index 903fb02..7b9633b 100644 --- a/kourou/kourou.cpp +++ b/kourou/kourou.cpp @@ -39,11 +39,281 @@ bool Kourou::initDevice(KLST_DEVINFO_HANDLE deviceInfo) return m_rcm_ready; } +int Kourou::hack(const char* payload_path) +{ + if (!arianeIsReady()) + return RcmDevice::hack(payload_path); + + ifstream userPayload(payload_path, ios::in | ios::binary | ios::ate); + + if (!userPayload.is_open()) + return OPEN_FILE_FAILED; + + const auto userPayloadSize = int(userPayload.tellg()); + if (userPayloadSize > PAYLOAD_MAX_SIZE) + return PAYLOAD_TOO_LARGE; + + userPayload.seekg(0, ios::beg); + char *userPayloadBuffer = new char[userPayloadSize]; + userPayload.read(&userPayloadBuffer[0], userPayloadSize); + bool error = !(userPayload) || int(userPayload.tellg()) != userPayloadSize; + userPayload.close(); + if (error) + { + delete[] userPayloadBuffer; + return OPEN_FILE_FAILED; + } + + int res = hack((u8*)userPayloadBuffer, (u32)userPayloadSize); + + delete[] userPayloadBuffer; + return res; +} + +int Kourou::hack(u8 *payload_buff, u32 buff_size) +{ + if (!arianeIsReady()) + return RcmDevice::hack(payload_buff, buff_size); + + UC_EXEC uc; + uc.command = PUSH_PAYLOAD; + uc.bin_size = buff_size; + + if (write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) + return USB_WRITE_FAILED; + + // Get response + bool response = false; + if (!readResponse(&response, sizeof(bool)) && !response) + return USB_WRITE_FAILED; + + if (sendBinPackets((char*)payload_buff, buff_size) != buff_size) + return USB_WRITE_FAILED; + + m_ariane_ready = false; + + return SUCCESS; +} + void Kourou::disconnect() { RcmDevice::disconnect(); m_rcm_ready = false; m_ariane_ready = false; + memset(&m_di, 0, sizeof(UC_DeviceInfo)); + m_di_set = false; +} + +bool Kourou::sdmmc_isDir(const char* path) +{ + if (path == nullptr) + return false; + + UC_SDIO uc; + uc.command = ISDIR_SD; + strcpy_s(uc.path, array_countof(uc.path), path); + + if (write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) + return false; + + u32 res = 0; + if (!readResponse(&res, sizeof(u32))) + return false; + + return res == SUCCESS ? true : false; +} + +bool Kourou::sdmmc_mkDir(const char* path) +{ + if (path == nullptr) + return false; + + UC_SDIO uc; + uc.command = MKDIR_SD; + strcpy_s(uc.path, array_countof(uc.path), path); + + if (write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) + return false; + + u32 res = 0; + if (!readResponse(&res, sizeof(u32))) + return false; + + return res == SUCCESS ? true : false; +} + +bool Kourou::sdmmc_mkPath(const char* path) +{ + if (path == nullptr) + return false; + + UC_SDIO uc; + uc.command = MKPATH_SD; + strcpy_s(uc.path, array_countof(uc.path), path); + + if (write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) + return false; + + u32 res = 0; + if (!readResponse(&res, sizeof(u32))) + return false; + + return res == SUCCESS ? true : false; +} + +u32 Kourou::sdmmc_fileSize(const char* path) +{ + if (path == nullptr) + return 0; + + UC_SDIO uc; + uc.command = SIZE_SD_FILE; + strcpy_s(uc.path, array_countof(uc.path), path); + + int bytesSent = write((const u8*)&uc, sizeof(uc)); + if (bytesSent != sizeof(uc)) + return 0; + + u32 size = 0; + if (!readResponse(&size, sizeof(u32))) + return 0; + + return size; +} + +int Kourou::sdmmc_readFile(const char* path, Bytes *dest, u32 *bytesRead) +{ + if (path == nullptr) + return BAD_ARGUMENT; + + UC_SDIO uc; + if (strlen(path) > array_countof(uc.path)-1) + return PATH_TOO_LONG; + + if (dest->size()) + dest->clear(); + + uc.command = READ_SD_FILE; + strcpy_s(uc.path, array_countof(uc.path), path); + + // Send command to device + int bytesSent = write((const u8*)&uc, sizeof(uc)); + if (bytesSent != sizeof(uc)) + return SEND_COMMAND_FAILED; + + u32 file_size = 0; + if (!readResponse(&file_size, sizeof(u32))) + return USB_WRITE_FAILED; + + if (!file_size) + return OPEN_FILE_FAILED; + + u8 usb_buffer[USB_BUFFER_LENGTH]; + UC_BlockHeader *bh = (UC_BlockHeader*)&usb_buffer[0]; + u32 offset = 0; + + while (offset < file_size) + { + memset(&usb_buffer[0], 0, USB_BUFFER_LENGTH); + if (read(usb_buffer, USB_BUFFER_LENGTH) != USB_BUFFER_LENGTH) + return USB_READ_FAILED; + + if (bh->signature != BIN_PACKET || !bh->block_size) + return USB_READ_FAILED; + + dest->insert(dest->end(), &usb_buffer[32], &usb_buffer[32] + bh->block_size); + offset += bh->block_size; + bool res = true; + sendResponse(&res, sizeof(res)); + } + + if (nullptr != bytesRead) + *bytesRead = offset; + + return offset == file_size ? SUCCESS : USB_READ_FAILED; +} + +int Kourou::sdmmc_readFile(const char* path, u8 *buffer, u32 size, u32 *bytesRead) +{ + if (path == nullptr || !size) + return BAD_ARGUMENT; + + UC_SDIO uc; + if (strlen(path) > array_countof(uc.path)-1) + return PATH_TOO_LONG; + + uc.command = READ_SD_FILE; + strcpy_s(uc.path, array_countof(uc.path), path); + + // Send command to device + int bytesSent = write((const u8*)&uc, sizeof(uc)); + if (bytesSent != sizeof(uc)) + return SEND_COMMAND_FAILED; + + u32 file_size = 0; + if (!readResponse(&file_size, sizeof(u32))) + return USB_WRITE_FAILED; + + if (!file_size) + return OPEN_FILE_FAILED; + + if (file_size > size) + return BUFFER_TOO_SMALL; + + u8 usb_buffer[USB_BUFFER_LENGTH]; + u32 offset = 0; + UC_BlockHeader *bh = (UC_BlockHeader*)&usb_buffer[0]; + while (offset < file_size) + { + memset(&usb_buffer[0], 0, USB_BUFFER_LENGTH); + if (read(usb_buffer, USB_BUFFER_LENGTH) != USB_BUFFER_LENGTH) + return USB_READ_FAILED; + + if (bh->signature != BIN_PACKET || !bh->block_size) + return USB_READ_FAILED; + + memcpy(&buffer[offset], &usb_buffer[32], bh->block_size); + offset += bh->block_size; + bool res = true; + sendResponse(&res, sizeof(res)); + } + + if (nullptr != bytesRead) + *bytesRead = offset; + + bool res = USB_READ_FAILED; + readResponse(&res, sizeof(bool)); + + return res ? SUCCESS : USB_READ_FAILED; +} + +int Kourou:: + +sdmmc_writeFile(Bytes *in_bytes, const char *out_path, bool create_always) +{ + UC_SDIO uc; + + if (strlen(out_path) > array_countof(uc.path)-1) + return PATH_TOO_LONG; + + if (!in_bytes->size()) + return OPEN_FILE_FAILED; + + if (in_bytes->size() > MAX_FILE_SIZE) + return FILE_TOO_LARGE; + + uc.command = WRITE_SD_FILE; + memset(uc.path, 0, array_countof(uc.path)); + uc.create_always = create_always; + strcpy_s(uc.path, array_countof(uc.path), out_path); + uc.file_size = in_bytes->size(); + + // Send command to device + int bytesSent = write((const u8*)&uc, sizeof(uc)); + if (bytesSent != sizeof(uc)) + return SEND_COMMAND_FAILED; + + return sendBinPackets((char*)in_bytes->data(), uc.file_size); } int Kourou::sdmmc_writeFile(const char* in_path, const char* out_path, bool create_always) @@ -68,20 +338,23 @@ int Kourou::sdmmc_writeFile(const char* in_path, const char* out_path, bool crea return end(FILE_TOO_LARGE); // Create command - memset(uc.path, 0, array_countof(uc.path)); uc.command = WRITE_SD_FILE; + memset(uc.path, 0, array_countof(uc.path)); + uc.create_always = create_always; strcpy_s(uc.path, array_countof(uc.path), out_path); uc.file_size = file.tellg(); file.seekg(0, ios::beg); + // Allocate memory for file + fileMemBlock = new char[uc.file_size]; + file.read(fileMemBlock, uc.file_size); + // Send command to device int bytesSent = write((const u8*)&uc, sizeof(uc)); if (bytesSent != sizeof(uc)) return end(SEND_COMMAND_FAILED); - // Allocate memory for file - fileMemBlock = new char[uc.file_size]; - file.read(fileMemBlock, uc.file_size); + //Sleep(100); // Make sure Ariane has enough time to open file return end(sendBinPackets(fileMemBlock, uc.file_size)); } @@ -101,7 +374,9 @@ int Kourou::sendBinPackets(char* buffer, u32 len) memcpy_s(&buf[32], bh.block_size, &buffer[curOffset], bh.block_size); u32 fbs = bh.block_size + 32; - if (write((const u8*)&buf[0], fbs) != int(fbs)) + //if (write((const u8*)&buf[0], fbs) != int(fbs)) + int res = write((const u8*)&buf[0], USB_BUFFER_LENGTH); + if (res != USB_BUFFER_LENGTH) return USB_WRITE_FAILED; // Get confirmation @@ -112,8 +387,9 @@ int Kourou::sendBinPackets(char* buffer, u32 len) return USB_WRITE_FAILED; bytesRemaining -= bh.block_size; + curOffset += bh.block_size; } - return int(len); + return int(len - bytesRemaining); } bool Kourou::readResponse(void* buffer, u32 size) @@ -135,19 +411,37 @@ bool Kourou::readResponse(void* buffer, u32 size) return true; } -bool Kourou::arianeIsReady_sync() +bool Kourou::sendResponse(void* buffer, u32 size) +{ + u32 res_size = RESPONSE_MAX_SIZE - sizeof(u16); + u8 tmp_buffer[RESPONSE_MAX_SIZE]; + if (size > res_size) + return false; + else res_size = size + sizeof(u16); + + u16* signature = (u16*)tmp_buffer; + *signature = RESPONSE; + memcpy(&tmp_buffer[sizeof(u16)], buffer, size); + + return write(tmp_buffer, res_size) == int(res_size); +} + +bool Kourou::arianeIsReady_sync(bool skip_rcm) { auto end = [&](bool ready) { m_ariane_ready = ready; return ready; }; - if (RcmDevice::deviceIsReady()) + if (!skip_rcm) { - m_rcm_ready = true; - return end(false); + if (RcmDevice::deviceIsReady()) + { + m_rcm_ready = true; + return end(false); + } + else m_rcm_ready = false; } - else m_rcm_ready = false; u8 buff[0x10]; static const char READY_INDICATOR[] = "READY.\n"; @@ -168,18 +462,24 @@ bool Kourou::arianeIsReady_sync() int Kourou::getDeviceInfo(UC_DeviceInfo* di) { + if (di != nullptr) memset(di, 0, sizeof(UC_DeviceInfo)); UC_Header uc; uc.command = GET_DEVICE_INFO; if(write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) return SEND_COMMAND_FAILED; - if(read((u8*)di, sizeof(UC_DeviceInfo)) != sizeof(UC_DeviceInfo)) + int res = read((u8*)(di != nullptr ? di : &m_di), sizeof(UC_DeviceInfo)); + if(res != sizeof(UC_DeviceInfo)) return RECEIVE_COMMAND_FAILED; if (di->signature != DEVINFO) return RECEIVE_COMMAND_FAILED; - return 0; + // Save device info + if (di != nullptr) memcpy(&m_di, di, sizeof(UC_DeviceInfo)); + m_di_set = true; + + return SUCCESS; } bool Kourou::rebootToRcm() @@ -216,5 +516,4 @@ bool Kourou::setAutoRcmEnabled(bool state) return false; return response; - } diff --git a/kourou/kourou.h b/kourou/kourou.h index 1c0c9e9..1f4a437 100644 --- a/kourou/kourou.h +++ b/kourou/kourou.h @@ -15,9 +15,8 @@ */ /* - * Kourou is a C++ child class derived from base class "RcmDevice" - * This class provides additionnal functions for communicating with Ariane (backend payload based program) - * + * Kourou class is derived from RcmDevice class + * Provides additionnal functions to communicate with device with Ariane (backend payload based program) */ #ifndef KOUROU_H @@ -27,10 +26,12 @@ typedef enum _KRESULT : DWORD { - RCM_REBOOT_FAILED = 0x00F, - ARIANE_NOT_READY = 0x010, - WRONG_PARAM_GENERIC = 0x011, - FAILED_TO_SET_AUTORCM = 0x012 + RCM_REBOOT_FAILED = 0x100, + ARIANE_NOT_READY = 0x101, + WRONG_PARAM_GENERIC = 0x102, + FAILED_TO_SET_AUTORCM = 0x103, + FAILED_TO_MKDIR = 0x104, + SD_FILE_WRITE_FAILED = 0x105 } KRESULT; @@ -39,23 +40,40 @@ class Kourou : public RcmDevice public: Kourou(); bool initDevice(KLST_DEVINFO_HANDLE deviceInfo = nullptr); + int hack(const char* payload_path); + int hack(u8 *payload_buff, u32 buff_size); void disconnect(); - - int sdmmc_writeFile(const char* in_path, const char* out_path, bool create_always = false); - int getDeviceInfo(UC_DeviceInfo* di); + bool readResponse(void* buffer, u32 size); + bool sendResponse(void* buffer, u32 size); + u32 sdmmc_fileSize(const char* path); + bool sdmmc_isDir(const char* path); + bool sdmmc_mkDir(const char* path); + bool sdmmc_mkPath(const char* path); + int sdmmc_readFile(const char* path, u8 *buffer, u32 size, u32 *bytesRead); + int sdmmc_readFile(const char* path, Bytes *dest, u32 *bytesRead = nullptr); + int sdmmc_writeFile(const char* in_path, const char* out_path, bool create_always = false); + int sdmmc_writeFile(Bytes *in_bytes, const char *out_path, bool create_always = false); + int pushPayload(const char* path); + int getDeviceInfo(UC_DeviceInfo* di); bool arianeIsReady() { return m_ariane_ready; } bool rcmIsReady() { return m_rcm_ready; } void setRcmReady(bool b) { m_rcm_ready = b; } - bool arianeIsReady_sync(); + bool arianeIsReady_sync(bool skip_rcm = false); void setArianeReady(bool b) { m_ariane_ready = b; } bool rebootToRcm(); bool setAutoRcmEnabled(bool state); + bool isReadyToReceivePayload() { return (m_rcm_ready || m_ariane_ready); } + bool isDeviceInfoAvailable() { return m_di_set; } + UC_DeviceInfo deviceInfo() { return m_di; } -private: - int sendBinPackets(char* buffer, u32 len); - bool readResponse(void* buffer, u32 size); +private: bool m_ariane_ready = false; bool m_rcm_ready = false; + UC_DeviceInfo m_di; + bool m_di_set = false; + + int sendBinPackets(char* buffer, u32 len); + }; #endif // KOUROU_H diff --git a/kourou/kourou.pro b/kourou/kourou.pro new file mode 100644 index 0000000..3bd7bbf --- /dev/null +++ b/kourou/kourou.pro @@ -0,0 +1,37 @@ +QT -= gui + +CONFIG += c++11 console +CONFIG -= app_bundle + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + kourou.cpp \ + libs/rcm_device.cpp \ + main.cpp + +ARCH = 64 + +contains( ARCH, 64 ) { + LIBS += -L$$PWD/../../../../../../../../libusbK-dev-kit/bin/lib/amd64/ -llibusbK +} +contains( ARCH, 32 ) { + LIBS += -L$$PWD/../../../../../../../../libusbK-dev-kit/bin/lib/x86/ -llibusbK +} +INCLUDEPATH += $$PWD/../../../../../../../../libusbK-dev-kit/includes +DEPENDPATH += $$PWD/../../../../../../../../libusbK-dev-kit/includes + +HEADERS += \ + kourou.h \ + libs/libusbk_int.h \ + libs/rcm_device.h \ + usb_command.h diff --git a/kourou/libs/rcm_device.cpp b/kourou/libs/rcm_device.cpp index 5c4a00a..53b50b8 100644 --- a/kourou/libs/rcm_device.cpp +++ b/kourou/libs/rcm_device.cpp @@ -91,7 +91,7 @@ bool RcmDevice::initDevice(KLST_DEVINFO_HANDLE deviceInfo) m_devStatus = CONNECTED; // Set pipes timeout policy - u32 pipe_timeout = 2000; //ms + u32 pipe_timeout = 2500; //ms m_usbApi.SetPipePolicy(m_usbHandle, READ_PIPE_ID, PIPE_TRANSFER_TIMEOUT, sizeof(u32), &pipe_timeout); m_usbApi.SetPipePolicy(m_usbHandle, WRITE_PIPE_ID, PIPE_TRANSFER_TIMEOUT, sizeof(u32), &pipe_timeout); @@ -133,7 +133,7 @@ int RcmDevice::read(u8* buffer, size_t bufferSize) int RcmDevice::write(const u8* buffer, size_t bufferSize) { - size_t bytesRemaining = int(bufferSize); + size_t bytesRemaining = bufferSize; size_t bytesWritten = 0; while (bytesRemaining > 0) @@ -174,34 +174,6 @@ const byte BUILTIN_INTERMEZZO[] = 0x5C, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40 }; -RRESULT RcmDevice::hack(const char* user_payload_path) -{ - ifstream userPayload(user_payload_path, ios::in | ios::binary | ios::ate); - - if (!userPayload.is_open()) - return OPEN_FILE_FAILED; - - const auto userPayloadSize = int(userPayload.tellg()); - if (userPayloadSize > PAYLOAD_MAX_SIZE) - return PAYLOAD_TOO_LARGE; - - userPayload.seekg(0, ios::beg); - char *userPayloadBuffer = new char[userPayloadSize]; - userPayload.read(&userPayloadBuffer[0], userPayloadSize); - bool error = !(userPayload) || int(userPayload.tellg()) != userPayloadSize; - userPayload.close(); - if (error) - { - delete[] userPayloadBuffer; - return OPEN_FILE_FAILED; - } - - RRESULT res = hack((u8*)userPayloadBuffer, (u32)userPayloadSize); - - delete[] userPayloadBuffer; - return res; -} - RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size) { if (!m_devIsInitialized) @@ -216,7 +188,7 @@ RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size) m_currentBuffer = 0; - // Read device id first. + // Read device's id first. vector deviceId(0x10, 0); if (read(&deviceId[0], 0x10) != int(deviceId.size())) return DEVICE_NOT_READY; @@ -272,24 +244,22 @@ RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size) else payload.resize(PAYLOAD_TOTAL_MAX_SIZE); - int test = int(payload.size()); - // Send the constructed payload, which contains the command, the stack smashing values, // the Intermezzo relocation stub, and the user payload. int bytesWritten = write(&payload[0], payload.size()); - if (bytesWritten < payload.size()) + if (bytesWritten < int(payload.size())) return USB_WRITE_FAILED; // The RCM backend alternates between two different DMA buffers. Ensure we're about to DMA // into the higher one, so we have less to copy during our attack. // Warning! If device reboot to RCM, resetCurrentBuffer() must be called otherwise we'll swith to lower buffer instead - u32 sres = switchToHighBuffer(); + int sres = switchToHighBuffer(); if (sres != 0 && (sres < 0 || sres != PACKET_SIZE)) return SW_HIGHBUFF_FAILED; // Finally, to trigger the memcpy vulnerability itself, we need to send a // long length "GET_STATUS" request to the endpoint - int stLength = RCM_PAYLOAD_ADDR - getCurrentBufferAddress(); + auto stLength = RCM_PAYLOAD_ADDR - getCurrentBufferAddress(); std::vector threshBuf(stLength, 0); libusbk::libusb_request req; memset(&req, 0, sizeof(req)); @@ -299,6 +269,7 @@ RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size) // Request device int res = Ioctl(libusbk::LIBUSB_IOCTL_GET_STATUS, &req, sizeof(req), &threshBuf[0], threshBuf.size()); + // If stack is smashed, the request will timeout // If the device is an ipatched unit or Mariko+, the request will likely return 0 (or < 0) if (res <= 0 && -res != ERROR_SEM_TIMEOUT) @@ -307,6 +278,34 @@ RRESULT RcmDevice::hack(u8 *payload_buff, u32 buff_size) return SUCCESS; } +RRESULT RcmDevice::hack(const char* user_payload_path) +{ + ifstream userPayload(user_payload_path, ios::in | ios::binary | ios::ate); + + if (!userPayload.is_open()) + return OPEN_FILE_FAILED; + + const auto userPayloadSize = int(userPayload.tellg()); + if (userPayloadSize > PAYLOAD_MAX_SIZE) + return PAYLOAD_TOO_LARGE; + + userPayload.seekg(0, ios::beg); + char *userPayloadBuffer = new char[userPayloadSize]; + userPayload.read(&userPayloadBuffer[0], userPayloadSize); + bool error = !(userPayload) || int(userPayload.tellg()) != userPayloadSize; + userPayload.close(); + if (error) + { + delete[] userPayloadBuffer; + return OPEN_FILE_FAILED; + } + + RRESULT res = hack((u8*)userPayloadBuffer, (u32)userPayloadSize); + + delete[] userPayloadBuffer; + return res; +} + //////////////////////////////////////////// ///// PRIVATE METHODS ///// //////////////////////////////////////////// @@ -359,6 +358,7 @@ int RcmDevice::Ioctl(DWORD ioctlCode, const void* inputBytes, size_t numInputByt return int(bytesReceived); } + // Switch to higher DMA buffer int RcmDevice::switchToHighBuffer() { @@ -368,9 +368,6 @@ int RcmDevice::switchToHighBuffer() memset(tempZeroDatas, 0, sizeof(tempZeroDatas)); const auto writeRes = write(tempZeroDatas, sizeof(tempZeroDatas)); - if (writeRes < 0) - return writeRes; - return writeRes; } else return 0; diff --git a/kourou/libs/rcm_device.h b/kourou/libs/rcm_device.h index d64269f..b1880b2 100644 --- a/kourou/libs/rcm_device.h +++ b/kourou/libs/rcm_device.h @@ -135,7 +135,7 @@ public: bool flushPipe(UCHAR pipeId) { return m_usbApi.FlushPipe(m_usbHandle, pipeId); } // Reset the current buffer to lower one. Use this with caution. - // Current buffer should not be reset manually, except after a controlled RCM reboot er disconnection. + // Current buffer should not be reset manually, except after a controlled RCM reboot or disconnection. // disconnect() method should be preferred void resetCurrentBuffer() { m_currentBuffer = 0; } diff --git a/kourou/libs/tegrarcm/aes-cmac.cpp b/kourou/libs/tegrarcm/aes-cmac.cpp deleted file mode 100644 index 24c89f8..0000000 --- a/kourou/libs/tegrarcm/aes-cmac.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -using std::cout; -using std::cerr; -using std::endl; - -#include -using std::hex; - -#include -using std::string; - -#include -using std::exit; - -#include "cryptlib.h" -using CryptoPP::Exception; - -#include "cmac.h" -using CryptoPP::CMAC; - -#include "aes.h" -using CryptoPP::AES; - -#include "hex.h" -using CryptoPP::HexEncoder; -using CryptoPP::HexDecoder; - -#include "filters.h" -using CryptoPP::StringSink; -using CryptoPP::StringSource; -using CryptoPP::HashFilter; -using CryptoPP::HashVerificationFilter; - -#include "secblock.h" -using CryptoPP::SecByteBlock; - -extern "C" int cmac_hash(const unsigned char *msg, int len, unsigned char *cmac_buf) -{ - SecByteBlock key(NULL, AES::DEFAULT_KEYLENGTH); - - string plain((const char *)msg, len); - string mac, encoded; - - try { - CMAC cmac(key, key.size()); - - StringSource(plain, true, - new HashFilter(cmac, - new StringSink(mac) - ) // HashFilter - ); // StringSource - } - catch(const CryptoPP::Exception& e) { - cerr << e.what() << endl; - return 1; - } - - memcpy(cmac_buf, mac.data(), mac.length()); - - return 0; -} diff --git a/kourou/libs/tegrarcm/aes-cmac.h b/kourou/libs/tegrarcm/aes-cmac.h deleted file mode 100644 index e643021..0000000 --- a/kourou/libs/tegrarcm/aes-cmac.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _CMAC_H -#define _CMAC_H - -#ifdef __cplusplus -extern "C" { -#endif - -int cmac_hash(const unsigned char *msg, int len, unsigned char *cmac_buf); - -#ifdef __cplusplus -} -#endif - -#endif // _CMAC_H diff --git a/kourou/libs/tegrarcm/debug.c b/kourou/libs/tegrarcm/debug.c deleted file mode 100644 index fbc66f2..0000000 --- a/kourou/libs/tegrarcm/debug.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "debug.h" - -void dump_hex(uint8_t *buf, int len) -{ - int i; - for (i=0; i < len; i++) { - if (i % 16 == 0) { - printf("%04x: ", i); - } - printf("%02x ", buf[i]); - if ((i + 1) % 16 == 0) { - printf("\n"); - } - } - printf("\n"); -} diff --git a/kourou/libs/tegrarcm/debug.h b/kourou/libs/tegrarcm/debug.h deleted file mode 100644 index 06e7c5d..0000000 --- a/kourou/libs/tegrarcm/debug.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef DEBUG_H -#define DEBUG_H - -#include -#include -#include - -#ifdef DEBUG -#include -#define dprintf(format, args...) __dprintf("[%s:%d] %s(): " format, __FILE__, __LINE__, __func__, ## args) -__attribute__((format(printf, 1, 2))) static inline void __dprintf(const char *format, ...); -__attribute__((format(printf, 1, 2))) static inline void __dprintf(const char *format, ...) -{ - va_list args; - va_start(args,format); - vfprintf(stderr, format, args); - va_end(args); -} -#else -#define dprintf(format, args...) __dprintf(format, ## args) -__attribute__((format(printf, 1, 2))) static inline void __dprintf(const char *format, ...); -__attribute__((format(printf, 1, 2))) static inline void __dprintf(const char *format, ...) { } -#endif - -void dump_hex(uint8_t *buf, int len); - -#endif // DEBUG_H diff --git a/kourou/libs/tegrarcm/miniloader/tegra20-miniloader.h b/kourou/libs/tegrarcm/miniloader/tegra20-miniloader.h deleted file mode 100644 index 2333d59..0000000 --- a/kourou/libs/tegrarcm/miniloader/tegra20-miniloader.h +++ /dev/null @@ -1,8323 +0,0 @@ -/* - * Copyright (c) 2011 NVIDIA CORPORATION. All Rights Reserved. - * - * NVIDIA CORPORATION and its licensors retain all intellectual property - * and proprietary rights in and to this software, related documentation - * and any modifications thereto. Any use, reproduction, disclosure or - * distribution of this software and related documentation without an express - * license agreement from NVIDIA CORPORATION is strictly prohibited. - */ -#define TEGRA20_MINILOADER_ENTRY 0x40008000 -uint8_t miniloader_tegra20[] = { -0xdf,0xf0,0x2f,0xe3,0x56,0x71,0x00,0xeb,0x60,0x7b,0x00,0xeb,0x00,0xd0,0xa0,0xe1, -0x36,0x71,0x00,0xeb,0x79,0x71,0x00,0xeb,0xd8,0x6b,0x00,0xeb,0xe2,0x6b,0x00,0xea, -0x07,0x32,0xa0,0xe3,0x08,0x00,0x93,0xe5,0x20,0x02,0xa0,0xe1,0x03,0x00,0x00,0xe2, -0x1e,0xff,0x2f,0xe1,0x07,0x32,0xa0,0xe3,0x08,0x00,0x93,0xe5,0x20,0x03,0xa0,0xe1, -0x03,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x80,0x30,0x9f,0xe5,0x70,0x40,0x2d,0xe9, -0x00,0x50,0xa0,0xe1,0x00,0x40,0x93,0xe5,0x00,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3, -0x05,0x00,0x00,0x1a,0x04,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x1a, -0x08,0x60,0x94,0xe5,0x00,0x00,0x56,0xe3,0x01,0x00,0x00,0x0a,0x00,0x40,0x85,0xe5, -0x70,0x80,0xbd,0xe8,0x04,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0xe8,0x20,0xa0,0xe3, -0xa8,0x69,0x00,0xeb,0x01,0x38,0xa0,0xe3,0x00,0x30,0x84,0xe5,0x04,0x30,0x84,0xe5, -0x08,0x30,0x84,0xe5,0x02,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x05,0x30,0xa0,0xe3, -0x10,0x30,0x84,0xe5,0xa5,0x4e,0x00,0xeb,0xe8,0x30,0x84,0xe2,0x18,0x00,0x84,0xe5, -0x1e,0x60,0xc4,0xe5,0xe4,0x30,0x84,0xe5,0x00,0x40,0x85,0xe5,0x70,0x80,0xbd,0xe8, -0x1c,0x81,0x02,0x40,0xf0,0x47,0x2d,0xe9,0x00,0x30,0xa0,0xe3,0x44,0x41,0x9f,0xe5, -0x22,0xde,0x4d,0xe2,0x04,0x60,0xa0,0xe3,0x00,0x80,0xa0,0xe1,0x18,0x32,0x8d,0xe5, -0x22,0x5e,0x8d,0xe2,0x14,0x32,0x8d,0xe5,0x0c,0x10,0x8d,0xe5,0x1c,0x62,0x8d,0xe5, -0xc6,0xff,0xff,0xeb,0x00,0x30,0x94,0xe5,0x08,0x10,0xa0,0xe1,0x14,0x22,0x35,0xe5, -0x00,0x70,0xa0,0xe1,0xe4,0xc0,0x93,0xe5,0x0c,0x00,0xa0,0xe1,0x3c,0xc0,0x83,0xe5, -0x82,0x69,0x00,0xeb,0x00,0x30,0x94,0xe5,0x05,0x00,0xa0,0xe1,0xf8,0x50,0x9f,0xe5, -0x3c,0x10,0x93,0xe5,0x05,0x20,0xa0,0xe1,0x3e,0x0d,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x02,0x00,0x00,0x0a,0x03,0x00,0xa0,0xe3,0x22,0xde,0x8d,0xe2,0xf0,0x87,0xbd,0xe8, -0x87,0xaf,0x8d,0xe2,0x86,0x9f,0x8d,0xe2,0x00,0x00,0x95,0xe5,0x09,0x30,0xa0,0xe1, -0x14,0x80,0x8d,0xe2,0x03,0x10,0xa0,0xe3,0x0a,0x20,0xa0,0xe1,0x18,0x72,0x8d,0xe5, -0x00,0x80,0x8d,0xe5,0x9b,0x0d,0x00,0xeb,0x00,0x30,0x50,0xe2,0xf0,0xff,0xff,0x1a, -0x18,0x32,0x8d,0xe5,0x85,0x3f,0x8d,0xe2,0x00,0x00,0x95,0xe5,0x06,0x10,0xa0,0xe1, -0x00,0x30,0x8d,0xe5,0x0a,0x20,0xa0,0xe1,0x09,0x30,0xa0,0xe1,0x91,0x0d,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xe6,0xff,0xff,0x1a,0x14,0x32,0x9d,0xe5,0x03,0x00,0x57,0xe1, -0x07,0x00,0x00,0x3a,0x08,0x30,0xa0,0xe1,0x02,0x1c,0x88,0xe2,0x01,0x00,0x00,0xea, -0x01,0x00,0x53,0xe1,0xde,0xff,0xff,0x0a,0x01,0x20,0xd3,0xe4,0x00,0x00,0x52,0xe3, -0xfa,0xff,0xff,0x0a,0x08,0x10,0xa0,0xe1,0x00,0x20,0xa0,0xe3,0x4c,0x00,0x9f,0xe5, -0x9b,0x09,0x00,0xeb,0x08,0x00,0xa0,0xe1,0xef,0x66,0x00,0xeb,0xf4,0x66,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xd2,0xff,0xff,0x0a,0x00,0x30,0x94,0xe5,0x01,0x20,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x38,0xc0,0x93,0xe5,0xe4,0x10,0x93,0xe5,0x1d,0x20,0xc3,0xe5, -0x7f,0xc0,0x8c,0xe2,0x21,0x20,0xc3,0xe5,0x7f,0x20,0xcc,0xe3,0x02,0x20,0x81,0xe0, -0xe4,0x20,0x83,0xe5,0xc7,0xff,0xff,0xea,0x64,0x94,0x02,0x40,0x00,0x90,0x02,0x40, -0x9c,0x00,0x90,0x00,0xdf,0xf0,0x2f,0xe3,0x24,0x10,0x9f,0xe5,0x00,0x20,0xa0,0xe3, -0x00,0x20,0x81,0xe5,0x1c,0x10,0x9f,0xe5,0x00,0x20,0x81,0xe5,0x18,0x10,0x9f,0xe5, -0x00,0x20,0x81,0xe5,0x01,0x00,0x2d,0xe9,0x63,0x6e,0x00,0xeb,0x01,0x00,0xbd,0xe8, -0x10,0xff,0x2f,0xe1,0x08,0x50,0x00,0x60,0x18,0xf2,0x00,0x60,0x08,0xf2,0x00,0x60, -0xf0,0x41,0x2d,0xe9,0x68,0xd0,0x4d,0xe2,0xe2,0x05,0x00,0xeb,0x01,0x00,0xa0,0xe3, -0x04,0x10,0xa0,0xe3,0xd7,0x06,0x00,0xeb,0x58,0x50,0x8d,0xe2,0x01,0xc0,0xa0,0xe3, -0x0c,0x00,0xa0,0xe1,0x30,0x21,0x9f,0xe5,0x0c,0x10,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xee,0x06,0x00,0xeb,0x01,0x00,0xa0,0xe3,0x56,0x07,0x00,0xeb, -0x00,0x40,0x50,0xe2,0xfb,0xff,0xff,0x1a,0x38,0x80,0x8d,0xe2,0x04,0x10,0xa0,0xe1, -0x08,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x18,0x70,0x8d,0xe2,0x08,0x60,0x8d,0xe2, -0x18,0x69,0x00,0xeb,0x04,0x10,0xa0,0xe1,0x07,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3, -0x14,0x69,0x00,0xeb,0x04,0x00,0xa0,0xe1,0x07,0x30,0xa0,0xe1,0x01,0xc0,0xa0,0xe3, -0x02,0x10,0xa0,0xe3,0x08,0x20,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x5e,0x06,0x00,0xeb, -0x04,0x00,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x02,0x10,0xa0,0xe3,0x10,0x40,0x86,0xe2, -0xee,0x08,0x00,0xeb,0x28,0x20,0x8d,0xe2,0x04,0x30,0x42,0xe2,0x02,0x10,0xd6,0xe5, -0x03,0xe0,0xd6,0xe5,0x00,0xc0,0xd6,0xe5,0x01,0x00,0xd6,0xe5,0x04,0x60,0x86,0xe2, -0x01,0x18,0xa0,0xe1,0x04,0x00,0x56,0xe1,0x0e,0x1c,0x81,0xe1,0x0c,0x10,0x81,0xe1, -0x00,0x14,0x81,0xe1,0x04,0x10,0xa3,0xe5,0xf3,0xff,0xff,0x1a,0x01,0x60,0xa0,0xe3, -0x07,0x30,0xa0,0xe1,0x00,0x00,0xa0,0xe3,0x02,0x10,0xa0,0xe3,0x00,0x60,0x8d,0xe5, -0x48,0x40,0x8d,0xe2,0x44,0x06,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x02,0x10,0xa0,0xe3, -0x9c,0x06,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x06,0x10,0xa0,0xe1,0x48,0x20,0x9f,0xe5, -0x04,0x30,0xa0,0xe1,0x00,0x60,0x8d,0xe5,0xb5,0x06,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x1d,0x07,0x00,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x00,0x20,0xd5,0xe7, -0x00,0x30,0xd4,0xe7,0x01,0x00,0x80,0xe2,0x03,0x00,0x52,0xe1,0x04,0x00,0x00,0x1a, -0x10,0x00,0x50,0xe3,0xf8,0xff,0xff,0x1a,0x01,0x00,0xa0,0xe3,0x68,0xd0,0x8d,0xe2, -0xf0,0x81,0xbd,0xe8,0x02,0x00,0xa0,0xe3,0xfb,0xff,0xff,0xea,0x08,0x6e,0x02,0x40, -0xf0,0x4f,0x2d,0xe9,0x07,0x32,0xa0,0xe3,0xfc,0xd0,0x4d,0xe2,0x00,0x60,0xa0,0xe3, -0x10,0x20,0xa0,0xe3,0x0c,0x40,0x8d,0xe2,0xf0,0x60,0x8d,0xe5,0x02,0xa0,0xa0,0xe1, -0xec,0x60,0x8d,0xe5,0x3c,0x70,0x84,0xe2,0xe8,0x60,0x8d,0xe5,0x00,0x50,0xa0,0xe1, -0x04,0x38,0x93,0xe5,0x04,0x00,0xa0,0xe1,0x01,0x90,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x78,0x60,0x8d,0xe5,0x14,0x80,0x84,0xe2,0x23,0xe4,0xa0,0xe1,0x23,0xc2,0xa0,0xe1, -0x33,0x32,0xa0,0xe1,0xff,0xe0,0x0e,0xe2,0x0f,0xc0,0x0c,0xe2,0x0f,0x30,0x03,0xe2, -0xbc,0xe1,0xcd,0xe1,0x1e,0xc0,0xcd,0xe5,0x1f,0x30,0xcd,0xe5,0xbd,0x68,0x00,0xeb, -0x06,0x10,0xa0,0xe1,0x0a,0x20,0xa0,0xe1,0x07,0x00,0xa0,0xe1,0xb9,0x68,0x00,0xeb, -0x04,0x00,0xa0,0xe1,0x93,0x08,0x00,0xeb,0x08,0x00,0xa0,0xe1,0x22,0x4e,0x00,0xeb, -0x07,0x00,0xa0,0xe1,0x72,0x0c,0x00,0xeb,0xf8,0x20,0x8d,0xe2,0x0e,0x00,0xa0,0xe3, -0x08,0xa0,0x22,0xe5,0x04,0x10,0xa0,0xe1,0x6f,0x45,0x00,0xeb,0x06,0x00,0x50,0xe1, -0x07,0x00,0x00,0x1a,0xf8,0x20,0x8d,0xe2,0x04,0x60,0xa0,0xe3,0x0c,0x60,0x22,0xe5, -0x07,0x00,0xa0,0xe3,0x08,0x10,0xa0,0xe1,0x67,0x45,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x0b,0x00,0x00,0x0a,0x58,0x40,0x8d,0xe2,0x03,0x10,0xa0,0xe3,0x05,0x00,0xa0,0xe1, -0x05,0x22,0x00,0xeb,0x05,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x04,0x20,0xa0,0xe1, -0x00,0x30,0xa0,0xe3,0xec,0x22,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xfc,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0xe4,0x80,0x8d,0xe2,0x01,0x70,0xa0,0xe3,0x0b,0x00,0xa0,0xe3, -0xf4,0x10,0x8d,0xe2,0x08,0x20,0xa0,0xe1,0x24,0x70,0x8d,0xe5,0xe4,0x60,0x8d,0xe5, -0x51,0x45,0x00,0xeb,0x00,0x00,0x50,0xe3,0xe9,0xff,0xff,0x1a,0xcc,0xfe,0xff,0xeb, -0xf8,0x20,0x8d,0xe2,0x30,0x00,0x8d,0xe5,0x10,0x60,0x22,0xe5,0x05,0x00,0xa0,0xe3, -0x28,0x10,0x84,0xe2,0x48,0x45,0x00,0xeb,0x00,0x00,0x50,0xe3,0xe0,0xff,0xff,0x1a, -0xf4,0x00,0x9d,0xe5,0x1c,0x10,0x84,0xe2,0xe7,0x07,0x00,0xeb,0x00,0x60,0x50,0xe2, -0xdb,0xff,0xff,0x1a,0x06,0x10,0xa0,0xe1,0xac,0x00,0x8d,0xe2,0x0a,0x20,0xa0,0xe1, -0xcc,0xb0,0x8d,0xe2,0x7b,0x68,0x00,0xeb,0x0a,0x20,0xa0,0xe1,0x9c,0x00,0x8d,0xe2, -0x06,0x10,0xa0,0xe1,0x77,0x68,0x00,0xeb,0x2a,0x05,0x00,0xeb,0x06,0x00,0xa0,0xe1, -0x06,0x10,0xa0,0xe1,0x1f,0x06,0x00,0xeb,0x06,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1, -0xa4,0x21,0x9f,0xe5,0x0b,0x30,0xa0,0xe1,0x00,0x70,0x8d,0xe5,0x38,0x06,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xa0,0x06,0x00,0xeb,0x00,0x60,0x50,0xe2,0xfb,0xff,0xff,0x1a, -0x01,0xa0,0xa0,0xe3,0xac,0x20,0x8d,0xe2,0x9c,0x30,0x8d,0xe2,0x02,0x10,0xa0,0xe3, -0x00,0xa0,0x8d,0xe5,0xbc,0x70,0x8d,0xe2,0xb3,0x05,0x00,0xeb,0x06,0x00,0xa0,0xe1, -0x02,0x10,0xa0,0xe3,0x0b,0x06,0x00,0xeb,0x06,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe1, -0x54,0x21,0x9f,0xe5,0x07,0x30,0xa0,0xe1,0x00,0xa0,0x8d,0xe5,0x24,0x06,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x8c,0x06,0x00,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x00,0x30,0xa0,0xe1,0x03,0x10,0xdb,0xe7,0x03,0x20,0xd7,0xe7,0x01,0x30,0x83,0xe2, -0x02,0x00,0x51,0xe1,0x31,0x00,0x00,0x1a,0x10,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a, -0x00,0x30,0xa0,0xe3,0x3e,0x30,0xcd,0xe5,0x18,0xff,0xff,0xeb,0x40,0x00,0x8d,0xe5, -0x82,0xfe,0xff,0xeb,0x04,0x31,0x9f,0xe5,0x20,0x10,0x84,0xe2,0x38,0x00,0x8d,0xe5, -0x08,0x20,0xa0,0xe1,0x10,0x00,0xa0,0xe3,0x4c,0xc9,0x93,0xe5,0x02,0x00,0x1c,0xe3, -0x00,0xc0,0xa0,0x03,0x01,0xc0,0xa0,0x13,0x3c,0xc0,0xcd,0xe5,0x4c,0xc9,0x93,0xe5, -0x01,0xc0,0x0c,0xe2,0x3d,0xc0,0xcd,0xe5,0x04,0xc0,0xa0,0xe3,0xa0,0x39,0x93,0xe5, -0xe4,0xc0,0x8d,0xe5,0x01,0x30,0x73,0xe2,0x00,0x30,0xa0,0x33,0x44,0x30,0xcd,0xe5, -0xf5,0x44,0x00,0xeb,0x00,0x60,0x50,0xe2,0x8d,0xff,0xff,0x1a,0x2c,0x20,0x9d,0xe5, -0x80,0x00,0x8d,0xe2,0xa8,0x30,0x9f,0xe5,0x00,0x20,0x83,0xe5,0x22,0x07,0x00,0xeb, -0x06,0x30,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x09,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1, -0xe5,0x1f,0x00,0xeb,0x00,0x30,0x50,0xe2,0x81,0xff,0xff,0x1a,0x58,0x40,0x8d,0xe2, -0x05,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x04,0x20,0xa0,0xe1,0x72,0x22,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x01,0x00,0xa0,0x03,0x7a,0xff,0xff,0x1a,0x82,0xff,0xff,0xea, -0x5c,0x30,0x9f,0xe5,0x01,0x60,0xa0,0xe3,0x3e,0x60,0xcd,0xe5,0x00,0x30,0x93,0xe5, -0x05,0x00,0x53,0xe3,0x0d,0x00,0x00,0x0a,0x04,0x30,0xa0,0xe3,0x06,0x00,0xa0,0xe1, -0xe0,0x10,0x8d,0xe2,0xdc,0x20,0x8d,0xe2,0xdc,0x30,0x8d,0xe5,0xd2,0x44,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x6a,0xff,0xff,0x1a,0xe0,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x02,0x30,0xa0,0x13,0x40,0x60,0x8d,0x05,0x40,0x30,0x8d,0x15,0xbf,0xff,0xff,0xea, -0x03,0x30,0xa0,0xe3,0x40,0x30,0x8d,0xe5,0xbc,0xff,0xff,0xea,0x08,0x6e,0x02,0x40, -0x00,0xf0,0x00,0x70,0x78,0x93,0x02,0x40,0xf0,0x4f,0x2d,0xe9,0x00,0x70,0xa0,0xe3, -0x00,0x80,0x92,0xe5,0xbc,0xd0,0x4d,0xe2,0x02,0x50,0xa0,0xe1,0x00,0x40,0xa0,0xe1, -0x01,0xa0,0xa0,0xe1,0xb4,0x70,0x8d,0xe5,0x07,0x00,0x58,0xe1,0x78,0x70,0x8d,0xe5, -0x0b,0x00,0x00,0x0a,0x98,0x63,0x9f,0xe5,0x00,0x30,0x96,0xe5,0x21,0x20,0xd3,0xe5, -0x01,0x00,0x52,0xe3,0x12,0x00,0x00,0x0a,0xe4,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3, -0xb4,0x30,0x8d,0xe5,0x02,0x00,0x00,0x0a,0xc7,0x07,0x00,0xeb,0x00,0x00,0x58,0xe1, -0x0f,0x00,0x00,0x0a,0x58,0x50,0x8d,0xe2,0x03,0x10,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x4d,0x21,0x00,0xeb,0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x05,0x20,0xa0,0xe1, -0x00,0x30,0xa0,0xe3,0x34,0x22,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xbc,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x12,0x30,0xa0,0xe3,0x58,0x50,0x8d,0xe2,0x78,0x30,0x8d,0xe5, -0xf0,0xff,0xff,0xea,0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe1,0x05,0x20,0xa0,0xe1, -0x07,0x30,0xa0,0xe1,0x94,0x1f,0x00,0xeb,0x00,0x00,0x50,0xe3,0xe8,0xff,0xff,0x1a, -0x00,0xb0,0x95,0xe5,0x01,0x80,0xa0,0xe3,0x10,0x50,0x8d,0xe5,0x00,0xa0,0xa0,0xe1, -0xb4,0x90,0x9d,0xe5,0x04,0x70,0xa0,0xe1,0x00,0x50,0xa0,0xe1,0x10,0x00,0x00,0xea, -0x04,0x00,0x5b,0xe1,0x01,0x00,0x89,0xe0,0x01,0x50,0xa0,0x03,0x01,0xc0,0xa0,0xe3, -0x08,0x20,0xa0,0xe1,0x04,0x10,0x61,0xe0,0x05,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x04,0xc0,0x8d,0xe5,0x04,0x90,0x89,0xe0,0x08,0xa0,0x8d,0xe5,0x0a,0x80,0xa0,0xe1, -0xeb,0x0a,0x00,0xeb,0x00,0x00,0x50,0xe3,0x6b,0x00,0x00,0x0a,0x04,0xb0,0x5b,0xe0, -0x10,0x00,0x00,0x0a,0x02,0x0b,0x5b,0xe3,0x0b,0x40,0xa0,0x31,0x02,0x4b,0xa0,0x23, -0x09,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x0a,0x30,0xa0,0xe1,0x07,0x00,0xa0,0xe1, -0x00,0xa0,0x8d,0xe5,0x4e,0x21,0x00,0xeb,0x00,0x00,0x50,0xe3,0x08,0x10,0xa0,0xe1, -0x5a,0x00,0x00,0x1a,0x00,0x00,0x58,0xe3,0xe0,0xff,0xff,0x0a,0xf5,0x07,0x00,0xeb, -0x00,0x10,0xa0,0xe1,0xdd,0xff,0xff,0xea,0x10,0x50,0x9d,0xe5,0xa8,0x20,0x8d,0xe2, -0xb4,0x10,0x9d,0xe5,0x07,0x40,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x65,0x0b,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xb6,0xff,0xff,0x1a,0x8c,0x30,0x8d,0xe2,0x14,0x50,0x8d,0xe5, -0x18,0x80,0x8d,0xe2,0x04,0x50,0xa0,0xe1,0xb0,0x70,0x8d,0xe2,0xac,0xa0,0x8d,0xe2, -0x80,0x90,0x8d,0xe2,0x03,0x40,0xa0,0xe1,0x10,0x30,0x8d,0xe5,0x04,0xc0,0xa0,0xe3, -0x0b,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1,0x0a,0x30,0xa0,0xe1,0xb0,0xc0,0x8d,0xe5, -0xa4,0xc0,0x8d,0xe2,0xa8,0x00,0x9d,0xe5,0xac,0xb0,0x8d,0xe5,0x01,0xb0,0x8b,0xe2, -0x00,0xc0,0x8d,0xe5,0xbb,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3,0x07,0x20,0xa0,0xe1, -0x0a,0x30,0xa0,0xe1,0x0d,0x10,0xa0,0xe3,0x46,0x00,0x00,0x1a,0xa4,0xc0,0x9d,0xe5, -0x00,0x90,0x8d,0xe5,0xa8,0x00,0x9d,0xe5,0x04,0xc0,0xa4,0xe5,0xb1,0x0b,0x00,0xeb, -0x08,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x09,0x10,0xa0,0xe1,0x02,0x80,0x88,0xe0, -0x7e,0x67,0x00,0xeb,0x04,0x00,0x5b,0xe3,0xe3,0xff,0xff,0x1a,0x00,0x30,0x96,0xe5, -0x05,0x40,0xa0,0xe1,0x14,0x50,0x9d,0xe5,0x21,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3, -0x2a,0x00,0x00,0x0a,0x9c,0x81,0x9f,0xe5,0x00,0x60,0xa0,0xe3,0x04,0x90,0xa0,0xe3, -0x00,0x00,0x98,0xe5,0xa4,0xc0,0x8d,0xe2,0x05,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1, -0x0a,0x30,0xa0,0xe1,0xac,0x60,0x8d,0xe5,0xb0,0x90,0x8d,0xe5,0x01,0x60,0x86,0xe2, -0x00,0xc0,0x8d,0xe5,0x97,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3,0x7c,0xff,0xff,0x1a, -0x04,0x20,0x95,0xe5,0xa4,0x30,0x9d,0xe5,0x03,0x00,0x52,0xe1,0x35,0x00,0x00,0x0a, -0x04,0x00,0x56,0xe3,0xed,0xff,0xff,0x1a,0x58,0x50,0x8d,0xe2,0x00,0x10,0xa0,0xe3, -0x28,0x20,0xa0,0xe3,0x05,0x00,0xa0,0xe1,0x5e,0x67,0x00,0xeb,0x04,0x00,0xa0,0xe1, -0x0a,0x10,0xa0,0xe3,0x05,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3,0xaa,0x21,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x01,0x00,0xa0,0x03,0x6a,0xff,0xff,0x1a,0x72,0xff,0xff,0xea, -0x07,0x40,0xa0,0xe1,0x58,0x50,0x8d,0xe2,0x66,0xff,0xff,0xea,0x1e,0x30,0xa0,0xe3, -0x07,0x40,0xa0,0xe1,0x58,0x50,0x8d,0xe2,0x78,0x30,0x8d,0xe5,0x61,0xff,0xff,0xea, -0xf4,0x30,0x9f,0xe5,0xb4,0x00,0x8d,0xe2,0x00,0x10,0x93,0xe5,0xbd,0x07,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x06,0x00,0x00,0x0a,0x15,0x30,0xa0,0xe3,0x58,0x50,0x8d,0xe2, -0x78,0x30,0x8d,0xe5,0x57,0xff,0xff,0xea,0x05,0x40,0xa0,0xe1,0x58,0x50,0x8d,0xe2, -0x54,0xff,0xff,0xea,0xb8,0x30,0x9f,0xe5,0x00,0x80,0x93,0xe5,0x16,0x07,0x00,0xeb, -0xb4,0x60,0x9d,0xe5,0x38,0x00,0x88,0xe5,0x00,0x00,0x56,0xe3,0x4c,0xff,0xff,0x0a, -0x11,0x07,0x00,0xeb,0x00,0x10,0xa0,0xe1,0x06,0x00,0xa0,0xe1,0x9c,0xfd,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xba,0xff,0xff,0x0a,0x0c,0x30,0xa0,0xe3,0x58,0x50,0x8d,0xe2, -0x78,0x30,0x8d,0xe5,0x43,0xff,0xff,0xea,0x10,0x90,0x9d,0xe5,0x00,0x50,0xa0,0xe1, -0xa0,0x60,0x8d,0xe2,0x00,0x00,0x98,0xe5,0x0b,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1, -0x0a,0x30,0xa0,0xe1,0x00,0x60,0x8d,0xe5,0x52,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x37,0xff,0xff,0x1a,0x04,0x20,0xb9,0xe5,0xa0,0x30,0x9d,0xe5,0x03,0x00,0x52,0xe1, -0x03,0x00,0x00,0x0a,0x01,0x50,0x85,0xe2,0x04,0x00,0x55,0xe3,0xf0,0xff,0xff,0x1a, -0xe8,0xff,0xff,0xea,0x18,0x30,0x8d,0xe2,0x0d,0x10,0xa0,0xe3,0x05,0xc2,0x83,0xe0, -0x20,0x30,0x9f,0xe5,0x07,0x20,0xa0,0xe1,0x00,0x00,0x93,0xe5,0x0a,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xce,0x0b,0x00,0xeb,0x04,0x00,0x55,0xe3,0xad,0xff,0xff,0x1a, -0xdc,0xff,0xff,0xea,0x64,0x94,0x02,0x40,0x00,0x90,0x02,0x40,0x78,0x93,0x02,0x40, -0xf0,0x4f,0x2d,0xe9,0x02,0x40,0xa0,0xe1,0x00,0x50,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xe1,0xdf,0x4d,0xe2,0x00,0x30,0xa0,0xe3,0x04,0x00,0x94,0xe5,0x01,0x70,0xa0,0xe1, -0x7c,0x33,0x8d,0xe5,0x74,0x33,0x8d,0xe5,0x00,0x00,0x92,0xe1,0x44,0x33,0x8d,0xe5, -0x02,0x00,0x00,0x0a,0x08,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x1a, -0x10,0x65,0x9f,0xe5,0xc9,0x7f,0x8d,0xe2,0x00,0x00,0x96,0xe5,0x00,0x00,0x50,0xe3, -0x23,0x0b,0x00,0x1b,0x03,0x10,0xa0,0xe3,0x05,0x00,0xa0,0xe1,0x5a,0x20,0x00,0xeb, -0x05,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3, -0x41,0x21,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xe1,0xdf,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x0c,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x1a,0xc4,0x64,0x9f,0xe5, -0xc9,0x7f,0x8d,0xe2,0xeb,0xff,0xff,0xea,0xde,0x0f,0x8d,0xe2,0x9a,0x0a,0x00,0xeb, -0x78,0x33,0x9d,0xe5,0x05,0x00,0x53,0xe3,0x4d,0x00,0x00,0x8a,0xa8,0xa4,0x9f,0xe5, -0x00,0x30,0x9a,0xe5,0x21,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3,0x9c,0x84,0x9f,0x15, -0x4c,0x00,0x00,0x0a,0x00,0x30,0x98,0xe5,0x05,0x00,0x53,0xe3,0x54,0x00,0x00,0x0a, -0x08,0x90,0x94,0xe5,0x0c,0x30,0x94,0xe5,0x74,0x33,0x8d,0xe5,0x00,0x00,0x59,0xe3, -0xd6,0xff,0xff,0x0a,0x00,0x30,0xa0,0xe3,0x05,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1, -0x04,0x20,0xa0,0xe1,0x8c,0x1e,0x00,0xeb,0x00,0x30,0x50,0xe2,0xcf,0xff,0xff,0x1a, -0xc9,0x7f,0x8d,0xe2,0x05,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1, -0x19,0x21,0x00,0xeb,0x00,0x60,0x50,0xe2,0x6c,0x00,0x00,0x1a,0x00,0x30,0x98,0xe5, -0x05,0x00,0x53,0xe3,0xd4,0x00,0x00,0x0a,0x06,0x00,0x53,0xe3,0x5e,0x00,0x00,0x0a, -0x00,0x20,0xa0,0xe3,0x01,0x30,0xa0,0xe3,0x00,0x60,0x94,0xe5,0x02,0xb0,0xa0,0xe1, -0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x02,0x00,0x00,0xea,0x04,0x60,0x56,0xe0, -0x04,0x90,0x89,0xe0,0x85,0x00,0x00,0x0a,0x02,0x0b,0x56,0xe3,0x06,0x40,0xa0,0x31, -0x02,0x4b,0xa0,0x23,0x09,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x0b,0x30,0xa0,0xe1, -0x05,0x00,0xa0,0xe1,0x00,0xb0,0x8d,0xe5,0x49,0x20,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x52,0x00,0x00,0x1a,0x00,0x30,0x98,0xe5,0x05,0x00,0x53,0xe3,0xee,0xff,0xff,0x1a, -0x18,0xc0,0x9d,0xe5,0x04,0x00,0x56,0xe1,0x01,0xc0,0xa0,0x03,0x1c,0x20,0x9d,0xe5, -0x09,0x00,0xa0,0xe1,0x04,0x10,0xa0,0xe1,0x18,0xc0,0x8d,0xe5,0x0c,0x30,0xa0,0xe1, -0x01,0xc0,0xa0,0xe3,0x04,0xb0,0x8d,0xe5,0x00,0xc0,0x8d,0xe5,0x22,0xce,0x8d,0xe2, -0x1c,0xb0,0x8d,0xe5,0x08,0xc0,0x8d,0xe5,0xc5,0x09,0x00,0xeb,0x00,0x00,0x50,0xe3, -0xdd,0xff,0xff,0x1a,0x1e,0x30,0xa0,0xe3,0x78,0x63,0x9f,0xe5,0x44,0x33,0x8d,0xe5, -0x98,0xff,0xff,0xea,0x11,0x30,0xa0,0xe3,0x68,0x63,0x9f,0xe5,0x44,0x33,0x8d,0xe5, -0xc9,0x7f,0x8d,0xe2,0x93,0xff,0xff,0xea,0x60,0x83,0x9f,0xe5,0xdf,0x0f,0x8d,0xe2, -0x00,0x10,0x98,0xe5,0xff,0x06,0x00,0xeb,0x00,0x30,0x50,0xe2,0x31,0x00,0x00,0x0a, -0x15,0x30,0xa0,0xe3,0x3c,0x63,0x9f,0xe5,0x44,0x33,0x8d,0xe5,0xc9,0x7f,0x8d,0xe2, -0x88,0xff,0xff,0xea,0x2c,0x63,0x9f,0xe5,0x00,0x90,0xa0,0xe3,0x37,0xbe,0x8d,0xe2, -0x04,0xc0,0xa0,0xe3,0x00,0x00,0x96,0xe5,0x70,0xc3,0x8d,0xe5,0x0c,0x10,0xa0,0xe3, -0xdd,0xcf,0x8d,0xe2,0x0b,0x20,0xa0,0xe1,0xdb,0x3f,0x8d,0xe2,0x6c,0x93,0x8d,0xe5, -0x00,0xc0,0x8d,0xe5,0x01,0x90,0x89,0xe2,0xa2,0x0a,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x77,0xff,0xff,0x1a,0x74,0x33,0x9d,0xe5,0x01,0x01,0x13,0xe3,0x02,0x00,0x00,0x0a, -0x04,0x00,0x59,0xe3,0xed,0xff,0xff,0x1a,0x71,0xff,0xff,0xea,0xd4,0x32,0x9f,0xe5, -0xda,0xcf,0x8d,0xe2,0x0b,0x10,0xa0,0xe3,0x0b,0x20,0xa0,0xe1,0x00,0x00,0x93,0xe5, -0xdb,0x3f,0x8d,0xe2,0x00,0xc0,0x8d,0xe5,0x92,0x0a,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x68,0x93,0x9d,0x05,0x8c,0xff,0xff,0x0a,0x65,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe3, -0x05,0x00,0xa0,0xe1,0x22,0x1e,0x8d,0xe2,0x01,0x2c,0xa0,0xe3,0x0c,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xf6,0x1f,0x00,0xeb,0x00,0x00,0x50,0xe3,0x97,0xff,0xff,0x0a, -0x80,0x62,0x9f,0xe5,0x5b,0xff,0xff,0xea,0x00,0x90,0x9a,0xe5,0x14,0x30,0x8d,0xe5, -0x2d,0x06,0x00,0xeb,0x7c,0x63,0x9d,0xe5,0x38,0x00,0x89,0xe5,0x14,0x30,0x9d,0xe5, -0x00,0x00,0x56,0xe3,0x64,0xff,0xff,0x0a,0x14,0x30,0x8d,0xe5,0x04,0xb0,0xa0,0xe3, -0x25,0x06,0x00,0xeb,0x14,0x30,0x9d,0xe5,0x0e,0x9d,0x8d,0xe2,0x64,0xb3,0x8d,0xe5, -0x68,0x03,0x8d,0xe5,0x60,0x33,0x8d,0xe5,0x5c,0x33,0x8d,0xe5,0x7f,0xfc,0xff,0xeb, -0x00,0x30,0x9a,0xe5,0x06,0x10,0xa0,0xe1,0x18,0x20,0x39,0xe5,0x18,0x00,0x8d,0xe5, -0xe4,0xc0,0x93,0xe5,0x1c,0x62,0x9f,0xe5,0x0c,0x00,0xa0,0xe1,0x3c,0xc0,0x83,0xe5, -0x3a,0x66,0x00,0xeb,0x00,0x30,0x9a,0xe5,0x09,0x00,0xa0,0xe1,0x06,0x20,0xa0,0xe1, -0x3c,0x10,0x93,0xe5,0xf7,0x09,0x00,0xeb,0x00,0x00,0x50,0xe3,0x11,0x00,0x00,0x0a, -0x0c,0x30,0xa0,0xe3,0xc9,0x7f,0x8d,0xe2,0x44,0x33,0x8d,0xe5,0x35,0xff,0xff,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x40,0xa0,0xe3,0xe4,0x11,0x9f,0xe5,0xe4,0x20,0x93,0xe5, -0x00,0x10,0x82,0xe5,0xe4,0x20,0x93,0xe5,0x40,0x40,0x83,0xe5,0x04,0x20,0x82,0xe2, -0xe4,0x20,0x83,0xe5,0xff,0x05,0x00,0xeb,0x74,0x03,0x9d,0xe5,0xe4,0xfc,0xff,0xeb, -0x04,0x00,0xa0,0xe1,0x33,0xff,0xff,0xea,0x18,0xc0,0x9d,0xe5,0x20,0x90,0x8d,0xe2, -0x00,0x00,0x96,0xe5,0x03,0x10,0xa0,0xe3,0xd9,0x2f,0x8d,0xe2,0x36,0x3e,0x8d,0xe2, -0x60,0xc3,0x8d,0xe5,0x00,0x90,0x8d,0xe5,0x46,0x0a,0x00,0xeb,0x00,0xc0,0x50,0xe2, -0xe2,0xff,0xff,0x1a,0x00,0x00,0x96,0xe5,0x0b,0x10,0xa0,0xe1,0x60,0xc3,0x8d,0xe5, -0xd9,0x2f,0x8d,0xe2,0xd7,0xcf,0x8d,0xe2,0x36,0x3e,0x8d,0xe2,0x00,0xc0,0x8d,0xe5, -0x3c,0x0a,0x00,0xeb,0x00,0x00,0x50,0xe3,0xd8,0xff,0xff,0x1a,0x5c,0x33,0x9d,0xe5, -0x18,0x20,0x9d,0xe5,0x03,0x00,0x52,0xe1,0x07,0x00,0x00,0x3a,0x09,0x30,0xa0,0xe1, -0x22,0x1e,0x8d,0xe2,0x01,0x00,0x00,0xea,0x01,0x00,0x53,0xe1,0xcf,0xff,0xff,0x0a, -0x01,0x20,0xd3,0xe4,0x00,0x00,0x52,0xe3,0xfa,0xff,0xff,0x0a,0x09,0x10,0xa0,0xe1, -0x00,0x20,0xa0,0xe3,0x2c,0x01,0x9f,0xe5,0x45,0x06,0x00,0xeb,0x09,0x00,0xa0,0xe1, -0x99,0x63,0x00,0xeb,0x9e,0x63,0x00,0xeb,0x00,0x00,0x50,0xe3,0xc3,0xff,0xff,0x0a, -0x00,0x30,0x9a,0xe5,0x01,0x20,0xa0,0xe3,0x38,0x00,0x93,0xe5,0xe4,0x10,0x93,0xe5, -0x1d,0x20,0xc3,0xe5,0x7f,0x00,0x80,0xe2,0x21,0x20,0xc3,0xe5,0x7f,0x20,0xc0,0xe3, -0x02,0x20,0x81,0xe0,0xe4,0x20,0x83,0xe5,0x11,0xff,0xff,0xea,0x20,0xc0,0x8d,0xe2, -0x06,0x10,0xa0,0xe1,0x0c,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x22,0xbe,0x8d,0xe2, -0x14,0xc0,0x8d,0xe5,0x44,0x6e,0x00,0xeb,0x06,0x30,0xa0,0xe1,0x05,0x00,0xa0,0xe1, -0x0b,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x00,0x60,0x8d,0xe5,0x7c,0x1f,0x00,0xeb, -0x00,0x60,0x50,0xe2,0x14,0xc0,0x9d,0xe5,0x84,0xff,0xff,0x1a,0x0b,0x00,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0xd9,0x65,0x00,0xeb,0x00,0xe0,0x50,0xe2, -0x0c,0x00,0x00,0x0a,0x01,0x20,0xa0,0xe3,0x0b,0x00,0xa0,0xe1,0x02,0x30,0xa0,0xe1, -0x10,0x10,0xa0,0xe3,0x00,0x60,0x8d,0xe5,0x04,0x60,0x8d,0xe5,0x08,0x60,0x8d,0xe5, -0xfb,0x08,0x00,0xeb,0x00,0x00,0x50,0xe3,0x60,0x20,0x9f,0x15,0x00,0x30,0x92,0x15, -0x08,0xff,0xff,0x1a,0x32,0xff,0xff,0xea,0x48,0x60,0x9f,0xe5,0xd3,0xcf,0x8d,0xe2, -0xdb,0x3f,0x8d,0xe2,0x37,0x2e,0x8d,0xe2,0x0d,0x10,0xa0,0xe3,0x6c,0xe3,0x8d,0xe5, -0x00,0x00,0x96,0xe5,0x04,0x60,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x14,0xc0,0x8d,0xe5, -0x70,0x63,0x8d,0xe5,0xeb,0x09,0x00,0xeb,0x14,0xc0,0x9d,0xe5,0x0b,0x00,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x0c,0x10,0xa0,0xe1,0xb8,0x65,0x00,0xeb,0x0c,0xc0,0x9f,0xe5, -0x00,0x30,0x9c,0xe5,0xf3,0xfe,0xff,0xea,0x00,0x90,0x02,0x40,0x64,0x94,0x02,0x40, -0x78,0x93,0x02,0x40,0xd8,0xad,0xfe,0x5a,0x9c,0x00,0x90,0x00,0xf0,0x4f,0x2d,0xe9, -0x94,0xd0,0x4d,0xe2,0x70,0x89,0x9f,0xe5,0x00,0x50,0xa0,0xe3,0x90,0x40,0x8d,0xe2, -0x04,0x50,0x24,0xe5,0x08,0x00,0xa0,0xe1,0xee,0xfb,0xff,0xeb,0x84,0x05,0x00,0xeb, -0x58,0x09,0x9f,0xe5,0xe8,0x20,0xa0,0xe3,0x00,0x10,0x98,0xe5,0xa3,0x65,0x00,0xeb, -0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x05,0x20,0xa0,0xe1,0xc9,0x1b,0x00,0xeb, -0x05,0x00,0x50,0xe1,0x82,0x00,0x00,0x1a,0x34,0xb9,0x9f,0xe5,0x88,0x60,0x8d,0xe2, -0x8c,0x40,0x9d,0xe5,0x84,0x50,0x8d,0xe2,0x04,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x05,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3,0xd9,0x1b,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x77,0x00,0x00,0x1a,0x88,0x30,0x9d,0xe5,0x01,0x30,0x43,0xe2,0x18,0x00,0x53,0xe3, -0x03,0xf1,0x9f,0x97,0xb2,0x00,0x00,0xea,0xd8,0x93,0x00,0x40,0x68,0x93,0x00,0x40, -0x4c,0x94,0x00,0x40,0xf8,0x93,0x00,0x40,0x48,0x93,0x00,0x40,0x28,0x93,0x00,0x40, -0xd4,0x92,0x00,0x40,0x5c,0x92,0x00,0x40,0xc8,0x91,0x00,0x40,0xc4,0x93,0x00,0x40, -0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40, -0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40, -0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40,0xc4,0x93,0x00,0x40, -0xc4,0x93,0x00,0x40,0x84,0x91,0x00,0x40,0x5c,0x91,0x00,0x40,0x8c,0x40,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x19,0x10,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x04,0x00,0xa0,0xe1, -0x2d,0x1d,0x00,0xeb,0x00,0x00,0x50,0xe3,0xc8,0x00,0x00,0x1a,0x8c,0x40,0x9d,0xe5, -0xd0,0xff,0xff,0xea,0x84,0x70,0x9d,0xe5,0x00,0xa0,0xa0,0xe3,0x8c,0x40,0x9d,0xe5, -0x40,0xa0,0x8d,0xe5,0x08,0x30,0x97,0xe5,0x02,0x00,0x53,0xe3,0xc9,0xff,0xff,0x1a, -0x50,0x30,0x8d,0xe5,0x06,0x63,0x00,0xeb,0x0a,0x00,0x50,0xe1,0x10,0x70,0x97,0xe5, -0x4c,0x00,0x8d,0xe5,0x30,0x01,0x00,0x1a,0x20,0x30,0xa0,0xe3,0x20,0x70,0x8d,0xe2, -0x40,0x30,0x8d,0xe5,0x36,0x00,0x00,0xea,0x00,0x30,0xa0,0xe3,0x74,0x00,0x8d,0xe2, -0x6c,0x30,0x8d,0xe5,0x40,0x30,0x8d,0xe5,0x8c,0x40,0x9d,0xe5,0x84,0xa0,0x9d,0xe5, -0xda,0x04,0x00,0xeb,0x04,0x30,0xa0,0xe3,0x05,0x00,0xa0,0xe3,0x70,0x10,0x8d,0xe2, -0x6c,0x20,0x8d,0xe2,0x6c,0x30,0x8d,0xe5,0x0f,0x42,0x00,0xeb,0x00,0x90,0x50,0xe2, -0x6d,0x00,0x00,0x1a,0x20,0x70,0x8d,0xe2,0x09,0x10,0xa0,0xe1,0x28,0x20,0xa0,0xe3, -0x07,0x00,0xa0,0xe1,0x47,0x65,0x00,0xeb,0x00,0x00,0x9a,0xe5,0xe8,0x08,0x00,0xeb, -0x09,0x30,0xa0,0xe1,0x04,0x00,0xa0,0xe1,0x09,0x10,0xa0,0xe3,0x0a,0x20,0xa0,0xe1, -0xfd,0x1c,0x00,0xeb,0x00,0x30,0x50,0xe2,0x19,0x00,0x00,0x1a,0x04,0x00,0xa0,0xe1, -0x0a,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1,0x8b,0x1f,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x13,0x00,0x00,0x1a,0x8c,0x40,0x9d,0xe5,0x9a,0xff,0xff,0xea,0x84,0xa0,0x9d,0xe5, -0x00,0x90,0xa0,0xe3,0x78,0x00,0x8d,0xe2,0x20,0x70,0x8d,0xe2,0x8c,0x40,0x9d,0xe5, -0x40,0x90,0x8d,0xe5,0xb5,0x04,0x00,0xeb,0x07,0x00,0xa0,0xe1,0x09,0x10,0xa0,0xe1, -0x28,0x20,0xa0,0xe3,0x2b,0x65,0x00,0xeb,0x00,0x00,0x9a,0xe5,0x74,0x10,0x8d,0xe2, -0x6a,0x04,0x00,0xeb,0x09,0x00,0x50,0xe1,0xce,0x00,0x00,0x0a,0x11,0x30,0xa0,0xe3, -0x40,0x30,0x8d,0xe5,0x04,0x00,0xa0,0xe1,0x03,0x10,0xa0,0xe3,0x86,0x1e,0x00,0xeb, -0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3, -0x6d,0x1f,0x00,0xeb,0x8c,0x00,0x9d,0xe5,0x55,0x1b,0x00,0xeb,0x94,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x00,0x20,0x98,0xe5,0x00,0x30,0xa0,0xe3,0x6c,0x30,0x8d,0xe5, -0x70,0x30,0x8d,0xe5,0x68,0x30,0x8d,0xe5,0x40,0x30,0x8d,0xe5,0x21,0x30,0xd2,0xe5, -0x84,0x00,0x9d,0xe5,0x8c,0x40,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x14,0x00,0x8d,0xe5, -0x82,0x00,0x00,0x1a,0x78,0x00,0x8d,0xe2,0xbf,0x08,0x00,0xeb,0x78,0x30,0x9d,0xe5, -0x05,0x00,0x53,0xe3,0x6a,0x00,0x00,0x9a,0x11,0x30,0xa0,0xe3,0x20,0x70,0x8d,0xe2, -0x40,0x30,0x8d,0xe5,0xde,0xff,0xff,0xea,0x8c,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3, -0x84,0x20,0x9d,0xe5,0xf1,0xfd,0xff,0xeb,0x01,0x00,0x50,0xe3,0xe0,0xff,0xff,0x1a, -0x8c,0x40,0x9d,0xe5,0x5f,0xff,0xff,0xea,0x8c,0x00,0x9d,0xe5,0x05,0x10,0xa0,0xe3, -0x84,0x20,0x9d,0xe5,0xf3,0xfc,0xff,0xeb,0x01,0x00,0x50,0xe3,0xd8,0xff,0xff,0x1a, -0x8c,0x40,0x9d,0xe5,0x57,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3,0x8c,0x40,0x9d,0xe5, -0x68,0x30,0x8d,0xe5,0x40,0x30,0x8d,0xe5,0xc7,0x04,0x00,0xeb,0x00,0x30,0x98,0xe5, -0x80,0x00,0x8d,0xe5,0x21,0x20,0xd3,0xe5,0x01,0x00,0x52,0xe3,0x82,0x00,0x00,0x1a, -0x3c,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0x68,0x30,0x8d,0xe5,0x06,0x00,0x00,0x0a, -0x00,0x30,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x02,0x10,0xa0,0xe3,0x80,0x20,0x8d,0xe2, -0x9d,0x1c,0x00,0xeb,0x00,0x30,0x50,0xe2,0xa0,0x00,0x00,0x0a,0x20,0x70,0x8d,0xe2, -0xb7,0xff,0xff,0xea,0x8c,0x00,0x9d,0xe5,0x02,0x10,0xa0,0xe3,0x3e,0x1e,0x00,0xeb, -0x8c,0x40,0x9d,0xe5,0x3b,0xff,0xff,0xea,0x8c,0x00,0x9d,0xe5,0x01,0x10,0xa0,0xe3, -0x84,0x20,0x9d,0xe5,0xf9,0xfb,0xff,0xeb,0x01,0x00,0x50,0xe3,0xb4,0xff,0xff,0x1a, -0x8c,0x40,0x9d,0xe5,0x33,0xff,0xff,0xea,0x84,0x40,0x9d,0xe5,0x00,0x30,0xa0,0xe3, -0x8c,0xa0,0x9d,0xe5,0x40,0x30,0x8d,0xe5,0x00,0x90,0x94,0xe5,0x03,0x00,0x59,0xe1, -0x0a,0x00,0x00,0x0a,0x00,0x30,0x98,0xe5,0x21,0x20,0xd3,0xe5,0x38,0x90,0x83,0xe5, -0x01,0x00,0x52,0xe3,0x3c,0x70,0x93,0x05,0xe4,0x70,0x93,0x15,0x00,0x00,0x57,0xe3, -0x02,0x00,0x00,0x0a,0x98,0x04,0x00,0xeb,0x00,0x00,0x59,0xe1,0xca,0x00,0x00,0x0a, -0x0a,0x40,0xa0,0xe1,0x20,0x70,0x8d,0xe2,0x95,0xff,0xff,0xea,0x8c,0x40,0x9d,0xe5, -0x90,0x70,0x8d,0xe2,0x90,0x04,0x00,0xeb,0x00,0xa0,0x98,0xe5,0x14,0x00,0x27,0xe5, -0x8d,0x04,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x38,0x00,0x8a,0xe5,0x03,0x10,0xa0,0xe3, -0x07,0x20,0xa0,0xe1,0x04,0x00,0xa0,0xe1,0x6b,0x1c,0x00,0xeb,0x00,0x30,0x50,0xe2, -0x06,0x00,0x00,0x1a,0x60,0xc5,0x9f,0xe5,0x04,0x00,0xa0,0xe1,0x7c,0x20,0x9d,0xe5, -0x00,0x10,0x9c,0xe5,0x91,0x1b,0x00,0xeb,0x00,0x00,0x50,0xe3,0x36,0xff,0xff,0x0a, -0x04,0x00,0xa0,0xe1,0x03,0x10,0xa0,0xe3,0x07,0x1e,0x00,0xeb,0x00,0x20,0xa0,0xe3, -0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0xee,0x1e,0x00,0xeb, -0x7f,0xff,0xff,0xea,0x2c,0x25,0x9f,0xe5,0x68,0x00,0x8d,0xe2,0x00,0x10,0x92,0xe5, -0x0c,0x05,0x00,0xeb,0x00,0x00,0x50,0xe3,0x3a,0x00,0x00,0x1a,0x08,0x35,0x9f,0xe5, -0x00,0xa0,0x93,0xe5,0x6c,0x04,0x00,0xeb,0x68,0x70,0x9d,0xe5,0x38,0x00,0x8a,0xe5, -0x00,0x00,0x57,0xe3,0xb0,0xff,0xff,0x0a,0x67,0x04,0x00,0xeb,0x00,0x10,0xa0,0xe1, -0x07,0x00,0xa0,0xe1,0xf2,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3,0x11,0x01,0x00,0x1a, -0xe4,0x74,0x9f,0xe5,0x00,0x00,0xa0,0xe3,0x6c,0xa0,0x8d,0xe2,0x70,0x90,0x8d,0xe2, -0x1b,0x10,0xa0,0xe3,0x0a,0x20,0xa0,0xe1,0x00,0xc0,0x97,0xe5,0x09,0x30,0xa0,0xe1, -0x00,0x00,0x8d,0xe5,0x0c,0x00,0xa0,0xe1,0xaa,0x08,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x9d,0xff,0xff,0x1a,0x14,0xc0,0x9d,0xe5,0x0a,0x20,0xa0,0xe1,0x00,0x00,0x97,0xe5, -0x1b,0x10,0xa0,0xe3,0x09,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x30,0x09,0x00,0xeb, -0x00,0xa0,0x50,0xe2,0x94,0xff,0xff,0x1a,0x20,0x70,0x8d,0xe2,0x0a,0x10,0xa0,0xe1, -0x28,0x20,0xa0,0xe3,0x07,0x00,0xa0,0xe1,0x6e,0x64,0x00,0xeb,0x0a,0x30,0xa0,0xe1, -0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe3,0x14,0x20,0x9d,0xe5,0x26,0x1c,0x00,0xeb, -0x00,0x30,0x50,0xe2,0x42,0xff,0xff,0x1a,0x27,0xff,0xff,0xea,0x78,0x00,0x8d,0xe2, -0x19,0x08,0x00,0xeb,0x78,0x30,0x9d,0xe5,0x05,0x00,0x53,0xe3,0x59,0xff,0xff,0x8a, -0x40,0x24,0x9f,0xe5,0x68,0x00,0x8d,0xe2,0x00,0x10,0x92,0xe5,0xd1,0x04,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xd7,0x00,0x00,0x0a,0x15,0x30,0xa0,0xe3,0x20,0x70,0x8d,0xe2, -0x40,0x30,0x8d,0xe5,0x32,0xff,0xff,0xea,0x78,0x30,0x9d,0xe5,0x06,0x00,0x53,0xe3, -0x05,0x00,0x00,0x0a,0x74,0x00,0x9d,0xe5,0x00,0x00,0x53,0xe1,0x03,0x00,0x00,0x0a, -0x12,0x30,0xa0,0xe3,0x40,0x30,0x8d,0xe5,0x29,0xff,0xff,0xea,0x74,0x00,0x9d,0xe5, -0xfd,0x07,0x00,0xeb,0x74,0x30,0x9d,0xe5,0x04,0x00,0xa0,0xe1,0x08,0x10,0xa0,0xe3, -0x03,0x00,0x53,0xe3,0x00,0x30,0x98,0x05,0x08,0x20,0xa0,0x03,0x00,0x20,0x98,0x15, -0x14,0x20,0x83,0x05,0x14,0x30,0x82,0x15,0x00,0x30,0xa0,0xe3,0x0a,0x20,0xa0,0xe1, -0xfd,0x1b,0x00,0xeb,0x00,0x30,0x50,0xe2,0x19,0xff,0xff,0x1a,0xfe,0xfe,0xff,0xea, -0x20,0x70,0x8d,0xe2,0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3,0x07,0x20,0xa0,0xe1, -0x89,0x1e,0x00,0xeb,0x00,0x30,0x50,0xe2,0x11,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1, -0x68,0x10,0x9d,0xe5,0x80,0x20,0x9d,0xe5,0x1c,0x1b,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x0b,0xff,0xff,0x1a,0x8c,0x40,0x9d,0xe5,0x92,0xfe,0xff,0xea,0x68,0xc0,0x8d,0xe2, -0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x0a,0x20,0xa0,0xe1,0x03,0x30,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0x56,0x69,0x00,0xeb,0x0a,0x00,0x50,0xe1,0x92,0x00,0x00,0x0a, -0x4c,0x10,0x9d,0xe5,0x02,0x31,0xa0,0xe3,0x00,0x00,0x57,0xe3,0x69,0x00,0x00,0x0a, -0x00,0x00,0x51,0xe3,0x00,0x20,0xa0,0x13,0x22,0x00,0x00,0x0a,0x03,0xb0,0x82,0xe7, -0x04,0x20,0x82,0xe2,0x02,0x00,0x51,0xe1,0xfb,0xff,0xff,0x8a,0x00,0x20,0x93,0xe5, -0x1c,0x03,0x9f,0xe5,0x00,0x00,0x52,0xe1,0xb6,0xfe,0xff,0x1a,0x03,0x00,0xa0,0xe1, -0x00,0x20,0xa0,0xe3,0x02,0x00,0x00,0xea,0x04,0xc0,0xb0,0xe5,0x0b,0x00,0x5c,0xe1, -0xb0,0xfe,0xff,0x1a,0x04,0x20,0x82,0xe2,0x02,0x00,0x51,0xe1,0xf9,0xff,0xff,0x8a, -0x00,0x20,0xa0,0xe3,0xf4,0xc2,0x9f,0xe5,0x03,0xc0,0x82,0xe7,0x04,0x20,0x82,0xe2, -0x02,0x00,0x51,0xe1,0xfa,0xff,0xff,0x8a,0x00,0x20,0x93,0xe5,0x0c,0x00,0x52,0xe1, -0xa4,0xfe,0xff,0x1a,0x00,0x20,0xa0,0xe3,0x03,0x00,0x00,0xea,0x04,0x00,0xb3,0xe5, -0xc8,0xc2,0x9f,0xe5,0x0c,0x00,0x50,0xe1,0x9e,0xfe,0xff,0x1a,0x04,0x20,0x82,0xe2, -0x02,0x00,0x51,0xe1,0xf8,0xff,0xff,0x8a,0x00,0x30,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x18,0x10,0xa0,0xe3,0x48,0x20,0x8d,0xe2,0xb3,0x1b,0x00,0xeb,0x00,0x30,0x50,0xe2, -0x15,0xff,0xff,0x1a,0x20,0x70,0x8d,0xe2,0xb3,0xfe,0xff,0xea,0x0a,0x00,0xa0,0xe1, -0x04,0x10,0xa0,0xe3,0x04,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3,0xaa,0x1b,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x2d,0xff,0xff,0x1a,0x00,0xc0,0x94,0xe5,0x07,0x90,0xa0,0xe1, -0x18,0x00,0x8d,0xe5,0x01,0x00,0xa0,0xe3,0x1c,0x70,0x8d,0xe5,0x14,0x00,0x8d,0xe5, -0x0c,0x70,0xa0,0xe1,0x02,0x00,0x00,0xea,0x04,0x70,0x57,0xe0,0x04,0x90,0x89,0xe0, -0x6c,0x00,0x00,0x0a,0x02,0x0b,0x57,0xe3,0x07,0x40,0xa0,0x31,0x02,0x4b,0xa0,0x23, -0x00,0x30,0xa0,0xe3,0x09,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x0a,0x00,0xa0,0xe1, -0x00,0x30,0x8d,0xe5,0x72,0x1d,0x00,0xeb,0x00,0x00,0x50,0xe3,0x17,0xff,0xff,0x1a, -0x10,0x22,0x9f,0xe5,0x00,0x30,0x92,0xe5,0x05,0x00,0x53,0xe3,0xed,0xff,0xff,0x1a, -0x14,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x03,0x10,0xa0,0xe1,0x6e,0x00,0x00,0x1a, -0x18,0xc0,0x9d,0xe5,0x04,0x00,0x57,0xe1,0x01,0xc0,0xa0,0x03,0x01,0x00,0x89,0xe0, -0x14,0x20,0x9d,0xe5,0x04,0x10,0x61,0xe0,0x18,0xc0,0x8d,0xe5,0x0c,0x30,0xa0,0xe1, -0x01,0xc0,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x04,0xc0,0x8d,0xe5,0x00,0xc0,0xa0,0xe3, -0x14,0xc0,0x8d,0xe5,0x08,0xc0,0x8d,0xe5,0xe9,0x06,0x00,0xeb,0x00,0x00,0x50,0xe3, -0xd8,0xff,0xff,0x1a,0x1e,0x30,0xa0,0xe3,0x0a,0x40,0xa0,0xe1,0x20,0x70,0x8d,0xe2, -0x40,0x30,0x8d,0xe5,0x92,0xfe,0xff,0xea,0x21,0x1a,0xb0,0xe1,0xb9,0xff,0xff,0x0a, -0x07,0xba,0x83,0xe7,0x01,0x70,0x87,0xe2,0x07,0x00,0x51,0xe1,0xfb,0xff,0xff,0x8a, -0x00,0x20,0x93,0xe5,0x78,0xc1,0x9f,0xe5,0x0c,0x00,0x52,0xe1,0x4d,0xfe,0xff,0x1a, -0x00,0x20,0xa0,0xe3,0x02,0x00,0x00,0xea,0x02,0x0a,0x93,0xe7,0x0b,0x00,0x50,0xe1, -0x48,0xfe,0xff,0x1a,0x01,0x20,0x82,0xe2,0x02,0x00,0x51,0xe1,0xf9,0xff,0xff,0x8a, -0x00,0x20,0xa0,0xe3,0x54,0x01,0x9f,0xe5,0x02,0x0a,0x83,0xe7,0x01,0x20,0x82,0xe2, -0x02,0x00,0x51,0xe1,0xfa,0xff,0xff,0x8a,0x00,0x20,0x93,0xe5,0x00,0x00,0x52,0xe1, -0x3c,0xfe,0xff,0x1a,0x00,0x20,0xa0,0xe3,0x03,0x00,0x00,0xea,0x02,0x0a,0x93,0xe7, -0x28,0xc1,0x9f,0xe5,0x0c,0x00,0x50,0xe1,0x36,0xfe,0xff,0x1a,0x01,0x20,0x82,0xe2, -0x02,0x00,0x51,0xe1,0xf8,0xff,0xff,0x8a,0x96,0xff,0xff,0xea,0x68,0x00,0x9d,0xe5, -0x01,0x1a,0xa0,0xe3,0x04,0xa8,0x90,0xe5,0xe3,0x68,0x00,0xeb,0x2a,0x34,0xa0,0xe1, -0xff,0x30,0x03,0xe2,0x20,0x00,0x53,0xe3,0x64,0xff,0xff,0x1a,0x4c,0x10,0x9d,0xe5, -0x01,0x00,0xa0,0xe3,0x40,0x30,0xa0,0xe3,0x10,0x11,0xa0,0xe1,0x4c,0x10,0x8d,0xe5, -0x40,0x10,0x41,0xe2,0x5f,0xff,0xff,0xea,0xbc,0x30,0x9f,0xe5,0x00,0x70,0x93,0xe5, -0x59,0x03,0x00,0xeb,0x68,0x30,0x9d,0xe5,0x38,0x00,0x87,0xe5,0x00,0x00,0x53,0xe3, -0x9d,0xfe,0xff,0x0a,0x03,0x00,0xa0,0xe1,0x80,0x10,0x9d,0xe5,0xe0,0xf9,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x91,0xfe,0xff,0x0a,0x0c,0x30,0xa0,0xe3,0x20,0x70,0x8d,0xe2, -0x40,0x30,0x8d,0xe5,0x4e,0xfe,0xff,0xea,0x07,0xc0,0xa0,0xe1,0x1c,0x70,0x9d,0xe5, -0x10,0xc0,0x8d,0xe5,0x48,0x03,0x00,0xeb,0x00,0x10,0xa0,0xe1,0x07,0x00,0xa0,0xe1, -0xd3,0xf9,0xff,0xeb,0x10,0xc0,0x9d,0xe5,0x20,0x70,0x8d,0xe2,0x00,0x40,0xa0,0xe1, -0x28,0x20,0xa0,0xe3,0x07,0x00,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x65,0x63,0x00,0xeb, -0x00,0x00,0x54,0xe3,0x10,0xc0,0x9d,0xe5,0x06,0x00,0x00,0x0a,0x02,0x30,0xa0,0xe3, -0x0a,0x40,0xa0,0xe1,0x40,0x30,0x8d,0xe5,0x39,0xfe,0xff,0xea,0xa5,0x03,0x00,0xeb, -0x00,0x10,0xa0,0xe1,0x8d,0xff,0xff,0xea,0x0a,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe3, -0x07,0x20,0xa0,0xe1,0x0c,0x30,0xa0,0xe1,0xa7,0x1d,0x00,0xeb,0x00,0x00,0x50,0xe3, -0xe5,0xfd,0xff,0x0a,0x0a,0x40,0xa0,0xe1,0x2d,0xfe,0xff,0xea,0x64,0x94,0x02,0x40, -0x7c,0x93,0x02,0x40,0x55,0xaa,0x55,0xaa,0x78,0x93,0x02,0x40,0x00,0x90,0x02,0x40, -0xaa,0x55,0xaa,0x55,0x98,0xfd,0xff,0xea,0x38,0x40,0x2d,0xe9,0xa0,0x50,0x9f,0xe5, -0x00,0x40,0x95,0xe5,0x00,0x00,0x54,0xe3,0x38,0x80,0xbd,0x18,0x04,0x20,0xa0,0xe1, -0x90,0x00,0x9f,0xe5,0x02,0x10,0xa0,0xe3,0x07,0x48,0x00,0xeb,0x84,0x00,0x9f,0xe5, -0x01,0x10,0xa0,0xe3,0x7b,0x48,0x00,0xeb,0x7f,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x78,0x48,0x00,0xeb,0x7e,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x75,0x48,0x00,0xeb, -0x3d,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x3c,0x4f,0x00,0xeb,0x3f,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x39,0x4f,0x00,0xeb,0x3e,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x36,0x4f,0x00,0xeb,0x04,0x10,0xa0,0xe1,0x3d,0x00,0xa0,0xe3,0x33,0x4f,0x00,0xeb, -0x04,0x10,0xa0,0xe1,0x3f,0x00,0xa0,0xe3,0x30,0x4f,0x00,0xeb,0x3e,0x00,0xa0,0xe3, -0x04,0x10,0xa0,0xe1,0x2d,0x4f,0x00,0xeb,0x1c,0x30,0x9f,0xe5,0x18,0x40,0xc3,0xe5, -0x1a,0x40,0xc3,0xe5,0x19,0x40,0xc3,0xe5,0x1b,0x40,0xc3,0xe5,0x00,0x30,0x85,0xe5, -0x38,0x80,0xbd,0xe8,0x60,0x90,0x02,0x40,0x7d,0x00,0xc8,0x01,0x44,0x90,0x02,0x40, -0xf0,0x41,0x2d,0xe9,0x00,0x10,0xa0,0xe3,0x88,0x51,0x9f,0xe5,0x00,0x40,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x05,0x00,0xa0,0xe1,0xf1,0x62,0x00,0xeb,0x78,0x31,0x9f,0xe5, -0x00,0x00,0x54,0xe3,0x00,0x00,0x93,0xe5,0x01,0x31,0xa0,0xe3,0x00,0x30,0x80,0xe5, -0x0e,0x33,0xa0,0xe3,0x08,0x30,0x80,0xe5,0x11,0x33,0xa0,0xe3,0x0c,0x30,0x80,0xe5, -0x04,0x30,0xa0,0xe3,0x14,0x30,0x80,0xe5,0x50,0x31,0x9f,0x05,0x04,0x50,0x80,0xe5, -0xa0,0x40,0x83,0x05,0x03,0x00,0x00,0x0a,0x01,0x00,0x54,0xe3,0x40,0x31,0x9f,0x05, -0x00,0x20,0xa0,0x03,0x50,0x20,0x83,0x05,0x00,0x30,0x64,0xe2,0x33,0xc0,0xa0,0xe3, -0x9f,0x3c,0xc3,0xe3,0x2c,0x61,0x9f,0xe5,0xff,0x30,0xc3,0xe3,0x01,0x7b,0xa0,0xe3, -0x1b,0x1a,0x83,0xe2,0x20,0x21,0x9f,0xe5,0x86,0x12,0x81,0xe2,0x1c,0x81,0x9f,0xe5, -0x00,0xc0,0x81,0xe5,0x04,0xc0,0x80,0xe0,0x14,0x11,0x9f,0xe5,0x18,0xc0,0x8c,0xe2, -0x04,0x40,0x88,0xe0,0x01,0x70,0x83,0xe7,0x00,0x10,0xa0,0xe3,0x06,0x70,0x93,0xe7, -0x07,0x78,0xa0,0xe1,0x27,0x78,0xa0,0xe1,0x06,0x70,0x83,0xe7,0x02,0x70,0x93,0xe7, -0x02,0x60,0xdc,0xe5,0x02,0x10,0xcc,0xe5,0x0f,0x72,0xc7,0xe3,0x18,0x40,0xd4,0xe5, -0x01,0xc2,0x87,0xe3,0x01,0x00,0x56,0xe1,0xff,0xc6,0xcc,0xe3,0x01,0x6b,0xa0,0x03, -0x0f,0xc8,0xcc,0xe3,0x01,0x60,0xa0,0x11,0x02,0xc5,0x8c,0xe3,0x01,0x40,0x04,0xe2, -0x03,0xcb,0xcc,0xe3,0x0c,0xc0,0x86,0xe1,0x0e,0xcd,0xcc,0xe3,0x06,0xcd,0x8c,0xe3, -0x78,0xc0,0xcc,0xe3,0x18,0xc0,0x8c,0xe3,0x04,0xc0,0xcc,0xe3,0x04,0xc1,0x8c,0xe1, -0x01,0xc0,0xcc,0xe3,0x02,0xc0,0x83,0xe7,0x04,0x20,0x42,0xe2,0x02,0x50,0x83,0xe7, -0x14,0x20,0x90,0xe5,0x01,0x00,0x52,0xe1,0x17,0x00,0x00,0x0a,0x84,0x20,0x9f,0xe5, -0x06,0x42,0x83,0xe2,0x1b,0x4a,0x84,0xe2,0x00,0xc0,0xa0,0xe1,0x02,0x20,0x83,0xe0, -0x00,0x30,0x92,0xe5,0x01,0x00,0x13,0xe3,0xfc,0xff,0xff,0x1a,0x04,0x30,0x9c,0xe4, -0x01,0x10,0x81,0xe2,0x00,0x30,0x84,0xe5,0x14,0x30,0x90,0xe5,0x03,0x00,0x51,0xe1, -0xf6,0xff,0xff,0x3a,0x00,0x30,0x92,0xe5,0x08,0x00,0x13,0xe3,0x01,0x10,0x03,0xe2, -0x01,0x10,0x81,0x03,0x02,0x3c,0x03,0xe2,0x00,0x00,0x51,0xe3,0xf8,0xff,0xff,0x1a, -0x00,0x00,0x53,0xe3,0xf6,0xff,0xff,0x1a,0xf0,0x81,0xbd,0xe8,0x24,0x20,0x9f,0xe5, -0x02,0x20,0x83,0xe0,0xf2,0xff,0xff,0xea,0x04,0x90,0x02,0x40,0x60,0x90,0x02,0x40, -0x00,0xb0,0x01,0x60,0x00,0x10,0x01,0x60,0x0c,0xb1,0x01,0x60,0x04,0xb1,0x01,0x60, -0x44,0x90,0x02,0x40,0x44,0xb0,0x01,0x60,0x18,0xb0,0x01,0x60,0xf8,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0x03,0x60,0xa0,0xe1,0x01,0x50,0xa0,0xe1,0x02,0x10,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x34,0x01,0x9f,0xe5,0x82,0x62,0x00,0xeb,0x06,0x10,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x28,0x01,0x9f,0xe5,0x7e,0x62,0x00,0xeb,0x24,0x31,0x9f,0xe5, -0x00,0x00,0x64,0xe2,0x9f,0x0c,0xc0,0xe3,0x00,0x00,0x54,0xe3,0xff,0x00,0xc0,0xe3, -0xa2,0x48,0xa0,0x03,0x03,0x20,0x90,0xe7,0x0a,0x16,0xa0,0x03,0x02,0x29,0xc2,0xe3, -0x03,0x20,0x80,0xe7,0x04,0x00,0x00,0x0a,0x01,0x00,0x54,0xe3,0x52,0x48,0xa0,0x03, -0x02,0x48,0xa0,0x13,0x05,0x16,0xa0,0x03,0x00,0x10,0xa0,0x13,0xdc,0xc0,0x9f,0xe5, -0x08,0x50,0x85,0xe3,0xe0,0x20,0x9f,0xe5,0xe0,0x30,0x9f,0xe5,0x0f,0x70,0x0c,0xe2, -0x57,0x74,0x87,0xe3,0x02,0x20,0x0c,0xe0,0x1f,0x63,0x82,0xe3,0x85,0x58,0x87,0xe1, -0x01,0x60,0x86,0xe1,0x03,0x30,0x80,0xe0,0x00,0x20,0x93,0xe5,0x08,0x00,0x12,0xe3, -0x01,0x10,0x02,0xe2,0x01,0x10,0x81,0x03,0x02,0x2c,0x02,0xe2,0x00,0x00,0x51,0xe3, -0xf8,0xff,0xff,0x1a,0x00,0x00,0x52,0xe3,0xf6,0xff,0xff,0x1a,0xa0,0x20,0x9f,0xe5, -0x06,0x02,0x80,0xe2,0x1b,0x0a,0x80,0xe2,0x00,0x60,0x80,0xe5,0x02,0x20,0x0c,0xe0, -0x22,0x28,0x84,0xe1,0x1f,0xc3,0x82,0xe3,0x00,0x20,0x93,0xe5,0x08,0x00,0x12,0xe3, -0x01,0x10,0x02,0xe2,0x01,0x10,0x81,0x03,0x02,0x2c,0x02,0xe2,0x00,0x00,0x51,0xe3, -0xf8,0xff,0xff,0x1a,0x00,0x00,0x52,0xe3,0xf6,0xff,0xff,0x1a,0x00,0xc0,0x80,0xe5, -0x00,0x20,0x93,0xe5,0x08,0x00,0x12,0xe3,0x01,0x10,0x02,0xe2,0x01,0x10,0x81,0x03, -0x02,0x2c,0x02,0xe2,0x00,0x00,0x51,0xe3,0xf8,0xff,0xff,0x1a,0x00,0x00,0x52,0xe3, -0xf6,0xff,0xff,0x1a,0x00,0x50,0x80,0xe5,0x00,0x20,0x93,0xe5,0x08,0x00,0x12,0xe3, -0x01,0x10,0x02,0xe2,0x01,0x10,0x81,0x03,0x02,0x2c,0x02,0xe2,0x00,0x00,0x51,0xe3, -0xf8,0xff,0xff,0x1a,0x00,0x00,0x52,0xe3,0xf6,0xff,0xff,0x1a,0xf8,0x80,0xbd,0xe8, -0x04,0x90,0x02,0x40,0x34,0x90,0x02,0x40,0x0c,0xb1,0x01,0x60,0xf0,0xff,0x00,0x00, -0x18,0xb0,0x01,0x60,0x00,0x00,0xff,0x0f,0x68,0x30,0x9f,0xe5,0x00,0x20,0x60,0xe2, -0x9f,0x2c,0xc2,0xe3,0x04,0x40,0x2d,0xe5,0xff,0x40,0xc2,0xe3,0x03,0x30,0x84,0xe0, -0x00,0xc0,0x93,0xe5,0x08,0x00,0x1c,0xe3,0x01,0x20,0x0c,0xe2,0x01,0x20,0x82,0x03, -0x02,0xcc,0x0c,0xe2,0x00,0x00,0x52,0xe3,0xf8,0xff,0xff,0x1a,0x00,0x00,0x5c,0xe3, -0xf6,0xff,0xff,0x1a,0x30,0x20,0x9f,0xe5,0x1f,0x10,0x01,0xe2,0x2c,0x30,0x9f,0xe5, -0x00,0x20,0x92,0xe5,0x00,0x00,0x82,0xe0,0x01,0x20,0xa0,0xe3,0x1a,0x20,0xc0,0xe5, -0x03,0x20,0x94,0xe7,0x1f,0x26,0xc2,0xe3,0x01,0x1a,0x82,0xe1,0x03,0x10,0x84,0xe7, -0x10,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x18,0xb0,0x01,0x60,0x60,0x90,0x02,0x40, -0x08,0xb1,0x01,0x60,0x80,0xc1,0x9f,0xe5,0x00,0x00,0x50,0xe3,0xf0,0x01,0x2d,0xe9, -0x01,0x10,0x41,0xe2,0x0e,0x13,0x81,0xe3,0x01,0x51,0xa0,0xe3,0x00,0xc0,0x9c,0xe5, -0x14,0x40,0xdd,0xe5,0x04,0x20,0x8c,0xe5,0x11,0x23,0xa0,0xe3,0x0c,0x20,0x8c,0xe5, -0x04,0x20,0xa0,0xe3,0x14,0x20,0x8c,0xe5,0x50,0x21,0x9f,0x05,0x00,0x50,0x8c,0xe5, -0x08,0x10,0x8c,0xe5,0xa0,0x00,0x82,0x05,0x03,0x00,0x00,0x0a,0x01,0x00,0x50,0xe3, -0x3c,0x21,0x9f,0x05,0x00,0x10,0xa0,0x03,0x50,0x10,0x82,0x05,0x00,0x50,0x60,0xe2, -0x33,0x70,0xa0,0xe3,0x9f,0x5c,0xc5,0xe3,0x28,0x61,0x9f,0xe5,0xff,0x50,0xc5,0xe3, -0x01,0x8b,0xa0,0xe3,0x1b,0x1a,0x85,0xe2,0x1c,0x21,0x9f,0xe5,0x86,0x12,0x81,0xe2, -0x00,0x70,0x81,0xe5,0x00,0x10,0x8c,0xe0,0x10,0x71,0x9f,0xe5,0x18,0x10,0x81,0xe2, -0x07,0x80,0x85,0xe7,0x00,0x80,0xa0,0xe3,0x06,0x70,0x95,0xe7,0x07,0x78,0xa0,0xe1, -0x27,0x78,0xa0,0xe1,0x06,0x70,0x85,0xe7,0x02,0x70,0x95,0xe7,0x02,0x60,0xd1,0xe5, -0x02,0x80,0xc1,0xe5,0x0f,0x12,0xc7,0xe3,0x01,0x12,0x81,0xe3,0x08,0x00,0x56,0xe1, -0xff,0x16,0xc1,0xe3,0x01,0x6b,0xa0,0x03,0x0f,0x18,0xc1,0xe3,0x08,0x60,0xa0,0x11, -0x02,0x15,0x81,0xe3,0x08,0x00,0x54,0xe1,0x03,0x1b,0xc1,0xe3,0x01,0x10,0x86,0xe1, -0x02,0x4c,0xc1,0xe3,0x23,0x00,0x00,0x0a,0x02,0x1c,0x84,0xe3,0x10,0x40,0xa0,0xe3, -0x06,0x1d,0xc1,0xe3,0x01,0x1c,0x81,0xe3,0x78,0x10,0xc1,0xe3,0x04,0x40,0x81,0xe1, -0x9c,0x10,0x9f,0xe5,0x04,0x40,0xc4,0xe3,0x00,0x00,0x81,0xe0,0x18,0x10,0xd0,0xe5, -0x01,0x10,0x01,0xe2,0x01,0x11,0x84,0xe1,0x01,0x10,0xc1,0xe3,0x02,0x10,0x85,0xe7, -0x80,0x20,0x9f,0xe5,0x02,0x30,0x85,0xe7,0x14,0x30,0x9c,0xe5,0x00,0x00,0x53,0xe3, -0x0e,0x00,0x00,0x0a,0xe8,0x20,0x42,0xe2,0x06,0x42,0x85,0xe2,0x1b,0x4a,0x84,0xe2, -0x0c,0x00,0xa0,0xe1,0x00,0x10,0xa0,0xe3,0x02,0x20,0x85,0xe0,0x00,0x30,0x92,0xe5, -0x01,0x00,0x13,0xe3,0xfc,0xff,0xff,0x1a,0x04,0x30,0x90,0xe4,0x01,0x10,0x81,0xe2, -0x00,0x30,0x84,0xe5,0x14,0x30,0x9c,0xe5,0x03,0x00,0x51,0xe1,0xf6,0xff,0xff,0x3a, -0xf0,0x01,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x0e,0x1d,0xc1,0xe3,0x18,0x40,0xa0,0xe3, -0x06,0x1d,0x81,0xe3,0x78,0x10,0xc1,0xe3,0xdb,0xff,0xff,0xea,0x60,0x90,0x02,0x40, -0x00,0xb0,0x01,0x60,0x00,0x10,0x01,0x60,0x0c,0xb1,0x01,0x60,0x04,0xb1,0x01,0x60, -0x44,0xb0,0x01,0x60,0x44,0x90,0x02,0x40,0x00,0xb1,0x01,0x60,0x00,0x20,0x60,0xe2, -0x28,0x30,0x9f,0xe5,0x9f,0x2c,0xc2,0xe3,0xff,0x20,0xc2,0xe3,0x03,0x00,0x92,0xe7, -0x08,0x00,0x10,0xe3,0x01,0x30,0x00,0xe2,0x01,0x30,0x83,0x03,0x00,0x00,0x53,0xe3, -0xa0,0x04,0xa0,0x01,0x01,0x00,0xa0,0x13,0x01,0x00,0x00,0x02,0x1e,0xff,0x2f,0xe1, -0x18,0xb0,0x01,0x60,0x34,0x30,0x9f,0xe5,0x00,0x20,0x60,0xe2,0x9f,0x2c,0xc2,0xe3, -0x30,0x00,0x2d,0xe9,0xff,0x20,0xc2,0xe3,0x24,0x50,0x9f,0xe5,0x01,0x40,0x01,0xe2, -0x03,0xc0,0x92,0xe7,0x00,0x00,0x85,0xe0,0x04,0xc0,0xcc,0xe3,0x04,0xc1,0x8c,0xe1, -0x03,0xc0,0x82,0xe7,0x18,0x10,0xc0,0xe5,0x30,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x04,0xb1,0x01,0x60,0x44,0x90,0x02,0x40,0x08,0x30,0x9f,0xe5,0x00,0x30,0x83,0xe0, -0x18,0x00,0xd3,0xe5,0x1e,0xff,0x2f,0xe1,0x44,0x90,0x02,0x40,0x5c,0x30,0x9f,0xe5, -0x00,0x30,0x83,0xe0,0x18,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x0a, -0x00,0x00,0x60,0xe2,0x48,0x30,0x9f,0xe5,0x9f,0x0c,0xc0,0xe3,0xff,0x00,0xc0,0xe3, -0x03,0x30,0x90,0xe7,0x00,0x30,0x81,0xe5,0x38,0x30,0x9f,0xe5,0x03,0x30,0x90,0xe7, -0x04,0x30,0x81,0xe5,0x30,0x30,0x9f,0xe5,0x03,0x30,0x90,0xe7,0x08,0x30,0x81,0xe5, -0x28,0x30,0x9f,0xe5,0x03,0x30,0x90,0xe7,0x0c,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x03,0x10,0xa0,0xe1,0x68,0x61,0x00,0xea, -0x44,0x90,0x02,0x40,0x20,0xb1,0x01,0x60,0x24,0xb1,0x01,0x60,0x28,0xb1,0x01,0x60, -0x2c,0xb1,0x01,0x60,0xf0,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1,0x1c,0xd0,0x4d,0xe2, -0x01,0x40,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0xb7,0xff,0xff,0xeb,0x00,0x70,0x50,0xe2, -0xfb,0xff,0xff,0x1a,0x05,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x08,0x60,0x8d,0xe2, -0x5e,0xfe,0xff,0xeb,0x07,0x10,0xa0,0xe1,0x06,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3, -0x53,0x61,0x00,0xeb,0x01,0x10,0xa0,0xe3,0x05,0x00,0xa0,0xe1,0x06,0x20,0xa0,0xe1, -0x04,0x30,0xa0,0xe1,0x00,0x10,0x8d,0xe5,0x3d,0xff,0xff,0xeb,0x05,0x00,0xa0,0xe1, -0xa5,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x05,0x00,0xa0,0xe1, -0xc0,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3,0x16,0x00,0x00,0x1a,0x00,0x10,0xd4,0xe5, -0x04,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3,0xa1,0xc3,0xa0,0xe1,0x81,0x10,0xa0,0xe1, -0x00,0x10,0xc4,0xe5,0x03,0x10,0xd4,0xe7,0x01,0x00,0xd2,0xe5,0xa0,0x13,0x81,0xe1, -0x03,0x10,0xc4,0xe7,0x01,0x30,0x83,0xe2,0x01,0x10,0xd2,0xe5,0x0f,0x00,0x53,0xe3, -0x81,0x10,0xa0,0xe1,0x01,0x10,0xe2,0xe5,0xf5,0xff,0xff,0x1a,0x00,0x00,0x5c,0xe3, -0x0f,0x20,0xd4,0x15,0x78,0x30,0xe0,0x13,0x03,0x30,0x22,0x10,0x0f,0x30,0xc4,0x15, -0x1c,0xd0,0x8d,0xe2,0xf0,0x80,0xbd,0xe8,0x05,0x00,0xa0,0xe1,0x04,0x10,0xa0,0xe1, -0xa9,0xff,0xff,0xeb,0xe4,0xff,0xff,0xea,0xf0,0x45,0x2d,0xe9,0x1c,0xd0,0x4d,0xe2, -0x38,0x50,0x9d,0xe5,0x03,0x80,0xa0,0xe1,0x00,0x40,0xa0,0xe1,0x01,0x60,0xa0,0xe1, -0x02,0x70,0xa0,0xe1,0x3c,0x30,0xdd,0xe5,0x00,0x00,0x55,0xe3,0x40,0xa0,0xdd,0xe5, -0x26,0x00,0x00,0x0a,0x00,0x00,0x53,0xe3,0x32,0x00,0x00,0x1a,0x00,0x00,0x5a,0xe3, -0x24,0x00,0x00,0x0a,0x01,0x00,0x55,0xe3,0x0a,0x00,0x00,0x9a,0x04,0x00,0xa0,0xe1, -0x71,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x01,0xc0,0xa0,0xe3, -0x04,0x00,0xa0,0xe1,0x01,0x10,0x45,0xe2,0x07,0x20,0xa0,0xe1,0x08,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xfe,0xfe,0xff,0xeb,0x07,0x51,0x45,0xe2,0x00,0x30,0xa0,0xe3, -0x05,0x72,0x87,0xe0,0x08,0x50,0x8d,0xe2,0x03,0x20,0x96,0xe7,0x04,0x10,0x97,0xe4, -0x02,0x20,0x21,0xe0,0x03,0x20,0x85,0xe7,0x04,0x30,0x83,0xe2,0x10,0x00,0x53,0xe3, -0xf8,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x5b,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xfb,0xff,0xff,0x1a,0x01,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x0c,0x10,0xa0,0xe1, -0x05,0x20,0xa0,0xe1,0x08,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xe8,0xfe,0xff,0xeb, -0x1c,0xd0,0x8d,0xe2,0xf0,0x85,0xbd,0xe8,0x04,0x00,0xa0,0xe1,0x4e,0xff,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x01,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x05,0x10,0xa0,0xe1,0x07,0x20,0xa0,0xe1,0x08,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0xdb,0xfe,0xff,0xeb,0xf1,0xff,0xff,0xea,0x00,0x10,0xa0,0xe3,0xef,0xfd,0xff,0xeb, -0x00,0x00,0x5a,0xe3,0xef,0xff,0xff,0x0a,0xc9,0xff,0xff,0xea,0x30,0x40,0x2d,0xe9, -0x0c,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1,0x0d,0x00,0xa0,0xe1,0xba,0x04,0x00,0xeb, -0x04,0x00,0x8d,0xe2,0xaa,0x04,0x00,0xeb,0x00,0x00,0x9d,0xe5,0x05,0x00,0x50,0xe3, -0x00,0xf1,0x9f,0x97,0x0e,0x00,0x00,0xea,0x7c,0xa3,0x00,0x40,0x84,0xa3,0x00,0x40, -0x8c,0xa3,0x00,0x40,0x94,0xa3,0x00,0x40,0x9c,0xa3,0x00,0x40,0x50,0xa3,0x00,0x40, -0x09,0x50,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x8b,0x4a,0x00,0xeb,0x04,0x00,0x84,0xe2, -0x05,0x10,0xa0,0xe1,0x04,0x20,0x9d,0xe5,0x3c,0x01,0x00,0xeb,0x0c,0xd0,0x8d,0xe2, -0x30,0x80,0xbd,0xe8,0x02,0x51,0xe0,0xe3,0xf5,0xff,0xff,0xea,0x04,0x50,0xa0,0xe3, -0xf3,0xff,0xff,0xea,0x02,0x50,0xa0,0xe3,0xf1,0xff,0xff,0xea,0x03,0x50,0xa0,0xe3, -0xef,0xff,0xff,0xea,0x01,0x50,0xa0,0xe3,0xed,0xff,0xff,0xea,0x0a,0x50,0xa0,0xe3, -0xeb,0xff,0xff,0xea,0xf0,0x47,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0x20,0x60,0x9d,0xe5, -0x01,0xa0,0xa0,0xe1,0x02,0x80,0xa0,0xe1,0x03,0x70,0xa0,0xe1,0x24,0x50,0xdd,0xe5, -0x28,0x90,0xdd,0xe5,0x04,0x00,0xa0,0xe1,0x0f,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xfb,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x0a,0x10,0xa0,0xe1,0x08,0x20,0xa0,0xe1, -0x07,0x30,0xa0,0xe1,0x20,0x60,0x8d,0xe5,0x24,0x50,0x8d,0xe5,0x28,0x90,0x8d,0xe5, -0xf0,0x47,0xbd,0xe8,0x7f,0xff,0xff,0xea,0x01,0x10,0xa0,0xe3,0x10,0xff,0xff,0xea, -0x00,0x10,0xa0,0xe3,0x0e,0xff,0xff,0xea,0x70,0x40,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0x01,0x50,0xa0,0xe1,0x1b,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3,0x70,0x80,0xbd,0x08, -0x04,0x00,0xa0,0xe1,0xf8,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x70,0x40,0xbd,0xe8,0x16,0xff,0xff,0xea, -0x01,0x00,0x40,0xe2,0x07,0x00,0x50,0xe3,0x00,0xf1,0x9f,0x97,0x13,0x00,0x00,0xea, -0x70,0xa4,0x00,0x40,0xc0,0xa4,0x00,0x40,0x80,0xa4,0x00,0x40,0xa0,0xa4,0x00,0x40, -0x70,0xa4,0x00,0x40,0xa0,0xa4,0x00,0x40,0x90,0xa4,0x00,0x40,0xb0,0xa4,0x00,0x40, -0x03,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x02,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x05,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x06,0x30,0xa0,0xe3,0x04,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x04,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0x00,0xa0,0xe3,0x00,0x00,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x05,0x00,0x50,0xe3, -0x00,0xf1,0x9f,0x97,0x09,0x00,0x00,0xea,0x10,0xa5,0x00,0x40,0x00,0xa5,0x00,0x40, -0x20,0xa5,0x00,0x40,0x30,0xa5,0x00,0x40,0x40,0xa5,0x00,0x40,0xf0,0xa4,0x00,0x40, -0x07,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x02,0x31,0xe0,0xe3,0x04,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x02,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x03,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x01,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x08,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x30,0x40,0x2d,0xe9,0x14,0xd0,0x4d,0xe2,0x08,0xc0,0x8d,0xe2,0x00,0x40,0xa0,0xe1, -0x01,0x1a,0xa0,0xe3,0x07,0x02,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0x9e,0x65,0x00,0xeb,0x00,0x00,0x50,0xe3,0x00,0x50,0xa0,0x13, -0x05,0x00,0x00,0x1a,0x08,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x50,0x90,0xe5, -0xbd,0x65,0x00,0xeb,0x25,0x5d,0xa0,0xe1,0x0f,0x50,0x05,0xe2,0x50,0x30,0x9f,0xe5, -0xc0,0x39,0x93,0xe5,0x08,0x00,0x13,0xe3,0x0b,0x00,0x00,0x0a,0x04,0x30,0xa0,0xe3, -0x10,0x20,0x8d,0xe2,0x04,0x30,0x22,0xe5,0x0b,0x00,0xa0,0xe3,0x04,0x10,0xa0,0xe1, -0x1d,0x3d,0x00,0xeb,0x00,0x30,0x94,0xe5,0x05,0x00,0x53,0xe3,0x06,0x30,0xa0,0x83, -0x00,0x30,0x84,0x85,0x14,0xd0,0x8d,0xe2,0x30,0x80,0xbd,0xe8,0x0f,0x00,0x55,0xe3, -0xf1,0xff,0xff,0x0a,0x0c,0x30,0x9f,0xe5,0x05,0x31,0x93,0xe7,0x00,0x30,0x84,0xe5, -0xf4,0xff,0xff,0xea,0x00,0xf0,0x00,0x70,0x5c,0x6e,0x02,0x40,0x30,0x40,0x2d,0xe9, -0x14,0xd0,0x4d,0xe2,0x08,0xc0,0x8d,0xe2,0x00,0x40,0xa0,0xe1,0x01,0x1a,0xa0,0xe3, -0x07,0x02,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5, -0x73,0x65,0x00,0xeb,0x00,0x00,0x50,0xe3,0x00,0x50,0xa0,0x13,0x05,0x00,0x00,0x1a, -0x08,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x50,0x90,0xe5,0x92,0x65,0x00,0xeb, -0x25,0x5d,0xa0,0xe1,0x0f,0x50,0x05,0xe2,0x40,0x30,0x9f,0xe5,0xc0,0x39,0x93,0xe5, -0x08,0x00,0x13,0xe3,0x07,0x00,0x00,0x0a,0x10,0x20,0x8d,0xe2,0x04,0x30,0xa0,0xe3, -0x04,0x30,0x22,0xe5,0x04,0x10,0xa0,0xe1,0x05,0x00,0xa0,0xe3,0xf2,0x3c,0x00,0xeb, -0x14,0xd0,0x8d,0xe2,0x30,0x80,0xbd,0xe8,0x0f,0x00,0x55,0xe3,0xf5,0xff,0xff,0x0a, -0x0c,0x30,0x9f,0xe5,0x05,0x31,0x93,0xe7,0x00,0x30,0x84,0xe5,0xf7,0xff,0xff,0xea, -0x00,0xf0,0x00,0x70,0x1c,0x6e,0x02,0x40,0x1e,0xff,0x2f,0xe1,0xff,0x0e,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x74,0x44,0x00,0xea,0x04,0xe0,0x2d,0xe5,0x0c,0xd0,0x4d,0xe2, -0x08,0x20,0x8d,0xe2,0x10,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe1,0x0e,0x00,0xa0,0xe3, -0x04,0x30,0x22,0xe5,0xdc,0x3c,0x00,0xeb,0x0c,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8, -0xf0,0x41,0x2d,0xe9,0x38,0xd0,0x4d,0xe2,0x08,0x50,0x8d,0xe2,0x00,0x40,0xa0,0xe1, -0x01,0x70,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x00,0x10,0xa0,0xe3,0x02,0x60,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x0f,0x60,0x00,0xeb,0x08,0x00,0xdd,0xe5,0x09,0x10,0xdd,0xe5, -0x0a,0x20,0xdd,0xe5,0x0b,0x30,0xdd,0xe5,0x14,0x00,0xcd,0xe5,0x10,0x00,0xcd,0xe5, -0x0c,0x00,0xcd,0xe5,0x15,0x10,0xcd,0xe5,0x11,0x10,0xcd,0xe5,0x0d,0x10,0xcd,0xe5, -0x16,0x20,0xcd,0xe5,0x12,0x20,0xcd,0xe5,0x0e,0x20,0xcd,0xe5,0x17,0x30,0xcd,0xe5, -0x13,0x30,0xcd,0xe5,0x0f,0x30,0xcd,0xe5,0x04,0x00,0xa0,0xe1,0x32,0xfe,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1, -0xa4,0xfd,0xff,0xeb,0x01,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x0c,0x10,0xa0,0xe1, -0x05,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xbc,0xfd,0xff,0xeb, -0x04,0x00,0xa0,0xe1,0x24,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x10,0x30,0xa0,0xe3,0x34,0x20,0x8d,0xe2,0x0e,0x00,0xa0,0xe3,0x28,0x10,0x8d,0xe2, -0x34,0x30,0x8d,0xe5,0x18,0x80,0x8d,0xe2,0xa7,0x3c,0x00,0xeb,0x28,0xc0,0x9d,0xe5, -0x08,0x20,0x88,0xe2,0x2c,0x30,0x9d,0xe5,0x01,0xc0,0x62,0xe5,0x2c,0xc4,0xa0,0xe1, -0x08,0x00,0x52,0xe1,0x03,0xcc,0x8c,0xe1,0x23,0x34,0xa0,0xe1,0xf9,0xff,0xff,0x1a, -0x08,0x00,0x88,0xe2,0x08,0x10,0xa0,0xe1,0x08,0x20,0xa0,0xe3,0x2c,0x30,0x8d,0xe5, -0x28,0xc0,0x8d,0xe5,0xd5,0x5f,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x03,0x10,0xd5,0xe7, -0x03,0x20,0xd8,0xe7,0x02,0x20,0x21,0xe0,0x03,0x20,0xc6,0xe7,0x01,0x30,0x83,0xe2, -0x10,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x02,0xfe,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1, -0x74,0xfd,0xff,0xeb,0x01,0xc0,0xa0,0xe3,0x06,0x20,0xa0,0xe1,0x04,0x00,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0x06,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x8c,0xfd,0xff,0xeb, -0x04,0x00,0xa0,0xe1,0xf4,0xfd,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x66,0xfd,0xff,0xeb,0x38,0xd0,0x8d,0xe2, -0xf0,0x81,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x10,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x30,0x40,0x2d,0xe9,0x00,0x40,0x50,0xe2,0x0c,0xd0,0x4d,0xe2,0x01,0x50,0xa0,0x03, -0x11,0x00,0x00,0x0a,0x81,0x11,0x61,0xe0,0x80,0xc0,0x9f,0xe5,0x02,0x00,0xa0,0xe1, -0x01,0x31,0xa0,0xe1,0x04,0x10,0x8d,0xe2,0x0c,0x20,0x83,0xe0,0x08,0x20,0x84,0xe5, -0x0f,0xe0,0xa0,0xe1,0x03,0xf0,0x9c,0xe7,0x08,0x30,0x94,0xe5,0x04,0x00,0x9d,0xe5, -0x0f,0xe0,0xa0,0xe1,0x04,0xf0,0x93,0xe5,0x00,0x00,0x50,0xe3,0x1f,0x50,0xa0,0x03, -0x04,0x00,0x00,0x1a,0x00,0x30,0xa0,0xe3,0x08,0x30,0x84,0xe5,0x05,0x00,0xa0,0xe1, -0x0c,0xd0,0x8d,0xe2,0x30,0x80,0xbd,0xe8,0x08,0x30,0x94,0xe5,0x04,0x00,0x9d,0xe5, -0x2c,0x10,0x9f,0xe5,0x0f,0xe0,0xa0,0xe1,0x0c,0xf0,0x93,0xe5,0x00,0x50,0x50,0xe2, -0xf3,0xff,0xff,0x1a,0x04,0x10,0xa0,0xe1,0x08,0x30,0x94,0xe5,0x04,0x00,0x9d,0xe5, -0x04,0x20,0x84,0xe2,0x0f,0xe0,0xa0,0xe1,0x08,0xf0,0x93,0xe5,0xee,0xff,0xff,0xea, -0x20,0x81,0x02,0x40,0x00,0xd0,0x02,0x40,0xf0,0x4f,0x2d,0xe9,0xcc,0xd0,0x4d,0xe2, -0x00,0x30,0xa0,0xe3,0xc8,0x20,0x8d,0xe2,0x01,0x40,0xa0,0xe1,0x03,0x10,0xa0,0xe1, -0x04,0x30,0x22,0xe5,0x24,0x20,0x8d,0xe5,0x03,0x20,0xa0,0xe1,0x34,0x00,0x8d,0xe5, -0x24,0x00,0x9d,0xe5,0x3f,0x03,0x00,0xeb,0x00,0x00,0x50,0xe3,0x10,0x00,0x00,0x0a, -0x6c,0x3a,0x9f,0xe5,0x2c,0x30,0x8d,0xe5,0x68,0xca,0x9f,0xe5,0x04,0x30,0xa0,0xe3, -0x28,0x30,0x8d,0xe5,0x20,0xc0,0x8d,0xe5,0x2c,0x10,0x9d,0xe5,0x00,0x00,0x91,0xe5, -0x00,0x00,0x50,0xe3,0xdf,0x66,0x00,0x1b,0x20,0x20,0x9d,0xe5,0x00,0x00,0x92,0xe5, -0x00,0x00,0x50,0xe3,0x9a,0x03,0x00,0x1b,0x28,0x00,0x9d,0xe5,0xcc,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0xc4,0x00,0x9d,0xe5,0xd5,0x66,0x00,0xeb,0x20,0xca,0x9f,0xe5, -0x00,0x00,0x50,0xe3,0x00,0x10,0xa0,0xe1,0x2c,0xc0,0x8d,0xe5,0x00,0x00,0x8c,0xe5, -0xe8,0xff,0xff,0x0a,0x24,0x00,0x9d,0xe5,0x08,0x2a,0x9f,0xe5,0x21,0x03,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xe3,0xff,0xff,0x1a,0x12,0xfc,0xff,0xeb,0x38,0x00,0x8d,0xe2, -0x51,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x28,0x00,0x8d,0xe5,0xe4,0x09,0x9f,0x15, -0x20,0x00,0x8d,0x15,0xdf,0xff,0xff,0x1a,0x05,0x00,0x54,0xe3,0x01,0x40,0xa0,0xe3, -0x49,0x40,0xcd,0xe5,0x9a,0x01,0x00,0x1a,0xcc,0x19,0x9f,0xe5,0xcc,0x89,0x9f,0xe5, -0x28,0x20,0x9d,0xe5,0x30,0x10,0x8d,0xe5,0x48,0x40,0xcd,0xe5,0x00,0x40,0x88,0xe5, -0x00,0x20,0x81,0xe5,0xb8,0x39,0x9f,0xe5,0x00,0x10,0xa0,0xe3,0xa4,0x29,0x9f,0xe5, -0xb0,0x49,0x9f,0xe5,0x00,0x60,0x93,0xe5,0x1c,0x10,0x8d,0xe5,0x20,0x20,0x8d,0xe5, -0x04,0x50,0xa0,0xe1,0x1c,0xff,0xff,0xeb,0x38,0x00,0x86,0xe5,0x1c,0x00,0x9d,0xe5, -0x20,0xc0,0x9d,0xe5,0x00,0x60,0xa0,0xe3,0x00,0x30,0xe0,0xe3,0x58,0x00,0x8d,0xe5, -0x54,0x30,0x8d,0xe5,0x10,0x90,0xa0,0xe3,0x00,0xc0,0x9c,0xe5,0x5c,0x60,0x8d,0xe5, -0x18,0xc0,0x8d,0xe5,0x10,0xff,0xff,0xeb,0x40,0x10,0x9d,0xe5,0x01,0x20,0xa0,0xe3, -0x38,0x30,0x8d,0xe2,0x49,0xc0,0xdd,0xe5,0x04,0xa0,0x83,0xe2,0x48,0xb0,0xdd,0xe5, -0x0c,0x10,0x84,0xe5,0x12,0x71,0xa0,0xe1,0x60,0x00,0x8d,0xe5,0x02,0x00,0x5c,0xe1, -0x64,0x90,0x8d,0xe5,0x01,0x30,0x47,0xe2,0x00,0xa0,0x84,0xe5,0x00,0x30,0x83,0xe0, -0x18,0x00,0x9d,0xe5,0x33,0x31,0xa0,0xe1,0x54,0x10,0x8d,0xe2,0x18,0x10,0x84,0xe5, -0x58,0x10,0x9d,0xe5,0x68,0x00,0x8d,0xe5,0x04,0x60,0x84,0xe5,0x24,0x10,0x84,0xe5, -0x5c,0x10,0x9d,0xe5,0x08,0x70,0x84,0xe5,0x10,0x30,0x84,0xe5,0x14,0x30,0x84,0xe5, -0x1c,0x20,0x84,0xe5,0x20,0x60,0x84,0xe5,0x28,0x10,0x84,0xe5,0x2c,0x60,0x84,0xe5, -0x39,0x20,0xc4,0xe5,0x38,0x20,0xc4,0xe5,0x3a,0x20,0xc4,0xe5,0x3b,0x60,0xc4,0xe5, -0x3c,0x60,0xc4,0xe5,0x3d,0x60,0xc4,0xe5,0x50,0x00,0x84,0xe5,0x64,0x20,0xc4,0xe5, -0x65,0x20,0xc4,0xe5,0x66,0x20,0xc4,0xe5,0x67,0xb0,0xc4,0xe5,0x68,0xc0,0xc4,0xe5, -0x4f,0x01,0x00,0x0a,0x00,0x20,0xa0,0xe3,0x01,0x60,0xa0,0xe3,0x02,0xb0,0xa0,0xe1, -0x08,0x90,0xa0,0xe1,0x04,0x20,0x84,0xe5,0x00,0x00,0x53,0xe3,0x05,0x00,0x00,0x1a, -0x39,0x30,0xd4,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x0a,0x38,0x30,0xd5,0xe5, -0x00,0x00,0x53,0xe3,0xf2,0x00,0x00,0x1a,0x64,0x30,0xd4,0xe5,0x00,0x00,0x53,0xe3, -0x5a,0x00,0x00,0x0a,0x39,0x30,0xd5,0xe5,0x01,0x00,0x53,0xe3,0x67,0x00,0x00,0x0a, -0x67,0x30,0xd4,0xe5,0x01,0x00,0x53,0xe3,0x00,0x70,0xa0,0x13,0xc1,0x00,0x00,0x0a, -0x68,0x30,0xd4,0xe5,0x01,0x00,0x53,0xe3,0x00,0x00,0xa0,0x13,0xba,0x00,0x00,0x0a, -0x38,0x30,0xd4,0xe5,0x03,0x70,0x87,0xe1,0x07,0x70,0x80,0xe1,0xff,0x00,0x17,0xe3, -0xb1,0x00,0x00,0x1a,0x3a,0x10,0xd5,0xe5,0x50,0x20,0x95,0xe5,0x08,0x30,0x95,0xe5, -0x01,0x10,0x81,0xe2,0x38,0x60,0xc5,0xe5,0x3a,0x10,0xc5,0xe5,0x03,0x30,0x82,0xe0, -0x50,0x30,0x85,0xe5,0x3b,0x30,0xd4,0xe5,0x00,0x00,0x53,0xe3,0x3d,0x00,0x00,0x0a, -0x14,0x10,0x95,0xe5,0x01,0x30,0x43,0xe2,0x3d,0x20,0xd5,0xe5,0x3b,0x30,0xc5,0xe5, -0x01,0x10,0x41,0xe2,0x38,0xb0,0xc5,0xe5,0x14,0x10,0x85,0xe5,0x01,0x00,0x52,0xe3, -0x64,0x70,0x94,0xe5,0x01,0x20,0x82,0x12,0xff,0x20,0x02,0x12,0x00,0x30,0xa0,0x03, -0x03,0x20,0xa0,0x01,0x02,0x30,0xa0,0x11,0xff,0x74,0xc7,0xe3,0x3d,0x20,0xc4,0xe5, -0xff,0x70,0xc7,0xe3,0x00,0x70,0x57,0xe2,0x01,0x70,0xa0,0x13,0x00,0x00,0x57,0xe3, -0x18,0x20,0x95,0x15,0x07,0x20,0xa0,0x01,0x07,0x80,0xa0,0x01,0x10,0x80,0x92,0x15, -0x28,0x22,0xa0,0x11,0x00,0x00,0x51,0xe3,0xa2,0x00,0x00,0x1a,0x18,0x00,0x94,0xe5, -0x0c,0x10,0x94,0xe5,0x0c,0x00,0x90,0xe5,0x01,0xa0,0xa0,0xe1,0x0f,0xc0,0x80,0xe2, -0x30,0x01,0xa0,0xe1,0x10,0x01,0x4c,0xe0,0x20,0x02,0xa0,0xe1,0x88,0x17,0x9f,0xe5, -0x00,0x00,0x62,0xe0,0x18,0x20,0x94,0xe5,0x14,0x00,0x8d,0xe5,0x50,0x00,0x94,0xe5, -0x13,0xaa,0x81,0xe0,0x10,0x20,0x92,0xe5,0x0a,0x10,0xa0,0xe1,0x3d,0x67,0x00,0xeb, -0x67,0x30,0xd4,0xe5,0x01,0x00,0x53,0xe3,0x85,0x00,0x00,0x1a,0x65,0x30,0xd5,0xe5, -0x08,0xa0,0x8a,0xe0,0x50,0x20,0x95,0xe5,0x00,0x00,0x53,0xe3,0x08,0x80,0x82,0xe0, -0x8d,0x00,0x00,0x1a,0x00,0x00,0xa0,0xe3,0x14,0x10,0x9d,0xe5,0x0a,0x20,0xa0,0xe1, -0x08,0x30,0xa0,0xe1,0x00,0x00,0x8d,0xe5,0x71,0xfc,0xff,0xeb,0x68,0x30,0xd4,0xe5, -0x01,0x00,0x53,0xe3,0x59,0x00,0x00,0x0a,0x14,0x30,0x94,0xe5,0x99,0xff,0xff,0xea, -0x00,0x30,0x95,0xe5,0x08,0x30,0x93,0xe5,0x0f,0xe0,0xa0,0xe1,0x14,0xf0,0x93,0xe5, -0x03,0x30,0x40,0xe2,0x01,0x00,0x53,0xe3,0x6a,0x00,0x00,0x9a,0x01,0x00,0x50,0xe3, -0x9b,0xff,0xff,0x1a,0x39,0x30,0xd5,0xe5,0x00,0x00,0x53,0xe3,0x99,0xff,0xff,0x1a, -0x3b,0x30,0xd5,0xe5,0x39,0x00,0xc5,0xe5,0x01,0x30,0x83,0xe2,0x3b,0x30,0xc5,0xe5, -0x3a,0x30,0xd4,0xe5,0x00,0x00,0x53,0xe3,0x94,0xff,0xff,0x0a,0x10,0x20,0x95,0xe5, -0x00,0x00,0x52,0xe3,0x91,0xff,0xff,0x0a,0x3c,0x10,0xd5,0xe5,0x01,0x20,0x42,0xe2, -0x10,0x20,0x85,0xe5,0x01,0x30,0x43,0xe2,0x3a,0x30,0xc5,0xe5,0x01,0x00,0x51,0xe3, -0xa4,0x36,0x9f,0xe5,0x0c,0x20,0x95,0x15,0x01,0x10,0x81,0x12,0xff,0x10,0x01,0x12, -0x64,0x00,0xd4,0xe5,0x0b,0x20,0xa0,0x01,0x0b,0x10,0xa0,0x01,0x39,0xb0,0xc5,0xe5, -0x11,0x22,0xa0,0x11,0x01,0x00,0x50,0xe3,0x3c,0x10,0xc4,0xe5,0x03,0x20,0x82,0xe0, -0x00,0x30,0x94,0xe5,0x20,0xb0,0x85,0xe5,0x00,0xc0,0x93,0xe5,0x04,0x00,0x93,0xe5, -0x63,0x00,0x00,0x0a,0x28,0x10,0x95,0xe5,0x0c,0xc0,0x60,0xe0,0x2c,0x00,0x95,0xe5, -0x01,0x10,0x81,0xe2,0x16,0x0c,0x51,0xe1,0x01,0x00,0x80,0xe2,0x2c,0x00,0x85,0xe5, -0x24,0x00,0x95,0x25,0x24,0x00,0x95,0x35,0x28,0x10,0x85,0xe5,0x0b,0x10,0xa0,0x21, -0x01,0x00,0x80,0x22,0x28,0xb0,0x85,0x25,0x24,0x00,0x85,0x25,0x08,0x30,0x93,0xe5, -0x0f,0xe0,0xa0,0xe1,0x10,0xf0,0x93,0xe5,0x00,0x00,0x50,0xe3,0x67,0xff,0xff,0x0a, -0x09,0x80,0xa0,0xe1,0x00,0x90,0xa0,0xe1,0x00,0x30,0x94,0xe5,0x08,0x30,0x93,0xe5, -0x0f,0xe0,0xa0,0xe1,0x14,0xf0,0x93,0xe5,0x02,0x00,0x50,0xe3,0xf9,0xff,0xff,0x0a, -0x00,0x00,0xa0,0xe3,0x8c,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x00,0x00,0x98,0xe5,0x88,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a, -0x1c,0x00,0x9d,0xe5,0x01,0x00,0x80,0xe2,0x3f,0x00,0x50,0xe3,0x1c,0x00,0x8d,0xe5, -0x0a,0xff,0xff,0x1a,0x09,0x70,0xa0,0xe1,0x28,0x90,0x8d,0xe5,0xd1,0xfe,0xff,0xea, -0x00,0x00,0x57,0xe3,0x2d,0x00,0x00,0x1a,0x14,0xc0,0x94,0xe5,0x0a,0x20,0xa0,0xe1, -0x14,0x30,0x9d,0xe5,0xa4,0x15,0x9f,0xe5,0x00,0x00,0x99,0xe5,0x01,0xc0,0x7c,0xe2, -0x00,0xc0,0xa0,0x33,0x00,0x30,0x8d,0xe5,0x14,0x30,0x81,0xe2,0x80,0x10,0x8d,0xe9, -0x57,0xfd,0xff,0xeb,0x14,0x30,0x94,0xe5,0x32,0xff,0xff,0xea,0x01,0x00,0x53,0xe3, -0x53,0xff,0xff,0x0a,0x14,0x30,0x94,0xe5,0x2e,0xff,0xff,0xea,0x00,0x00,0x99,0xe5, -0x69,0xfc,0xff,0xeb,0x41,0xff,0xff,0xea,0x00,0x00,0xa0,0xe3,0x66,0xfc,0xff,0xeb, -0x00,0x70,0xa0,0xe1,0x39,0xff,0xff,0xea,0x09,0x80,0xa0,0xe1,0x09,0x90,0xa0,0xe3, -0xcc,0xff,0xff,0xea,0x14,0x30,0x9d,0xe5,0x08,0xa0,0x8a,0xe0,0x50,0x00,0x95,0xe5, -0x0a,0x10,0xa0,0xe1,0x03,0x22,0xa0,0xe1,0x08,0x00,0x80,0xe0,0xad,0x66,0x00,0xeb, -0x65,0xb0,0xc5,0xe5,0x7c,0xff,0xff,0xea,0x0c,0x00,0x94,0xe5,0x0c,0xa0,0x94,0xe5, -0x04,0x00,0x40,0xe2,0x16,0x00,0xa0,0xe1,0x5f,0xff,0xff,0xea,0x00,0x00,0xa0,0xe3, -0x00,0x10,0xa0,0xe1,0xc7,0xfb,0xff,0xeb,0x65,0xb0,0xc5,0xe5,0x6c,0xff,0xff,0xea, -0x30,0x20,0x9d,0xe5,0x00,0x00,0x99,0xe5,0x00,0x10,0x92,0xe5,0xc1,0xfb,0xff,0xeb, -0x00,0x00,0x99,0xe5,0xe4,0x14,0x9f,0xe5,0x89,0xfc,0xff,0xeb,0x66,0xb0,0xc5,0xe5, -0xc8,0xff,0xff,0xea,0x64,0xb0,0xc5,0xe5,0x24,0x00,0x95,0xe5,0x28,0x10,0x95,0xe5, -0xa5,0xff,0xff,0xea,0xbc,0xc4,0x9f,0xe5,0x09,0x80,0xa0,0xe1,0x68,0x30,0xdc,0xe5, -0x01,0x00,0x53,0xe3,0x67,0x00,0x00,0x0a,0x60,0x20,0x9d,0xe5,0x0f,0x30,0x82,0xe2, -0x0f,0x30,0xc3,0xe3,0x02,0x30,0x53,0xe0,0x0a,0x00,0x00,0x0a,0x18,0xc0,0x9d,0xe5, -0x02,0x10,0xdc,0xe7,0x02,0x20,0x8c,0xe0,0x80,0x00,0x51,0xe3,0x03,0x00,0x00,0x0a, -0x18,0x00,0x00,0xea,0x01,0x10,0xf2,0xe5,0x00,0x00,0x51,0xe3,0x15,0x00,0x00,0x1a, -0x01,0x30,0x53,0xe2,0xfa,0xff,0xff,0x1a,0x20,0x10,0x9d,0xe5,0x00,0xc0,0xa0,0xe3, -0x90,0x60,0x8d,0xe2,0x8c,0x70,0x8d,0xe2,0x04,0xe0,0xa0,0xe3,0x8c,0xc0,0x8d,0xe5, -0x00,0x00,0x91,0xe5,0x06,0x20,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x07,0x30,0xa0,0xe1, -0xc0,0xc0,0x8d,0xe2,0x90,0xe0,0x8d,0xe5,0x00,0xc0,0x8d,0xe5,0x15,0x02,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x10,0x00,0x00,0x1a,0xc0,0x20,0x9d,0xe5,0x30,0x34,0x9f,0xe5, -0x03,0x00,0x52,0xe1,0x01,0x00,0x00,0x0a,0x0d,0x90,0xa0,0xe3,0x8f,0xff,0xff,0xea, -0x00,0x04,0x9f,0xe5,0x11,0x10,0xa0,0xe3,0x06,0x20,0xa0,0xe1,0x07,0x30,0xa0,0xe1, -0x00,0xc0,0x90,0xe5,0xbc,0x00,0x8d,0xe2,0x00,0x00,0x8d,0xe5,0x0c,0x00,0xa0,0xe1, -0x04,0x02,0x00,0xeb,0x00,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a,0x01,0x90,0xa0,0xe3, -0x82,0xff,0xff,0xea,0xcc,0x13,0x9f,0xe5,0xb8,0xc0,0x8d,0xe2,0x06,0x20,0xa0,0xe1, -0x07,0x30,0xa0,0xe1,0x00,0x00,0x91,0xe5,0x12,0x10,0xa0,0xe3,0x00,0xc0,0x8d,0xe5, -0xf8,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0xf3,0xff,0xff,0x1a,0xbc,0xa0,0x9d,0xe5, -0x08,0x30,0x4a,0xe2,0x0f,0x00,0x53,0xe3,0xe2,0xff,0xff,0x8a,0xb8,0xc0,0x9d,0xe5, -0x07,0x00,0x5c,0xe3,0xdf,0xff,0xff,0x9a,0x0c,0x00,0x5c,0xe3,0xdd,0xff,0xff,0x8a, -0x3c,0x30,0x9d,0xe5,0x03,0x00,0x5a,0xe1,0x2f,0x00,0x00,0x0a,0x17,0x90,0xa0,0xe3, -0x6a,0xff,0xff,0xea,0x00,0x00,0x98,0xe5,0xea,0xfc,0xff,0xeb,0x14,0x30,0x95,0xe5, -0xab,0xfe,0xff,0xea,0x60,0x33,0x9f,0xe5,0x7c,0x60,0x8d,0xe2,0x28,0x10,0x9d,0xe5, -0x06,0x00,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x6c,0x50,0x8d,0xe2,0x30,0x30,0x8d,0xe5, -0xb0,0x5d,0x00,0xeb,0x05,0x00,0xa0,0xe1,0x28,0x10,0x9d,0xe5,0x10,0x20,0xa0,0xe3, -0x38,0x83,0x9f,0xe5,0xab,0x5d,0x00,0xeb,0x28,0xc0,0x9d,0xe5,0x04,0x00,0xa0,0xe1, -0x04,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1,0x00,0x40,0x8d,0xe5, -0x48,0xc0,0xcd,0xe5,0xf4,0xfa,0xff,0xeb,0x30,0x00,0x9d,0xe5,0x00,0x40,0x88,0xe5, -0x00,0x40,0x80,0xe5,0x52,0xfe,0xff,0xea,0x00,0x00,0x99,0xe5,0x14,0x13,0x9f,0xe5, -0xd0,0xfc,0xff,0xeb,0x00,0x00,0x99,0xe5,0xcc,0xfc,0xff,0xeb,0x68,0x20,0x9d,0xe5, -0x04,0x33,0x9f,0xe5,0x04,0x10,0xb3,0xe5,0x04,0x00,0x92,0xe4,0x01,0x00,0x50,0xe1, -0x03,0x00,0x00,0x1a,0xf4,0x02,0x9f,0xe5,0x00,0x00,0x53,0xe1,0xf8,0xff,0xff,0x1a, -0x88,0xff,0xff,0xea,0x19,0x90,0xa0,0xe3,0x3c,0xff,0xff,0xea,0x40,0x30,0x9d,0xe5, -0x03,0x00,0x5c,0xe1,0xcc,0xff,0xff,0x1a,0x01,0xe0,0xa0,0xe3,0xa4,0x22,0x9f,0xe5, -0x0a,0x90,0x6c,0xe0,0x1e,0xcc,0xa0,0xe1,0x1e,0x99,0xa0,0xe1,0x10,0x10,0xa0,0xe3, -0x00,0x00,0x92,0xe5,0x07,0x30,0xa0,0xe1,0x14,0xc0,0x8d,0xe5,0x06,0x20,0xa0,0xe1, -0xb4,0xc0,0x8d,0xe2,0x18,0x90,0x8d,0xe5,0x00,0xc0,0x8d,0xe5,0xa9,0x01,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xa4,0xff,0xff,0x1a,0x01,0x90,0xa0,0xe3,0xb4,0x30,0x9d,0xe5, -0x19,0xba,0xa0,0xe1,0x01,0x20,0x4b,0xe2,0x03,0x00,0x12,0xe1,0x91,0xff,0xff,0x1a, -0x20,0x30,0x9d,0xe5,0xb0,0xc0,0x8d,0xe2,0x02,0x10,0xa0,0xe3,0x06,0x20,0xa0,0xe1, -0x00,0x00,0x93,0xe5,0x07,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x99,0x01,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x19,0xff,0xff,0x1a,0xb0,0x30,0x9d,0xe5,0x04,0x00,0x53,0xe3, -0x84,0xff,0xff,0x8a,0x1c,0xc2,0x9f,0xe5,0x04,0x10,0xa0,0xe3,0x06,0x20,0xa0,0xe1, -0x07,0x30,0xa0,0xe1,0x00,0x00,0x9c,0xe5,0xac,0xc0,0x8d,0xe2,0x00,0xc0,0x8d,0xe5, -0x8c,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x0c,0xff,0xff,0x1a,0xac,0x30,0x9d,0xe5, -0x04,0x00,0x53,0xe3,0x77,0xff,0xff,0x8a,0xe8,0x11,0x9f,0xe5,0xa8,0xc0,0x8d,0xe2, -0x06,0x20,0xa0,0xe1,0x07,0x30,0xa0,0xe1,0x00,0x00,0x91,0xe5,0x0e,0x10,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0x7f,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0xff,0xfe,0xff,0x1a, -0xa8,0x30,0x9d,0xe5,0x04,0x00,0x53,0xe3,0x00,0xa0,0xa0,0x91,0xa4,0x90,0x8d,0x92, -0x68,0xff,0xff,0x8a,0x03,0x00,0x5a,0xe1,0x49,0x00,0x00,0x2a,0x20,0x20,0x9d,0xe5, -0x09,0x10,0xa0,0xe3,0x07,0x30,0xa0,0xe1,0x8c,0xa0,0x8d,0xe5,0x00,0x00,0x92,0xe5, -0x06,0x20,0xa0,0xe1,0x00,0x90,0x8d,0xe5,0x6e,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x69,0xff,0xff,0x1a,0x7c,0x31,0x9f,0xe5,0xa0,0xc0,0x8d,0xe2,0x08,0x10,0xa0,0xe3, -0x06,0x20,0xa0,0xe1,0x00,0x00,0x93,0xe5,0x07,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x64,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x5f,0xff,0xff,0x1a,0x54,0x11,0x9f,0xe5, -0x9c,0xc0,0x8d,0xe2,0x06,0x20,0xa0,0xe1,0x07,0x30,0xa0,0xe1,0x00,0x00,0x91,0xe5, -0x0a,0x10,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x5a,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x55,0xff,0xff,0x1a,0xa4,0x30,0x9d,0xe5,0x18,0x00,0x9d,0xe5,0x03,0x00,0x50,0xe1, -0x44,0xff,0xff,0x9a,0x14,0x10,0x9d,0xe5,0xa0,0x20,0x9d,0xe5,0x91,0x03,0x03,0xe0, -0x9b,0x32,0x22,0xe0,0x9c,0x30,0x9d,0xe5,0x03,0x20,0x82,0xe0,0xb4,0x30,0x9d,0xe5, -0x03,0x00,0x52,0xe1,0x3b,0xff,0xff,0x8a,0xf8,0x20,0x9f,0xe5,0x98,0xc0,0x8d,0xe2, -0x0b,0x10,0xa0,0xe3,0x07,0x30,0xa0,0xe1,0x00,0x00,0x92,0xe5,0x06,0x20,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0x43,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x3e,0xff,0xff,0x1a, -0xd0,0x10,0x9f,0xe5,0x94,0xc0,0x8d,0xe2,0x06,0x20,0xa0,0xe1,0x07,0x30,0xa0,0xe1, -0x00,0x00,0x91,0xe5,0x0c,0x10,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x39,0x01,0x00,0xeb, -0x00,0x00,0x50,0xe3,0x34,0xff,0xff,0x1a,0x98,0x20,0x9d,0xe5,0x94,0x30,0x9d,0xe5, -0x9c,0x10,0x9d,0xe5,0x03,0x00,0x52,0xe1,0x22,0xff,0xff,0x8a,0x02,0x20,0x81,0xe0, -0x03,0x00,0x52,0xe1,0x1f,0xff,0xff,0x9a,0xa8,0x30,0x9d,0xe5,0x01,0xa0,0x8a,0xe2, -0xb3,0xff,0xff,0xea,0x80,0x90,0xa0,0xe3,0x00,0xa0,0xa0,0xe3,0x20,0x10,0x9d,0xe5, -0x06,0x20,0xa0,0xe1,0x24,0xc0,0x9d,0xe5,0x07,0x30,0xa0,0xe1,0x8c,0xa0,0x8d,0xe5, -0x01,0xa0,0x8a,0xe2,0x00,0x00,0x91,0xe5,0x1f,0x10,0xa0,0xe3,0x00,0xc0,0x8d,0xe5, -0x20,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x1b,0xff,0xff,0x1a,0xc4,0x30,0xdd,0xe5, -0x09,0x00,0x53,0xe1,0x00,0x90,0xa0,0xe1,0x0a,0xff,0xff,0x1a,0x03,0x00,0x5a,0xe3, -0xed,0xff,0xff,0x1a,0x38,0x20,0x9f,0xe5,0x00,0x30,0x92,0xe5,0x01,0x20,0xa0,0xe3, -0x21,0x20,0xc3,0xe5,0x1c,0x20,0x9f,0xe5,0x1c,0xc0,0x9d,0xe5,0x34,0x00,0x83,0xe5, -0x00,0x20,0x92,0xe5,0x34,0x00,0x9d,0xe5,0x30,0xc0,0x83,0xe5,0x00,0x20,0x80,0xe5, -0x68,0xfd,0xff,0xea,0x00,0xa0,0x02,0x40,0x7c,0x90,0x02,0x40,0x50,0xd4,0x02,0x40, -0x54,0xd4,0x02,0x40,0x64,0x94,0x02,0x40,0x58,0xd4,0x02,0x40,0x00,0xb0,0x02,0x40, -0x98,0xd4,0x02,0x40,0x01,0x00,0x02,0x00,0xac,0xd4,0x02,0x40,0xa8,0xd4,0x02,0x40, -0xb8,0xd4,0x02,0x40,0xf0,0x4f,0x2d,0xe9,0x0f,0xa0,0x11,0xe2,0x1c,0xd0,0x4d,0xe2, -0x01,0x40,0xa0,0xe1,0x00,0x60,0xa0,0xe1,0x02,0x50,0xa0,0xe1,0x03,0x70,0xa0,0xe1, -0x40,0x80,0xdd,0xe5,0x44,0x90,0xdd,0xe5,0x00,0x40,0xa0,0x13,0x02,0x00,0x00,0x0a, -0x04,0x00,0xa0,0xe1,0x1c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x04,0x00,0xa0,0xe1, -0x2f,0x64,0x00,0xeb,0x00,0xb0,0x50,0xe2,0x0b,0x40,0xa0,0x01,0xf7,0xff,0xff,0x0a, -0x0a,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0xbe,0x5c,0x00,0xeb,0x00,0x00,0x59,0xe3, -0x2b,0x00,0x00,0x0a,0x00,0x00,0x55,0xe3,0x2d,0x00,0x00,0x1a,0x00,0x00,0xa0,0xe3, -0xed,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfb,0xff,0xff,0x1a,0x01,0x00,0xa0,0xe3, -0xe9,0xfa,0xff,0xeb,0x00,0x10,0x50,0xe2,0xfb,0xff,0xff,0x1a,0x00,0x00,0x55,0xe3, -0x21,0x00,0x00,0x1a,0x24,0xc2,0xa0,0xe1,0x00,0xa0,0xa0,0xe3,0x0a,0x00,0xa0,0xe1, -0x00,0xa0,0x8d,0xe5,0x0c,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x0b,0x30,0xa0,0xe1, -0x14,0xc0,0x8d,0xe5,0x72,0xfa,0xff,0xeb,0x0a,0x00,0x58,0xe1,0x14,0xc0,0x9d,0xe5, -0x0b,0x00,0x00,0x0a,0x0a,0x00,0x55,0xe1,0x31,0x00,0x00,0x1a,0x04,0x81,0x9f,0xe5, -0x01,0x00,0xa0,0xe3,0x00,0x11,0x9f,0xe5,0x06,0x20,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x08,0x30,0xa0,0xe1,0xa0,0x00,0x8d,0xe9,0xb5,0xfb,0xff,0xeb,0x00,0x00,0x57,0xe3, -0x17,0x00,0x00,0x1a,0x04,0x20,0xa0,0xe1,0x06,0x00,0xa0,0xe1,0x0b,0x10,0xa0,0xe1, -0x01,0x40,0xa0,0xe3,0x91,0x5c,0x00,0xeb,0x0b,0x00,0xa0,0xe1,0xfd,0x63,0x00,0xeb, -0xc6,0xff,0xff,0xea,0xbd,0x61,0x00,0xeb,0xd1,0xff,0xff,0xea,0x39,0xfa,0xff,0xeb, -0xdb,0xff,0xff,0xea,0x3f,0xf9,0xff,0xeb,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe1, -0x34,0xfa,0xff,0xeb,0x01,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x31,0xfa,0xff,0xeb, -0x00,0x00,0x58,0xe3,0xc8,0xff,0xff,0x0a,0x01,0x00,0xa0,0xe3,0xb1,0xfb,0xff,0xeb, -0xc5,0xff,0xff,0xea,0x01,0x00,0xa0,0xe3,0x08,0x10,0xa0,0xe1,0xb1,0xfb,0xff,0xeb, -0x01,0x00,0xa0,0xe3,0xad,0xfb,0xff,0xeb,0x70,0x20,0x9f,0xe5,0x00,0x30,0xa0,0xe3, -0x00,0x00,0x92,0xe5,0x03,0x10,0x90,0xe7,0x03,0x20,0x98,0xe7,0x04,0x30,0x83,0xe2, -0x02,0x00,0x51,0xe1,0x11,0x00,0x00,0x1a,0x10,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a, -0xd7,0xff,0xff,0xea,0x01,0x00,0xa0,0xe3,0x0a,0x10,0xa0,0xe1,0x19,0xfa,0xff,0xeb, -0x01,0x00,0xa0,0xe3,0x30,0x10,0x9f,0xe5,0xe1,0xfa,0xff,0xeb,0x0a,0x00,0x59,0xe1, -0x14,0xc0,0x9d,0xe5,0x24,0x30,0x9f,0x15,0x10,0x20,0x46,0x12,0x1c,0x30,0x9f,0x05, -0x48,0x20,0x9d,0x05,0x00,0x20,0x83,0x15,0x00,0x20,0x83,0x05,0xbe,0xff,0xff,0xea, -0x00,0x40,0xa0,0xe3,0xcb,0xff,0xff,0xea,0x6c,0x90,0x02,0x40,0x80,0x90,0x02,0x40, -0x68,0x90,0x02,0x40,0x04,0x30,0x9f,0xe5,0x00,0x00,0x83,0xe5,0x1e,0xff,0x2f,0xe1, -0x64,0x90,0x02,0x40,0x10,0x40,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0x06,0xfc,0xff,0xeb, -0x00,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3,0x08,0x30,0x9f,0x05,0x00,0x30,0x93,0x05, -0x00,0x30,0x84,0x05,0x10,0x80,0xbd,0xe8,0x64,0x90,0x02,0x40,0x04,0x30,0x9f,0xe5, -0x00,0x00,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x54,0x82,0x02,0x40,0x10,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0xcd,0xfb,0xff,0xeb,0x00,0x30,0x94,0xe5,0x05,0x00,0x53,0xe3, -0x08,0x30,0x9f,0x85,0x00,0x30,0x93,0x85,0x00,0x30,0x84,0x85,0x10,0x80,0xbd,0xe8, -0x54,0x82,0x02,0x40,0x1e,0xff,0x2f,0xe1,0xf0,0x40,0x2d,0xe9,0x00,0x30,0xa0,0xe3, -0x2c,0xd0,0x4d,0xe2,0x00,0x50,0xa0,0xe1,0x01,0x60,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x20,0x30,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x80,0x01,0x00,0xeb,0x20,0x00,0x50,0xe3, -0x27,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3,0x27,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3, -0x02,0x70,0xa0,0x13,0x02,0x00,0x00,0x0a,0x07,0x00,0xa0,0xe1,0x2c,0xd0,0x8d,0xe2, -0xf0,0x80,0xbd,0xe8,0x77,0x09,0x00,0xeb,0x01,0x30,0x74,0xe2,0x00,0x30,0xa0,0x33, -0x00,0x00,0x55,0xe3,0x00,0x20,0xa0,0x03,0x01,0x20,0x03,0x12,0x00,0x00,0x52,0xe3, -0x11,0x00,0x00,0x1a,0x00,0x00,0x53,0xe3,0x13,0x00,0x00,0x1a,0x00,0x30,0x56,0xe2, -0x01,0x30,0xa0,0x13,0x00,0x00,0x55,0xe3,0x00,0x20,0xa0,0x13,0x01,0x20,0x03,0x02, -0x00,0x00,0x52,0xe3,0x0c,0x00,0x00,0x1a,0x00,0x00,0x53,0xe3,0x10,0x00,0x00,0x0a, -0x00,0x30,0x95,0xe5,0x03,0x00,0x50,0xe1,0x06,0x70,0xa0,0x83,0xe5,0xff,0xff,0x8a, -0x00,0x60,0x84,0xe5,0x00,0x70,0xa0,0xe3,0xe2,0xff,0xff,0xea,0x00,0x70,0x95,0xe5, -0x00,0x00,0x57,0xe3,0x00,0x00,0x85,0x05,0xde,0xff,0xff,0x0a,0x09,0x70,0xa0,0xe3, -0xdc,0xff,0xff,0xea,0x05,0x02,0x00,0xeb,0xde,0xff,0xff,0xea,0xad,0x05,0x00,0xeb, -0xdc,0xff,0xff,0xea,0x1c,0x00,0x8d,0xe2,0x63,0x01,0x00,0xeb,0x00,0x70,0x50,0xe2, -0x0d,0x00,0x00,0x1a,0x04,0x30,0xa0,0xe3,0x18,0x60,0x8d,0xe2,0x18,0x30,0x8d,0xe5, -0x14,0x50,0x8d,0xe2,0x27,0x30,0x8d,0xe2,0x07,0x10,0xa0,0xe3,0x00,0x30,0x8d,0xe5, -0x06,0x20,0xa0,0xe1,0x1c,0x00,0x9d,0xe5,0x05,0x30,0xa0,0xe1,0x14,0x70,0x8d,0xe5, -0x80,0x01,0x00,0xeb,0x00,0x70,0x50,0xe2,0x02,0x00,0x00,0x0a,0x1c,0x00,0x9d,0xe5, -0x7b,0x01,0x00,0xeb,0xc3,0xff,0xff,0xea,0x0c,0x30,0x8d,0xe2,0x0b,0x10,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x06,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1,0x1c,0x00,0x9d,0xe5, -0x74,0x01,0x00,0xeb,0x00,0x70,0x50,0xe2,0xf3,0xff,0xff,0x1a,0x10,0x30,0x8d,0xe2, -0x1c,0x00,0x9d,0xe5,0x00,0x30,0x8d,0xe5,0x0a,0x10,0xa0,0xe3,0x06,0x20,0xa0,0xe1, -0x05,0x30,0xa0,0xe1,0x6b,0x01,0x00,0xeb,0x00,0x70,0x50,0xe2,0xea,0xff,0xff,0x1a, -0x20,0x30,0x8d,0xe2,0x07,0x20,0xa0,0xe1,0x00,0x30,0x8d,0xe5,0x03,0x30,0xa0,0xe3, -0x0c,0x00,0x9d,0xe5,0x10,0x10,0x9d,0xe5,0x09,0x61,0x00,0xeb,0x00,0x70,0x50,0xe2, -0xe1,0xff,0xff,0x1a,0x1c,0x00,0x9d,0xe5,0x5d,0x01,0x00,0xeb,0x20,0x60,0x9d,0xe5, -0xbe,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0xf0,0x41,0x2d,0xe9,0x00,0x70,0x50,0xe2, -0x10,0xd0,0x4d,0xe2,0x01,0x60,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x03,0x50,0xa0,0xe1, -0x28,0x80,0x9d,0xe5,0x6a,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13, -0x02,0x00,0x00,0x1a,0x09,0x00,0xa0,0xe3,0x10,0xd0,0x8d,0xe2,0xf0,0x81,0xbd,0xe8, -0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x4a,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x48,0x00,0x00,0xea,0x26,0x00,0x00,0xea,0x46,0x00,0x00,0xea,0x24,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x43,0x00,0x00,0xea,0x3d,0x00,0x00,0xea,0x41,0x00,0x00,0xea, -0x40,0x00,0x00,0xea,0x3f,0x00,0x00,0xea,0x3e,0x00,0x00,0xea,0x3d,0x00,0x00,0xea, -0x3c,0x00,0x00,0xea,0x1a,0x00,0x00,0xea,0x3a,0x00,0x00,0xea,0x18,0x00,0x00,0xea, -0x17,0x00,0x00,0xea,0x16,0x00,0x00,0xea,0x36,0x00,0x00,0xea,0x35,0x00,0x00,0xea, -0x13,0x00,0x00,0xea,0x33,0x00,0x00,0xea,0x32,0x00,0x00,0xea,0x31,0x00,0x00,0xea, -0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea,0x0d,0x00,0x00,0xea,0x2d,0x00,0x00,0xea, -0x2c,0x00,0x00,0xea,0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x29,0x00,0x00,0xea, -0x28,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x26,0x00,0x00,0xea,0x25,0x00,0x00,0xea, -0x24,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0x22,0x00,0x00,0xea,0x21,0x00,0x00,0xea, -0xff,0xff,0xff,0xea,0x04,0x30,0xa0,0xe3,0x01,0x20,0xa0,0xe3,0x0c,0x30,0x8d,0xe5, -0x08,0x20,0x8d,0xe5,0x00,0x10,0x94,0xe5,0x00,0x00,0x51,0xe3,0x2a,0x00,0x00,0x0a, -0x00,0x30,0x84,0xe5,0x00,0x30,0x95,0xe5,0x02,0x00,0x53,0xe1,0x2c,0x00,0x00,0x8a, -0x00,0x00,0x58,0xe3,0xc2,0xff,0xff,0x0a,0xd4,0x00,0x00,0xeb,0x20,0x00,0x50,0xe3, -0x3c,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3,0x2d,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3, -0x02,0x00,0xa0,0x13,0xbb,0xff,0xff,0x1a,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x04,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x3a,0x09,0x00,0xeb, -0xb4,0xff,0xff,0xea,0x01,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x0c,0x20,0x8d,0xe5, -0x08,0x20,0x8d,0xe5,0xe2,0xff,0xff,0xea,0xc0,0x00,0x00,0xeb,0x20,0x00,0x50,0xe3, -0x22,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3,0x13,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3, -0x0f,0x00,0x00,0x1a,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2, -0x08,0x30,0x8d,0xe2,0xb9,0x08,0x00,0xeb,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x1a, -0x08,0x20,0x9d,0xe5,0x0c,0x30,0x9d,0xe5,0xd1,0xff,0xff,0xea,0x00,0x00,0x58,0xe3, -0x00,0x30,0x84,0xe5,0x08,0x00,0xa0,0x01,0x06,0x00,0xa0,0x13,0x00,0x20,0x85,0xe5, -0x98,0xff,0xff,0xea,0x04,0x00,0xa0,0xe3,0x96,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1, -0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2,0x00,0x05,0x00,0xeb, -0xec,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1, -0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x5b,0x05,0x00,0xeb,0x89,0xff,0xff,0xea, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2, -0x48,0x01,0x00,0xeb,0xdf,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x04,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0xa1,0x01,0x00,0xeb, -0x7c,0xff,0xff,0xea,0xf0,0x41,0x2d,0xe9,0x00,0x70,0x50,0xe2,0x10,0xd0,0x4d,0xe2, -0x01,0x60,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x03,0x50,0xa0,0xe1,0x28,0x80,0x9d,0xe5, -0x6a,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13,0x02,0x00,0x00,0x1a, -0x09,0x00,0xa0,0xe3,0x10,0xd0,0x8d,0xe2,0xf0,0x81,0xbd,0xe8,0x29,0x00,0x51,0xe3, -0x01,0xf1,0x8f,0x90,0x4a,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x48,0x00,0x00,0xea, -0x26,0x00,0x00,0xea,0x46,0x00,0x00,0xea,0x24,0x00,0x00,0xea,0x44,0x00,0x00,0xea, -0x43,0x00,0x00,0xea,0x3d,0x00,0x00,0xea,0x41,0x00,0x00,0xea,0x40,0x00,0x00,0xea, -0x3f,0x00,0x00,0xea,0x3e,0x00,0x00,0xea,0x3d,0x00,0x00,0xea,0x3c,0x00,0x00,0xea, -0x1a,0x00,0x00,0xea,0x3a,0x00,0x00,0xea,0x18,0x00,0x00,0xea,0x17,0x00,0x00,0xea, -0x16,0x00,0x00,0xea,0x36,0x00,0x00,0xea,0x35,0x00,0x00,0xea,0x13,0x00,0x00,0xea, -0x33,0x00,0x00,0xea,0x32,0x00,0x00,0xea,0x31,0x00,0x00,0xea,0x0f,0x00,0x00,0xea, -0x0e,0x00,0x00,0xea,0x0d,0x00,0x00,0xea,0x2d,0x00,0x00,0xea,0x2c,0x00,0x00,0xea, -0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x29,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x27,0x00,0x00,0xea,0x26,0x00,0x00,0xea,0x25,0x00,0x00,0xea,0x24,0x00,0x00,0xea, -0x23,0x00,0x00,0xea,0x22,0x00,0x00,0xea,0x21,0x00,0x00,0xea,0xff,0xff,0xff,0xea, -0x04,0x30,0xa0,0xe3,0x01,0x20,0xa0,0xe3,0x0c,0x30,0x8d,0xe5,0x08,0x20,0x8d,0xe5, -0x00,0x10,0x94,0xe5,0x00,0x00,0x51,0xe3,0x2a,0x00,0x00,0x0a,0x00,0x30,0x84,0xe5, -0x00,0x30,0x95,0xe5,0x02,0x00,0x53,0xe1,0x2c,0x00,0x00,0x8a,0x00,0x00,0x58,0xe3, -0xc2,0xff,0xff,0x0a,0x45,0x00,0x00,0xeb,0x20,0x00,0x50,0xe3,0x3c,0x00,0x00,0x0a, -0x30,0x00,0x50,0xe3,0x2d,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x02,0x00,0xa0,0x13, -0xbb,0xff,0xff,0x1a,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1, -0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x7b,0x0a,0x00,0xeb,0xb4,0xff,0xff,0xea, -0x01,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x0c,0x20,0x8d,0xe5,0x08,0x20,0x8d,0xe5, -0xe2,0xff,0xff,0xea,0x31,0x00,0x00,0xeb,0x20,0x00,0x50,0xe3,0x22,0x00,0x00,0x0a, -0x30,0x00,0x50,0xe3,0x13,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x0f,0x00,0x00,0x1a, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2, -0x2a,0x08,0x00,0xeb,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x1a,0x08,0x20,0x9d,0xe5, -0x0c,0x30,0x9d,0xe5,0xd1,0xff,0xff,0xea,0x00,0x00,0x58,0xe3,0x00,0x30,0x84,0xe5, -0x08,0x00,0xa0,0x01,0x06,0x00,0xa0,0x13,0x00,0x20,0x85,0xe5,0x98,0xff,0xff,0xea, -0x04,0x00,0xa0,0xe3,0x96,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2,0x71,0x04,0x00,0xeb,0xec,0xff,0xff,0xea, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0x80,0x8d,0xe5,0x35,0x06,0x00,0xeb,0x89,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1, -0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2,0xb9,0x00,0x00,0xeb, -0xdf,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1, -0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x81,0x02,0x00,0xeb,0x7c,0xff,0xff,0xea, -0x10,0x40,0x2d,0xe9,0x10,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe3,0x10,0x30,0x8d,0xe2, -0x01,0x1a,0xa0,0xe3,0x04,0x20,0xa0,0xe1,0x04,0x40,0x23,0xe5,0x07,0x02,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x03,0x30,0xa0,0xe3,0xd9,0x5f,0x00,0xeb,0x04,0x00,0x50,0xe1, -0x0c,0x30,0x9d,0x05,0x04,0x00,0xa0,0x11,0x04,0x08,0x93,0x05,0x20,0x04,0xa0,0x01, -0xff,0x00,0x00,0x02,0x10,0xd0,0x8d,0xe2,0x10,0x80,0xbd,0xe8,0x30,0x40,0x2d,0xe9, -0x00,0x40,0x50,0xe2,0x14,0xd0,0x4d,0xe2,0x09,0x00,0xa0,0x03,0x0a,0x00,0x00,0x0a, -0x00,0xe0,0xa0,0xe3,0x10,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3, -0x0e,0x20,0xa0,0xe1,0x03,0x30,0xa0,0xe3,0x04,0xe0,0x2c,0xe5,0x00,0xc0,0x8d,0xe5, -0xc3,0x5f,0x00,0xeb,0x00,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a,0x14,0xd0,0x8d,0xe2, -0x30,0x80,0xbd,0xe8,0x0c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x04,0x58,0x90,0xe5, -0xe1,0x5f,0x00,0xeb,0x25,0x54,0xa0,0xe1,0xff,0x50,0x05,0xe2,0x20,0x00,0x55,0xe3, -0x09,0x00,0x00,0x0a,0x30,0x00,0x55,0xe3,0x0a,0x00,0x00,0x0a,0x35,0x00,0x55,0xe3, -0x02,0x00,0xa0,0x13,0xf0,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x99,0x0b,0x00,0xeb, -0x04,0x00,0x50,0xe3,0x01,0x00,0xa0,0x03,0xeb,0xff,0xff,0xea,0x04,0x00,0xa0,0xe1, -0x94,0x03,0x00,0xeb,0xf9,0xff,0xff,0xea,0x04,0x00,0xa0,0xe1,0x39,0x07,0x00,0xeb, -0xf6,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0xf0,0x41,0x2d,0xe9,0x00,0x70,0x50,0xe2, -0x10,0xd0,0x4d,0xe2,0x00,0x00,0xa0,0xe3,0x01,0x60,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x03,0x50,0xa0,0xe1,0x28,0x80,0x9d,0xe5,0x0c,0x00,0x8d,0xe5,0x08,0x00,0x8d,0xe5, -0x3f,0x00,0x00,0x0a,0x00,0x00,0x52,0xe1,0x00,0x00,0x53,0x11,0x3a,0x00,0x00,0x0a, -0x0e,0x00,0x51,0xe3,0x12,0x00,0x00,0x9a,0xb0,0xff,0xff,0xeb,0x20,0x00,0x50,0xe3, -0x39,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3,0x3f,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3, -0x45,0x00,0x00,0x0a,0x08,0x30,0x9d,0xe5,0x0c,0x20,0x9d,0xe5,0x00,0x10,0x94,0xe5, -0x00,0x00,0x51,0xe3,0x17,0x00,0x00,0x1a,0x00,0x00,0x58,0xe3,0x00,0x20,0x84,0xe5, -0x08,0x00,0xa0,0x01,0x06,0x00,0xa0,0x13,0x00,0x30,0x85,0xe5,0x10,0xd0,0x8d,0xe2, -0xf0,0x81,0xbd,0xe8,0x01,0x30,0xa0,0xe3,0x2c,0x21,0x9f,0xe5,0x13,0x11,0xa0,0xe1, -0x02,0x20,0x01,0xe0,0x00,0x00,0x52,0xe1,0x04,0x20,0xa0,0x13,0x08,0x30,0x8d,0x15, -0x0c,0x20,0x8d,0x15,0xec,0xff,0xff,0x1a,0x80,0x00,0x11,0xe3,0xe1,0xff,0xff,0x0a, -0x0c,0x30,0x8d,0xe5,0x03,0x20,0xa0,0xe1,0x08,0x30,0x8d,0xe5,0x00,0x10,0x94,0xe5, -0x00,0x00,0x51,0xe3,0xe7,0xff,0xff,0x0a,0x00,0x20,0x84,0xe5,0x00,0x20,0x95,0xe5, -0x03,0x00,0x52,0xe1,0x12,0x00,0x00,0x8a,0x00,0x00,0x58,0xe3,0x0e,0x00,0x00,0x0a, -0x86,0xff,0xff,0xeb,0x20,0x00,0x50,0xe3,0x25,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3, -0x2a,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x02,0x00,0xa0,0x13,0xde,0xff,0xff,0x1a, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0x80,0x8d,0xe5,0x6b,0x0b,0x00,0xeb,0xd7,0xff,0xff,0xea,0x09,0x00,0xa0,0xe3, -0xd5,0xff,0xff,0xea,0x04,0x00,0xa0,0xe3,0xd3,0xff,0xff,0xea,0x0c,0x20,0x8d,0xe2, -0x08,0x30,0x8d,0xe2,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x32,0x03,0x00,0xeb, -0x08,0x30,0x9d,0xe5,0x0c,0x20,0x9d,0xe5,0xc3,0xff,0xff,0xea,0x0c,0x20,0x8d,0xe2, -0x08,0x30,0x8d,0xe2,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0xd2,0x06,0x00,0xeb, -0x08,0x30,0x9d,0xe5,0x0c,0x20,0x9d,0xe5,0xbb,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1, -0x06,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x30,0x8d,0xe2,0x22,0x0b,0x00,0xeb, -0xb3,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1, -0x05,0x30,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x4a,0x03,0x00,0xeb,0xb6,0xff,0xff,0xea, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0x80,0x8d,0xe5,0xeb,0x06,0x00,0xeb,0xaf,0xff,0xff,0xea,0x7f,0x4f,0x00,0x00, -0xff,0x0e,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x10,0x41,0xe2,0x1e,0x00,0x51,0xe3, -0x01,0xf1,0x8f,0x90,0x34,0x00,0x00,0xea,0x35,0x00,0x00,0xea,0x32,0x00,0x00,0xea, -0x39,0x00,0x00,0xea,0x30,0x00,0x00,0xea,0x19,0x00,0x00,0xea,0x18,0x00,0x00,0xea, -0x2d,0x00,0x00,0xea,0x16,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x14,0x00,0x00,0xea, -0x13,0x00,0x00,0xea,0x12,0x00,0x00,0xea,0x11,0x00,0x00,0xea,0x26,0x00,0x00,0xea, -0x3f,0x00,0x00,0xea,0x24,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0x22,0x00,0x00,0xea, -0x41,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x1f,0x00,0x00,0xea,0x08,0x00,0x00,0xea, -0x17,0x00,0x00,0xea,0x16,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x1a,0x00,0x00,0xea, -0x19,0x00,0x00,0xea,0x2c,0x00,0x00,0xea,0x01,0x00,0x00,0xea,0x16,0x00,0x00,0xea, -0x23,0x00,0x00,0xea,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x00,0x10,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x2d,0x0d,0x80,0xe2,0x4a,0x1e,0x80,0xe2, -0x09,0x00,0x80,0xe2,0x03,0x00,0xc0,0xe3,0x0c,0x10,0x81,0xe2,0x01,0x10,0x60,0xe0, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x10,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x02,0x1c,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x01,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x03,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0xff,0x1e,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x82,0x1f,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x10,0x10,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0xa6,0x04,0x00,0x00,0x70,0x40,0x2d,0xe9,0x2d,0x4d,0x80,0xe2, -0x08,0xd0,0x4d,0xe2,0x04,0x50,0x84,0xe2,0x00,0xc0,0xa0,0xe1,0x4a,0x6e,0x85,0xe2, -0x18,0x00,0x9d,0xe5,0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x3d,0x00,0x00,0xea, -0x37,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0x0e,0x01,0x00,0xea,0x06,0x01,0x00,0xea, -0x00,0x01,0x00,0xea,0x37,0x00,0x00,0xea,0x36,0x00,0x00,0xea,0xf8,0x00,0x00,0xea, -0xed,0x00,0x00,0xea,0xe2,0x00,0x00,0xea,0xd9,0x00,0x00,0xea,0xce,0x00,0x00,0xea, -0xc3,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0xbc,0x00,0x00,0xea,0xb5,0x00,0x00,0xea, -0xaf,0x00,0x00,0xea,0xa9,0x00,0x00,0xea,0xa3,0x00,0x00,0xea,0x9d,0x00,0x00,0xea, -0x96,0x00,0x00,0xea,0x8e,0x00,0x00,0xea,0x26,0x00,0x00,0xea,0x25,0x00,0x00,0xea, -0x79,0x00,0x00,0xea,0x71,0x00,0x00,0xea,0x69,0x00,0x00,0xea,0x63,0x00,0x00,0xea, -0x5d,0x00,0x00,0xea,0x55,0x00,0x00,0xea,0x1e,0x00,0x00,0xea,0x4b,0x00,0x00,0xea, -0x08,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x1a,0x00,0x00,0xea,0x19,0x00,0x00,0xea, -0x18,0x00,0x00,0xea,0x17,0x00,0x00,0xea,0x16,0x00,0x00,0xea,0x15,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x3a,0x00,0x00,0xea,0x00,0x10,0x93,0xe5,0x34,0xc0,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x01,0x11,0x8c,0xe0,0x68,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0xd0,0x8d,0xe2,0x70,0x80,0xbd,0xe8,0x00,0x10,0x93,0xe5,0x44,0xc0,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x01,0x12,0x8c,0xe0,0x60,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf6,0xff,0xff,0xea,0x20,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x5b,0x59,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf1,0xff,0xff,0xea,0x00,0x00,0x5c,0xe3,0xd6,0x00,0x00,0x0a, -0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13,0xd3,0x00,0x00,0x0a,0x00,0x00,0x50,0xe3, -0xd1,0x00,0x00,0x0a,0x05,0x10,0x41,0xe2,0x1b,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90, -0xcd,0x00,0x00,0xea,0xe1,0x00,0x00,0xea,0x0f,0x01,0x00,0xea,0xca,0x00,0x00,0xea, -0xc9,0x00,0x00,0xea,0xc8,0x00,0x00,0xea,0xc7,0x00,0x00,0xea,0xc6,0x00,0x00,0xea, -0xc5,0x00,0x00,0xea,0xe3,0x00,0x00,0xea,0xc3,0x00,0x00,0xea,0xc2,0x00,0x00,0xea, -0xc1,0x00,0x00,0xea,0xc0,0x00,0x00,0xea,0xbf,0x00,0x00,0xea,0xbe,0x00,0x00,0xea, -0xbd,0x00,0x00,0xea,0xbc,0x00,0x00,0xea,0xd6,0xff,0xff,0xea,0xbc,0x00,0x00,0xea, -0xb9,0x00,0x00,0xea,0xb8,0x00,0x00,0xea,0xb7,0x00,0x00,0xea,0xb6,0x00,0x00,0xea, -0xb5,0x00,0x00,0xea,0xb4,0x00,0x00,0xea,0xb3,0x00,0x00,0xea,0xb2,0x00,0x00,0xea, -0xc4,0xff,0xff,0xea,0x08,0x10,0x8d,0xe2,0x04,0x30,0xa0,0xe3,0x04,0x30,0x21,0xe5, -0x00,0x20,0x92,0xe5,0x2d,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xc3,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0xfe,0x1e,0x8c,0xe2,0x0d,0x10,0x81,0xe2,0x00,0x20,0x92,0xe5, -0x03,0x10,0x81,0xe0,0x25,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xbb,0xff,0xff,0xea, -0x08,0x10,0x8d,0xe2,0xff,0x3e,0xa0,0xe3,0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5, -0x1e,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xb4,0xff,0xff,0xea,0x0c,0x10,0xa0,0xe1, -0xff,0x2e,0xa0,0xe3,0x19,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xaf,0xff,0xff,0xea, -0x06,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x14,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xaa,0xff,0xff,0xea,0x08,0x10,0x8d,0xe2,0xfe,0x3e,0xa0,0xe3,0x04,0x30,0x21,0xe5, -0x00,0x20,0x92,0xe5,0x0d,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xa3,0xff,0xff,0xea, -0x08,0x10,0x8d,0xe2,0x10,0x30,0xa0,0xe3,0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5, -0x06,0x59,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x9c,0xff,0xff,0xea,0x00,0x30,0xa0,0xe1, -0x00,0x20,0xa0,0xe3,0x10,0x10,0x9c,0xe5,0x02,0x10,0xc0,0xe7,0x04,0x20,0x82,0xe2, -0x10,0x10,0x9c,0xe5,0x10,0x00,0x52,0xe3,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc3,0xe5, -0xb2,0x11,0xdc,0xe1,0x02,0x10,0xc3,0xe5,0x13,0x10,0xdc,0xe5,0x04,0xc0,0x8c,0xe2, -0x03,0x10,0xc3,0xe5,0x04,0x30,0x83,0xe2,0xf1,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3, -0x8a,0xff,0xff,0xea,0x44,0x3b,0xdc,0xe5,0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5, -0x04,0x30,0x21,0xe5,0xed,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x83,0xff,0xff,0xea, -0x09,0x10,0x84,0xe2,0x00,0x20,0x92,0xe5,0x03,0x10,0xc1,0xe3,0xe7,0x58,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x7d,0xff,0xff,0xea,0x02,0x10,0x85,0xe2,0x00,0x20,0x92,0xe5, -0xe2,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x78,0xff,0xff,0xea,0x28,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xdd,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x73,0xff,0xff,0xea, -0x24,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xd8,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x6e,0xff,0xff,0xea,0x2c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xd3,0x58,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x69,0xff,0xff,0xea,0x22,0x1d,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x08,0x10,0x81,0xe2,0xcd,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x63,0xff,0xff,0xea, -0xa9,0x1e,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xc8,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x5e,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0xaa,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x08,0x10,0x81,0xe2, -0xbe,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x54,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0xaa,0x1e,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x04,0x10,0x81,0xe2,0xb4,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x4a,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0xc1,0x21,0xe0,0xaa,0x1e,0x81,0xe2,0xac,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x42,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0xa9,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x0c,0x10,0x81,0xe2, -0xa2,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x38,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0xa9,0x1e,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x08,0x10,0x81,0xe2,0x98,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x2e,0xff,0xff,0xea,0x04,0x10,0x86,0xe2,0x00,0x20,0x92,0xe5,0x93,0x58,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x29,0xff,0xff,0xea,0x84,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x8e,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x24,0xff,0xff,0xea,0x00,0x10,0x93,0xe5, -0x88,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x81,0x14,0x8c,0xe0,0x87,0x58,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x1d,0xff,0xff,0xea,0x30,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x82,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x18,0xff,0xff,0xea,0x04,0x00,0xa0,0xe3, -0x16,0xff,0xff,0xea,0x00,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3,0x03,0x10,0x9c,0xe7, -0x03,0x10,0xc0,0xe7,0x03,0x10,0x9c,0xe7,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc2,0xe5, -0x03,0x10,0x9c,0xe7,0x21,0x18,0xa0,0xe1,0x02,0x10,0xc2,0xe5,0x03,0x10,0x9c,0xe7, -0x04,0x30,0x83,0xe2,0x10,0x00,0x53,0xe3,0x21,0x1c,0xa0,0xe1,0x03,0x10,0xc2,0xe5, -0x04,0x20,0x82,0xe2,0xf0,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3,0x03,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0, -0xaa,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x0c,0x10,0x81,0xe2,0x63,0x58,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf9,0xfe,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5, -0x01,0x41,0x81,0xe0,0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x11,0x8c,0xe0, -0xb0,0x1a,0x91,0xe5,0x00,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5,0x01,0x41,0x81,0xe0, -0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x11,0x8c,0xe0,0xb0,0x1a,0x91,0xe5, -0x21,0x14,0xa0,0xe1,0x01,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5,0x01,0x41,0x81,0xe0, -0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x11,0x8c,0xe0,0xb0,0x1a,0x91,0xe5, -0x21,0x18,0xa0,0xe1,0x02,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5,0x01,0x41,0x81,0xe0, -0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x20,0x82,0xe2,0x01,0x11,0x8c,0xe0, -0x04,0x00,0x52,0xe3,0xb3,0x1a,0xd1,0xe5,0x03,0x10,0xc0,0xe5,0x04,0x00,0x80,0xe2, -0xdd,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3,0xd4,0xfe,0xff,0xea,0x00,0x30,0x93,0xe5, -0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0xa9,0x1e,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x04,0x10,0x81,0xe2,0x34,0x58,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xca,0xfe,0xff,0xea,0x2d,0xcd,0x80,0xe2,0xf0,0x41,0x2d,0xe9,0x04,0x40,0x8c,0xe2, -0x18,0x50,0x9d,0xe5,0x4a,0x6e,0x84,0xe2,0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90, -0xce,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0xc4,0x00,0x00,0xea,0xbd,0x00,0x00,0xea, -0xb4,0x00,0x00,0xea,0x72,0x00,0x00,0xea,0xc8,0x00,0x00,0xea,0xc7,0x00,0x00,0xea, -0x69,0x00,0x00,0xea,0x5d,0x00,0x00,0xea,0x51,0x00,0x00,0xea,0x47,0x00,0x00,0xea, -0x3b,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0xc0,0x00,0x00,0xea,0x27,0x00,0x00,0xea, -0x7f,0x00,0x00,0xea,0x78,0x00,0x00,0xea,0x71,0x00,0x00,0xea,0x6a,0x00,0x00,0xea, -0x89,0x00,0x00,0xea,0x81,0x00,0x00,0xea,0xb8,0x00,0x00,0xea,0xb7,0x00,0x00,0xea, -0xb6,0x00,0x00,0xea,0x8a,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x14,0x00,0x00,0xea, -0x96,0x00,0x00,0xea,0x14,0x00,0x00,0xea,0xb0,0x00,0x00,0xea,0xaf,0x00,0x00,0xea, -0xd4,0x00,0x00,0xea,0xcb,0x00,0x00,0xea,0xac,0x00,0x00,0xea,0xab,0x00,0x00,0xea, -0xaa,0x00,0x00,0xea,0xa9,0x00,0x00,0xea,0xa8,0x00,0x00,0xea,0xa7,0x00,0x00,0xea, -0xa6,0x00,0x00,0xea,0xa5,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x20,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xfc,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x08,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0xf5,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0xa9,0x0e,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xef,0x57,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xaa,0x3e,0x83,0xe2, -0x03,0x00,0x80,0xe0,0x08,0x00,0x80,0xe2,0xe4,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xaa,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x04,0x00,0x80,0xe2,0xd9,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x20,0xe0,0xaa,0x0e,0x80,0xe2,0xd0,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xa9,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x0c,0x00,0x80,0xe2,0xc5,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0xa9,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x08,0x00,0x80,0xe2, -0xba,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x04,0x00,0x86,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xb4,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x84,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xae,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x28,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xa8,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x24,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xa2,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x2c,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x22,0x0d,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x08,0x00,0x80,0xe2, -0x00,0x20,0x92,0xe5,0x95,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x09,0x00,0x8c,0xe2,0x05,0x10,0xa0,0xe1,0x03,0x00,0xc0,0xe3,0x00,0x20,0x92,0xe5, -0x8e,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x02,0x00,0x84,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x88,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x0c,0x00,0x80,0xe2,0x10,0x40,0x85,0xe2,0x02,0x30,0xd5,0xe5, -0x03,0xc0,0xd5,0xe5,0x00,0x10,0xd5,0xe5,0x01,0x20,0xd5,0xe5,0x04,0x50,0x85,0xe2, -0x03,0x38,0xa0,0xe1,0x04,0x00,0x55,0xe1,0x0c,0x3c,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x34,0x83,0xe1,0x04,0x30,0xa0,0xe5,0xf3,0xff,0xff,0x1a,0x7a,0xff,0xff,0xea, -0x06,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x73,0x57,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x88,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x83,0x04,0x80,0xe0,0x6b,0x57,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x30,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x65,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x44,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x03,0x02,0x80,0xe0,0x5d,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13, -0x63,0x00,0x00,0x0a,0x00,0x00,0x55,0xe3,0x61,0x00,0x00,0x0a,0x05,0x10,0x41,0xe2, -0x12,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x5b,0x00,0x00,0xea,0x4f,0x00,0x00,0xea, -0x43,0x00,0x00,0xea,0x58,0x00,0x00,0xea,0x57,0x00,0x00,0xea,0x56,0x00,0x00,0xea, -0x55,0x00,0x00,0xea,0x54,0x00,0x00,0xea,0x53,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x51,0x00,0x00,0xea,0x50,0x00,0x00,0xea,0x4f,0x00,0x00,0xea,0x4e,0x00,0x00,0xea, -0x4d,0x00,0x00,0xea,0x4c,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0x4a,0x00,0x00,0xea, -0x49,0x00,0x00,0xea,0x10,0x00,0x00,0xea,0x00,0x30,0x93,0xe5,0x34,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x01,0x80,0xe0,0x37,0x57,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0xfe,0x0e,0x80,0xe2, -0x0d,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x00,0x80,0xe0, -0x2e,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x10,0x40,0x85,0xe2, -0x02,0x10,0xd5,0xe5,0x03,0xc0,0xd5,0xe5,0x00,0x30,0xd5,0xe5,0x01,0x20,0xd5,0xe5, -0x04,0x50,0x85,0xe2,0x01,0x18,0xa0,0xe1,0x04,0x00,0x55,0xe1,0x0c,0x1c,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x34,0x83,0xe1,0x04,0x30,0x80,0xe4,0xf3,0xff,0xff,0x1a, -0x21,0xff,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5,0x02,0x60,0xd5,0xe5, -0x03,0x70,0xd5,0xe5,0x00,0xc0,0xd5,0xe5,0x01,0x81,0x81,0xe0,0x01,0x40,0xd5,0xe5, -0x06,0x68,0xa0,0xe1,0x04,0x50,0x85,0xe2,0x88,0x10,0x81,0xe0,0x07,0x6c,0x86,0xe1, -0x02,0x10,0x81,0xe0,0x0c,0xc0,0x86,0xe1,0x01,0x20,0x82,0xe2,0x01,0x11,0x80,0xe0, -0x04,0xc4,0x8c,0xe1,0x04,0x00,0x52,0xe3,0xb0,0xca,0x81,0xe5,0xed,0xff,0xff,0x1a, -0x0d,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xa9,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x04,0x00,0x80,0xe2,0x01,0x57,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0xaa,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x0c,0x00,0x80,0xe2, -0xf6,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x04,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x04,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x0c,0x00,0x51,0xe3, -0x03,0x00,0x00,0x0a,0x0d,0x00,0x51,0xe3,0x01,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x00,0x10,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x10,0x40,0x2d,0xe9,0x00,0xe0,0xa0,0xe3, -0x10,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1,0x10,0xc0,0x8d,0xe2,0x01,0x1a,0xa0,0xe3, -0x01,0x01,0xa0,0xe3,0x0e,0x20,0xa0,0xe1,0x03,0x30,0xa0,0xe3,0x04,0xe0,0x2c,0xe5, -0x00,0xc0,0x8d,0xe5,0x0a,0x5c,0x00,0xeb,0x00,0x00,0x50,0xe3,0x0a,0x00,0x00,0x1a, -0x0c,0x20,0x9d,0xe5,0x00,0x30,0x92,0xe5,0x02,0x38,0x43,0xe2,0x01,0x30,0x43,0xe2, -0x02,0x00,0x53,0xe3,0x03,0x00,0x00,0x8a,0x04,0x30,0x92,0xe5,0x30,0x10,0x9f,0xe5, -0x01,0x00,0x53,0xe1,0x02,0x00,0x00,0x0a,0x04,0x00,0xa0,0xe3,0x10,0xd0,0x8d,0xe2, -0x10,0x80,0xbd,0xe8,0x08,0x10,0x92,0xe5,0x03,0x00,0x51,0xe1,0xf9,0xff,0xff,0x1a, -0x10,0x30,0x92,0xe5,0x05,0x00,0x53,0xe3,0x00,0x20,0x84,0x05,0x04,0x00,0xa0,0x13, -0xf5,0xff,0xff,0xea,0x01,0x00,0x02,0x00,0x08,0x40,0x2d,0xe9,0x00,0xc0,0xa0,0xe1, -0x08,0x00,0x9d,0xe5,0x0e,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x13,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x18,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x20,0x00,0x00,0xea, -0x24,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x2c,0x00,0x00,0xea,0x30,0x00,0x00,0xea, -0x34,0x00,0x00,0xea,0x38,0x00,0x00,0xea,0x3c,0x00,0x00,0xea,0x40,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xe4,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xa9,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x04,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x0c,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xa2,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x04,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x9d,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x08,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x98,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x0c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x93,0x56,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x10,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x8e,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x14,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x89,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x18,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x84,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x21,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x7f,0x56,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x30,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x7a,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x34,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x75,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x38,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x70,0x56,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x3c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x6b,0x56,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x40,0x10,0x81,0xe2,0x63,0x56,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x57,0x10,0x81,0xe2,0x5b,0x56,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x00,0x9f,0xe5,0x1e,0xff,0x2f,0xe1, -0xf0,0x17,0x00,0x00,0x01,0x10,0x41,0xe2,0x1f,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90, -0x35,0x00,0x00,0xea,0x36,0x00,0x00,0xea,0x33,0x00,0x00,0xea,0x3a,0x00,0x00,0xea, -0x31,0x00,0x00,0xea,0x1a,0x00,0x00,0xea,0x19,0x00,0x00,0xea,0x2e,0x00,0x00,0xea, -0x17,0x00,0x00,0xea,0x16,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x14,0x00,0x00,0xea, -0x13,0x00,0x00,0xea,0x12,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x40,0x00,0x00,0xea, -0x25,0x00,0x00,0xea,0x24,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0x42,0x00,0x00,0xea, -0x10,0x00,0x00,0xea,0x20,0x00,0x00,0xea,0x09,0x00,0x00,0xea,0x18,0x00,0x00,0xea, -0x17,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x1a,0x00,0x00,0xea, -0x2d,0x00,0x00,0xea,0x02,0x00,0x00,0xea,0x17,0x00,0x00,0xea,0x24,0x00,0x00,0xea, -0xff,0xff,0xff,0xea,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x00,0x10,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x0a,0x80,0xe2,0x7e,0x1e,0x80,0xe2, -0x09,0x00,0x80,0xe2,0x03,0x00,0xc0,0xe3,0x0c,0x10,0x81,0xe2,0x01,0x10,0x60,0xe0, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x40,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x03,0x1c,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x01,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x03,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x40,0x10,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x82,0x1f,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x14,0x10,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0xf0,0x17,0x00,0x00,0xe6,0x07,0x00,0x00,0x70,0x40,0x2d,0xe9, -0x01,0x4a,0x80,0xe2,0x08,0xd0,0x4d,0xe2,0x04,0x50,0x84,0xe2,0x00,0xc0,0xa0,0xe1, -0x7e,0x6e,0x85,0xe2,0x18,0x00,0x9d,0xe5,0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90, -0x36,0x00,0x00,0xea,0x30,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x06,0x01,0x00,0xea, -0xfd,0x00,0x00,0xea,0xf7,0x00,0x00,0xea,0x30,0x00,0x00,0xea,0x2f,0x00,0x00,0xea, -0xef,0x00,0x00,0xea,0xe4,0x00,0x00,0xea,0xd9,0x00,0x00,0xea,0xd0,0x00,0x00,0xea, -0xc5,0x00,0x00,0xea,0xba,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0xb3,0x00,0x00,0xea, -0xac,0x00,0x00,0xea,0xa6,0x00,0x00,0xea,0xa0,0x00,0x00,0xea,0x9a,0x00,0x00,0xea, -0x94,0x00,0x00,0xea,0x8d,0x00,0x00,0xea,0x85,0x00,0x00,0xea,0x1f,0x00,0x00,0xea, -0x1e,0x00,0x00,0xea,0x70,0x00,0x00,0xea,0x68,0x00,0x00,0xea,0x60,0x00,0x00,0xea, -0x5a,0x00,0x00,0xea,0x54,0x00,0x00,0xea,0x4c,0x00,0x00,0xea,0x17,0x00,0x00,0xea, -0x42,0x00,0x00,0xea,0x3a,0x00,0x00,0xea,0x14,0x00,0x00,0xea,0x13,0x00,0x00,0xea, -0x12,0x00,0x00,0xea,0x11,0x00,0x00,0xea,0x10,0x00,0x00,0xea,0x0f,0x00,0x00,0xea, -0x0e,0x00,0x00,0xea,0x0d,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x00,0x10,0x93,0xe5, -0x44,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x01,0x13,0x8c,0xe0,0xbb,0x55,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0xd0,0x8d,0xe2,0x70,0x80,0xbd,0xe8,0x20,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xb5,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf8,0xff,0xff,0xea, -0x00,0x00,0x5c,0xe3,0xd5,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13, -0xd2,0x00,0x00,0x0a,0x00,0x00,0x50,0xe3,0xd0,0x00,0x00,0x0a,0x05,0x10,0x41,0xe2, -0x12,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0xcc,0x00,0x00,0xea,0xe0,0x00,0x00,0xea, -0x0e,0x01,0x00,0xea,0xc9,0x00,0x00,0xea,0xc8,0x00,0x00,0xea,0xc7,0x00,0x00,0xea, -0xc6,0x00,0x00,0xea,0xc5,0x00,0x00,0xea,0xc4,0x00,0x00,0xea,0xe2,0x00,0x00,0xea, -0xc2,0x00,0x00,0xea,0xc1,0x00,0x00,0xea,0xc0,0x00,0x00,0xea,0xbf,0x00,0x00,0xea, -0xbe,0x00,0x00,0xea,0xbd,0x00,0x00,0xea,0xbc,0x00,0x00,0xea,0xbb,0x00,0x00,0xea, -0xd5,0xff,0xff,0xea,0xbb,0x00,0x00,0xea,0x08,0x10,0x8d,0xe2,0x04,0x30,0xa0,0xe3, -0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5,0x90,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xd3,0xff,0xff,0xea,0x00,0x10,0x93,0xe5,0x34,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x01,0x11,0x8c,0xe0,0x89,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xcc,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x5f,0x1d,0x8c,0xe2,0x2d,0x10,0x81,0xe2,0x00,0x20,0x92,0xe5, -0x03,0x10,0x81,0xe0,0x81,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xea, -0xc0,0x33,0x9f,0xe5,0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5,0x04,0x30,0x21,0xe5, -0x7a,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xbd,0xff,0xff,0xea,0x0c,0x10,0xa0,0xe1, -0xa0,0x23,0x9f,0xe5,0x75,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xb8,0xff,0xff,0xea, -0x06,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x70,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xb3,0xff,0xff,0xea,0x80,0x33,0x9f,0xe5,0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5, -0x04,0x30,0x21,0xe5,0x69,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xac,0xff,0xff,0xea, -0x08,0x10,0x8d,0xe2,0x10,0x30,0xa0,0xe3,0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5, -0x62,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xa5,0xff,0xff,0xea,0x00,0x30,0xa0,0xe1, -0x00,0x20,0xa0,0xe3,0x10,0x10,0x9c,0xe5,0x02,0x10,0xc0,0xe7,0x04,0x20,0x82,0xe2, -0x10,0x10,0x9c,0xe5,0x10,0x00,0x52,0xe3,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc3,0xe5, -0xb2,0x11,0xdc,0xe1,0x02,0x10,0xc3,0xe5,0x13,0x10,0xdc,0xe5,0x04,0xc0,0x8c,0xe2, -0x03,0x10,0xc3,0xe5,0x04,0x30,0x83,0xe2,0xf1,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3, -0x93,0xff,0xff,0xea,0x04,0x30,0xd4,0xe5,0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5, -0x04,0x30,0x21,0xe5,0x49,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x8c,0xff,0xff,0xea, -0x09,0x10,0x84,0xe2,0x00,0x20,0x92,0xe5,0x03,0x10,0xc1,0xe3,0x43,0x55,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x86,0xff,0xff,0xea,0x02,0x10,0x85,0xe2,0x00,0x20,0x92,0xe5, -0x3e,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x81,0xff,0xff,0xea,0x28,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x39,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x7c,0xff,0xff,0xea, -0x24,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x34,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x77,0xff,0xff,0xea,0x2c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x2f,0x55,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x72,0xff,0xff,0xea,0x35,0x1d,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x08,0x10,0x81,0xe2,0x29,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x6c,0xff,0xff,0xea, -0xf5,0x1e,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x24,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x67,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0xf6,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x08,0x10,0x81,0xe2, -0x1a,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x5d,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0xf6,0x1e,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x04,0x10,0x81,0xe2,0x10,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x53,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0xc1,0x21,0xe0,0xf6,0x1e,0x81,0xe2,0x08,0x55,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x4b,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0xf5,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x0c,0x10,0x81,0xe2, -0xfe,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x41,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0xf5,0x1e,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x08,0x10,0x81,0xe2,0xf4,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x37,0xff,0xff,0xea,0x04,0x10,0x86,0xe2,0x00,0x20,0x92,0xe5,0xef,0x54,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x32,0xff,0xff,0xea,0x51,0x1f,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0xea,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x2d,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x52,0xcf,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x83,0x30,0x83,0xe0,0x03,0x14,0x8c,0xe0, -0xe2,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x25,0xff,0xff,0xea,0x30,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xdd,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x20,0xff,0xff,0xea, -0x04,0x00,0xa0,0xe3,0x1e,0xff,0xff,0xea,0x00,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe3, -0x03,0x10,0x9c,0xe7,0x03,0x10,0xc0,0xe7,0x03,0x10,0x9c,0xe7,0x21,0x14,0xa0,0xe1, -0x01,0x10,0xc2,0xe5,0x03,0x10,0x9c,0xe7,0x21,0x18,0xa0,0xe1,0x02,0x10,0xc2,0xe5, -0x03,0x10,0x9c,0xe7,0x04,0x30,0x83,0xe2,0x10,0x00,0x53,0xe3,0x21,0x1c,0xa0,0xe1, -0x03,0x10,0xc2,0xe5,0x04,0x20,0x82,0xe2,0xf0,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3, -0x0b,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0xf6,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x0c,0x10,0x81,0xe2, -0xbe,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x01,0xff,0xff,0xea,0x00,0x20,0xa0,0xe3, -0x00,0x10,0x93,0xe5,0x01,0x41,0x81,0xe0,0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0, -0x01,0x11,0x8c,0xe0,0x70,0x1f,0x91,0xe5,0x00,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x01,0x41,0x81,0xe0,0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x11,0x8c,0xe0, -0x70,0x1f,0x91,0xe5,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x01,0x41,0x81,0xe0,0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x11,0x8c,0xe0, -0x70,0x1f,0x91,0xe5,0x21,0x18,0xa0,0xe1,0x02,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x01,0x41,0x81,0xe0,0x84,0x10,0x81,0xe0,0x02,0x10,0x81,0xe0,0x01,0x20,0x82,0xe2, -0x01,0x11,0x8c,0xe0,0x04,0x00,0x52,0xe3,0x73,0x1f,0xd1,0xe5,0x03,0x10,0xc0,0xe5, -0x04,0x00,0x80,0xe2,0xdd,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3,0xdc,0xfe,0xff,0xea, -0x00,0x30,0x93,0xe5,0x2c,0x10,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0, -0xf5,0x1e,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x04,0x10,0x81,0xe2,0x8f,0x54,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xd2,0xfe,0xff,0xea,0xf0,0x17,0x00,0x00,0xe0,0x17,0x00,0x00, -0x01,0xca,0x80,0xe2,0xf0,0x41,0x2d,0xe9,0x04,0x40,0x8c,0xe2,0x18,0x50,0x9d,0xe5, -0x7e,0x6e,0x84,0xe2,0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0xcf,0x00,0x00,0xea, -0x28,0x00,0x00,0xea,0xc5,0x00,0x00,0xea,0xbe,0x00,0x00,0xea,0xb4,0x00,0x00,0xea, -0x72,0x00,0x00,0xea,0xc9,0x00,0x00,0xea,0xc8,0x00,0x00,0xea,0x69,0x00,0x00,0xea, -0x5d,0x00,0x00,0xea,0x51,0x00,0x00,0xea,0x47,0x00,0x00,0xea,0x3b,0x00,0x00,0xea, -0x2f,0x00,0x00,0xea,0xc1,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x7f,0x00,0x00,0xea, -0x78,0x00,0x00,0xea,0x71,0x00,0x00,0xea,0x6a,0x00,0x00,0xea,0x89,0x00,0x00,0xea, -0x81,0x00,0x00,0xea,0xb9,0x00,0x00,0xea,0xb8,0x00,0x00,0xea,0xb7,0x00,0x00,0xea, -0x8a,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x14,0x00,0x00,0xea,0x96,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0xb1,0x00,0x00,0xea,0xb0,0x00,0x00,0xea,0xd5,0x00,0x00,0xea, -0xcc,0x00,0x00,0xea,0xad,0x00,0x00,0xea,0xac,0x00,0x00,0xea,0xab,0x00,0x00,0xea, -0xaa,0x00,0x00,0xea,0xa9,0x00,0x00,0xea,0xa8,0x00,0x00,0xea,0xa7,0x00,0x00,0xea, -0xa6,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x20,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x55,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x08,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x4e,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0xf5,0x0e,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x48,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xf6,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x08,0x00,0x80,0xe2,0x3d,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0xf6,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x04,0x00,0x80,0xe2, -0x32,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5, -0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x20,0xe0, -0xf6,0x0e,0x80,0xe2,0x29,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0xf5,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x0c,0x00,0x80,0xe2, -0x1e,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5, -0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0, -0xf5,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x08,0x00,0x80,0xe2,0x13,0x54,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x04,0x00,0x86,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x0d,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x51,0x0f,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x07,0x54,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x28,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x01,0x54,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x24,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xfb,0x53,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x2c,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0xf5,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x35,0x0d,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x08,0x00,0x80,0xe2,0x00,0x20,0x92,0xe5, -0xee,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x09,0x00,0x8c,0xe2, -0x05,0x10,0xa0,0xe1,0x03,0x00,0xc0,0xe3,0x00,0x20,0x92,0xe5,0xe7,0x53,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x02,0x00,0x84,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0xe1,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x0c,0x00,0x80,0xe2,0x10,0x40,0x85,0xe2,0x02,0x30,0xd5,0xe5,0x03,0xc0,0xd5,0xe5, -0x00,0x10,0xd5,0xe5,0x01,0x20,0xd5,0xe5,0x04,0x50,0x85,0xe2,0x03,0x38,0xa0,0xe1, -0x04,0x00,0x55,0xe1,0x0c,0x3c,0x83,0xe1,0x01,0x30,0x83,0xe1,0x02,0x34,0x83,0xe1, -0x04,0x30,0xa0,0xe5,0xf3,0xff,0xff,0x1a,0x7a,0xff,0xff,0xea,0x06,0x00,0xa0,0xe1, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xcc,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x52,0x0f,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x83,0x30,0x83,0xe0,0x03,0x04,0x80,0xe0,0xc3,0x53,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x30,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0xbd,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x44,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x03,0x03,0x80,0xe0,0xb5,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13, -0x63,0x00,0x00,0x0a,0x00,0x00,0x55,0xe3,0x61,0x00,0x00,0x0a,0x05,0x10,0x41,0xe2, -0x12,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x5b,0x00,0x00,0xea,0x4f,0x00,0x00,0xea, -0x43,0x00,0x00,0xea,0x58,0x00,0x00,0xea,0x57,0x00,0x00,0xea,0x56,0x00,0x00,0xea, -0x55,0x00,0x00,0xea,0x54,0x00,0x00,0xea,0x53,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x51,0x00,0x00,0xea,0x50,0x00,0x00,0xea,0x4f,0x00,0x00,0xea,0x4e,0x00,0x00,0xea, -0x4d,0x00,0x00,0xea,0x4c,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0x4a,0x00,0x00,0xea, -0x49,0x00,0x00,0xea,0x10,0x00,0x00,0xea,0x00,0x30,0x93,0xe5,0x34,0x00,0x80,0xe2, -0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x01,0x80,0xe0,0x8f,0x53,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x5f,0x0d,0x80,0xe2, -0x2d,0x00,0x80,0xe2,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x00,0x80,0xe0, -0x86,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x10,0x40,0x85,0xe2, -0x02,0x10,0xd5,0xe5,0x03,0xc0,0xd5,0xe5,0x00,0x30,0xd5,0xe5,0x01,0x20,0xd5,0xe5, -0x04,0x50,0x85,0xe2,0x01,0x18,0xa0,0xe1,0x04,0x00,0x55,0xe1,0x0c,0x1c,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x34,0x83,0xe1,0x04,0x30,0x80,0xe4,0xf3,0xff,0xff,0x1a, -0x20,0xff,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5,0x02,0x60,0xd5,0xe5, -0x03,0x70,0xd5,0xe5,0x00,0xc0,0xd5,0xe5,0x01,0x81,0x81,0xe0,0x01,0x40,0xd5,0xe5, -0x06,0x68,0xa0,0xe1,0x04,0x50,0x85,0xe2,0x88,0x10,0x81,0xe0,0x07,0x6c,0x86,0xe1, -0x02,0x10,0x81,0xe0,0x0c,0xc0,0x86,0xe1,0x01,0x20,0x82,0xe2,0x01,0x11,0x80,0xe0, -0x04,0xc4,0x8c,0xe1,0x04,0x00,0x52,0xe3,0x70,0xcf,0x81,0xe5,0xed,0xff,0xff,0x1a, -0x0c,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0xf5,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x04,0x00,0x80,0xe2,0x59,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x2c,0xc0,0xa0,0xe3,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0xf6,0x3e,0x83,0xe2,0x03,0x00,0x80,0xe0,0x0c,0x00,0x80,0xe2, -0x4e,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x04,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x04,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x0c,0x00,0x51,0xe3, -0x03,0x00,0x00,0x0a,0x0d,0x00,0x51,0xe3,0x01,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x00,0x10,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x10,0x40,0x2d,0xe9,0x00,0xe0,0xa0,0xe3, -0x10,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1,0x10,0xc0,0x8d,0xe2,0x01,0x1a,0xa0,0xe3, -0x01,0x01,0xa0,0xe3,0x0e,0x20,0xa0,0xe1,0x03,0x30,0xa0,0xe3,0x04,0xe0,0x2c,0xe5, -0x00,0xc0,0x8d,0xe5,0x62,0x58,0x00,0xeb,0x00,0x00,0x50,0xe3,0x06,0x00,0x00,0x1a, -0x0c,0x20,0x9d,0xe5,0x00,0x30,0x92,0xe5,0x03,0x38,0x43,0xe2,0x01,0x30,0x43,0xe2, -0x01,0x00,0x53,0xe3,0x02,0x00,0x00,0x9a,0x04,0x00,0xa0,0xe3,0x10,0xd0,0x8d,0xe2, -0x10,0x80,0xbd,0xe8,0x04,0x30,0x92,0xe5,0x24,0x10,0x9f,0xe5,0x01,0x00,0x53,0xe1, -0xf8,0xff,0xff,0x1a,0x08,0x10,0x92,0xe5,0x03,0x00,0x51,0xe1,0xf5,0xff,0xff,0x1a, -0x10,0x30,0x92,0xe5,0x05,0x00,0x53,0xe3,0x00,0x20,0x84,0x05,0x04,0x00,0xa0,0x13, -0xf1,0xff,0xff,0xea,0x01,0x00,0x03,0x00,0x08,0x40,0x2d,0xe9,0x00,0xc0,0xa0,0xe1, -0x08,0x00,0x9d,0xe5,0x0e,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x13,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x18,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x20,0x00,0x00,0xea, -0x24,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x2c,0x00,0x00,0xea,0x30,0x00,0x00,0xea, -0x34,0x00,0x00,0xea,0x38,0x00,0x00,0xea,0x3c,0x00,0x00,0xea,0x40,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xec,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x01,0x53,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x04,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x0c,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xfa,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x04,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xf5,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x08,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xf0,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x0c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xeb,0x52,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x10,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0xe6,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x14,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xe1,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x18,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xdc,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x21,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xd7,0x52,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x30,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0xd2,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x34,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xcd,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x38,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xc8,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x3c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0xc3,0x52,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x40,0x10,0x81,0xe2,0xbb,0x52,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x57,0x10,0x81,0xe2,0xb3,0x52,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x02,0x0a,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x10,0x41,0xe2,0x27,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x4a,0x00,0x00,0xea, -0x31,0x00,0x00,0xea,0x48,0x00,0x00,0xea,0x3b,0x00,0x00,0xea,0x46,0x00,0x00,0xea, -0x22,0x00,0x00,0xea,0x21,0x00,0x00,0xea,0x43,0x00,0x00,0xea,0x1f,0x00,0x00,0xea, -0x1e,0x00,0x00,0xea,0x1d,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x1b,0x00,0x00,0xea, -0x1a,0x00,0x00,0xea,0x3c,0x00,0x00,0xea,0x3d,0x00,0x00,0xea,0x3a,0x00,0x00,0xea, -0x39,0x00,0x00,0xea,0x38,0x00,0x00,0xea,0x3f,0x00,0x00,0xea,0x44,0x00,0x00,0xea, -0x35,0x00,0x00,0xea,0x11,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0x4a,0x00,0x00,0xea, -0x31,0x00,0x00,0xea,0x30,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x0a,0x00,0x00,0xea,0x2c,0x00,0x00,0xea,0x19,0x00,0x00,0xea,0x2a,0x00,0x00,0xea, -0x29,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x26,0x00,0x00,0xea, -0x25,0x00,0x00,0xea,0x06,0x00,0x00,0xea,0x05,0x00,0x00,0xea,0x0a,0x00,0x00,0xea, -0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x00,0x10,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x40,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x40,0x10,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x01,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x02,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0xa0,0x10,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x04,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x02,0x1a,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x21,0x1e,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x54,0x10,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0x41,0x0e,0x80,0xe2,0x05,0x10,0x80,0xe2,0x2d,0xce,0x80,0xe2, -0x03,0x10,0xc1,0xe3,0x00,0x00,0xa0,0xe3,0x0c,0x10,0x61,0xe0,0x00,0x10,0x82,0xe5, -0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5,0x01,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0xd8,0x04,0x00,0x00,0xce,0x02,0x00,0x00,0x30,0x40,0x2d,0xe9, -0x41,0x4e,0x80,0xe2,0x0c,0xd0,0x4d,0xe2,0x00,0xc0,0xa0,0xe1,0xb2,0x5f,0x84,0xe2, -0x18,0x00,0x9d,0xe5,0x29,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0xfb,0x00,0x00,0xea, -0xf5,0x00,0x00,0xea,0xec,0x00,0x00,0xea,0xe6,0x00,0x00,0xea,0xdb,0x00,0x00,0xea, -0xd4,0x00,0x00,0xea,0xf5,0x00,0x00,0xea,0xf4,0x00,0x00,0xea,0xcc,0x00,0x00,0xea, -0xc1,0x00,0x00,0xea,0xb6,0x00,0x00,0xea,0xab,0x00,0x00,0xea,0xa0,0x00,0x00,0xea, -0x95,0x00,0x00,0xea,0xed,0x00,0x00,0xea,0x8d,0x00,0x00,0xea,0x87,0x00,0x00,0xea, -0x80,0x00,0x00,0xea,0x79,0x00,0x00,0xea,0x72,0x00,0x00,0xea,0x6c,0x00,0x00,0xea, -0x65,0x00,0x00,0xea,0x5d,0x00,0x00,0xea,0xe4,0x00,0x00,0xea,0xe3,0x00,0x00,0xea, -0x47,0x00,0x00,0xea,0x3f,0x00,0x00,0xea,0x37,0x00,0x00,0xea,0x31,0x00,0x00,0xea, -0x2b,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0xdc,0x00,0x00,0xea,0x19,0x00,0x00,0xea, -0x10,0x00,0x00,0xea,0xd9,0x00,0x00,0xea,0xd8,0x00,0x00,0xea,0xd7,0x00,0x00,0xea, -0xd6,0x00,0x00,0xea,0xd5,0x00,0x00,0xea,0xd4,0x00,0x00,0xea,0xd3,0x00,0x00,0xea, -0xd2,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0x08,0x10,0x8d,0xe2,0x04,0x30,0xa0,0xe3, -0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5,0x08,0x52,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x0c,0xd0,0x8d,0xe2,0x30,0x80,0xbd,0xe8,0x00,0x10,0x93,0xe5,0x71,0xce,0x8c,0xe2, -0x04,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x01,0x11,0x8c,0xe0,0xff,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf5,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x7f,0x1d,0x8c,0xe2, -0x3e,0x10,0x81,0xe2,0x00,0x20,0x92,0xe5,0x03,0x10,0x81,0xe0,0xf7,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xed,0xff,0xff,0xea,0x08,0x10,0x8d,0xe2,0x02,0x3a,0xa0,0xe3, -0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5,0xf0,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xe6,0xff,0xff,0xea,0x0c,0x10,0xa0,0xe1,0x02,0x2a,0xa0,0xe3,0xeb,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xe1,0xff,0xff,0xea,0x05,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xe6,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xdc,0xff,0xff,0xea,0xc4,0x35,0x9f,0xe5, -0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5,0x04,0x30,0x21,0xe5,0xdf,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xd5,0xff,0xff,0xea,0x08,0x10,0x8d,0xe2,0x6e,0x3e,0xa0,0xe3, -0x04,0x30,0x21,0xe5,0x00,0x20,0x92,0xe5,0xd8,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xce,0xff,0xff,0xea,0x00,0x30,0xa0,0xe1,0x00,0x20,0xa0,0xe3,0xe0,0x16,0x9c,0xe5, -0x02,0x10,0xc0,0xe7,0x04,0x20,0x82,0xe2,0xe0,0x16,0x9c,0xe5,0x10,0x00,0x52,0xe3, -0x21,0x14,0xa0,0xe1,0x01,0x10,0xc3,0xe5,0xe0,0x16,0x9c,0xe5,0x21,0x18,0xa0,0xe1, -0x02,0x10,0xc3,0xe5,0xe3,0x16,0xdc,0xe5,0x04,0xc0,0x8c,0xe2,0x03,0x10,0xc3,0xe5, -0x04,0x30,0x83,0xe2,0xf0,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3,0xbb,0xff,0xff,0xea, -0x10,0x34,0xdc,0xe5,0x08,0x10,0x8d,0xe2,0x00,0x20,0x92,0xe5,0x04,0x30,0x21,0xe5, -0xbe,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xb4,0xff,0xff,0xea,0x05,0x10,0x84,0xe2, -0x00,0x20,0x92,0xe5,0x03,0x10,0xc1,0xe3,0xb8,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xae,0xff,0xff,0xea,0x02,0x10,0x84,0xe2,0x00,0x20,0x92,0xe5,0xb3,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xa9,0xff,0xff,0xea,0x07,0x1c,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x08,0x10,0x81,0xe2,0xad,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xa3,0xff,0xff,0xea, -0x07,0x1c,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x04,0x10,0x81,0xe2,0xa7,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x9d,0xff,0xff,0xea,0x07,0x1c,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x0c,0x10,0x81,0xe2,0xa1,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x97,0xff,0xff,0xea, -0x0c,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x92,0xff,0xff,0xea,0x6e,0x1d,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x08,0x10,0x81,0xe2, -0x96,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x8c,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x20,0x10,0x81,0xe2,0x8c,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x82,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x1c,0x10,0x81,0xe2, -0x82,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x78,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x18,0x10,0x81,0xe2,0x78,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x6e,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5, -0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x14,0x10,0x81,0xe2, -0x6e,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x64,0xff,0xff,0xea,0x00,0x30,0x93,0xe5, -0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2, -0x01,0x10,0x8c,0xe0,0x10,0x10,0x81,0xe2,0x64,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x5a,0xff,0xff,0xea,0x04,0x10,0x85,0xe2,0x00,0x20,0x92,0xe5,0x5f,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x55,0xff,0xff,0xea,0x82,0x1e,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x04,0x10,0x81,0xe2,0x59,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x4f,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x82,0xce,0x8c,0xe2,0x08,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x03,0x31,0x83,0xe0,0x83,0x32,0x63,0xe0,0x83,0x11,0x8c,0xe0,0x4f,0x51,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x45,0xff,0xff,0xea,0x71,0x1e,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x4a,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x40,0xff,0xff,0xea,0x00,0x10,0x93,0xe5, -0x72,0xce,0x8c,0xe2,0x04,0xc0,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x01,0x13,0x8c,0xe0, -0x42,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x38,0xff,0xff,0xea,0x07,0x1c,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x3d,0x51,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x33,0xff,0xff,0xea, -0x00,0x00,0x5c,0xe3,0x2c,0x00,0x00,0x0a,0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13, -0x29,0x00,0x00,0x0a,0x00,0x00,0x50,0xe3,0x27,0x00,0x00,0x0a,0x05,0x10,0x41,0xe2, -0x23,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x23,0x00,0x00,0xea,0xb3,0x00,0x00,0xea, -0xa8,0x00,0x00,0xea,0x20,0x00,0x00,0xea,0x1f,0x00,0x00,0xea,0x1e,0x00,0x00,0xea, -0x1d,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x79,0x00,0x00,0xea, -0x19,0x00,0x00,0xea,0x18,0x00,0x00,0xea,0x17,0x00,0x00,0xea,0x16,0x00,0x00,0xea, -0x15,0x00,0x00,0xea,0x14,0x00,0x00,0xea,0x13,0x00,0x00,0xea,0x12,0x00,0x00,0xea, -0x68,0x00,0x00,0xea,0x54,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea, -0x0d,0x00,0x00,0xea,0x0c,0x00,0x00,0xea,0x0b,0x00,0x00,0xea,0x0a,0x00,0x00,0xea, -0x09,0x00,0x00,0xea,0x08,0x00,0x00,0xea,0x07,0x00,0x00,0xea,0x06,0x00,0x00,0xea, -0x05,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea, -0x3e,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x01,0x00,0x00,0xea,0x04,0x00,0xa0,0xe3, -0x02,0xff,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5,0x81,0x41,0x81,0xe0, -0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2,0x01,0x11,0x8c,0xe0, -0x28,0x10,0x91,0xe5,0x00,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5,0x81,0x41,0x81,0xe0, -0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2,0x01,0x11,0x8c,0xe0, -0x28,0x10,0x91,0xe5,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2, -0x01,0x11,0x8c,0xe0,0xba,0x12,0xd1,0xe1,0x02,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x01,0x20,0x82,0xe2, -0x6e,0x1e,0x81,0xe2,0x40,0x00,0x52,0xe3,0x01,0x11,0x8c,0xe0,0x2b,0x10,0xd1,0xe5, -0x03,0x10,0xc0,0xe5,0x04,0x00,0x80,0xe2,0xda,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3, -0xda,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe1,0x00,0x20,0xa0,0xe3,0x10,0x13,0x9c,0xe5, -0x02,0x10,0xc0,0xe7,0x04,0x20,0x82,0xe2,0x10,0x13,0x9c,0xe5,0x01,0x0c,0x52,0xe3, -0x21,0x14,0xa0,0xe1,0x01,0x10,0xc3,0xe5,0x10,0x13,0x9c,0xe5,0x21,0x18,0xa0,0xe1, -0x02,0x10,0xc3,0xe5,0x13,0x13,0xdc,0xe5,0x04,0xc0,0x8c,0xe2,0x03,0x10,0xc3,0xe5, -0x04,0x30,0x83,0xe2,0xf0,0xff,0xff,0x1a,0x00,0x00,0xa0,0xe3,0xc7,0xfe,0xff,0xea, -0x00,0x10,0x93,0xe5,0x21,0xce,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x01,0x11,0x8c,0xe0, -0xca,0x50,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xc0,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe1, -0x00,0x20,0xa0,0xe3,0x10,0x13,0x9c,0xe5,0x02,0x10,0xc0,0xe7,0x04,0x20,0x82,0xe2, -0x10,0x13,0x9c,0xe5,0x10,0x00,0x52,0xe3,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc3,0xe5, -0x10,0x13,0x9c,0xe5,0x21,0x18,0xa0,0xe1,0x02,0x10,0xc3,0xe5,0x13,0x13,0xdc,0xe5, -0x04,0xc0,0x8c,0xe2,0x03,0x10,0xc3,0xe5,0x04,0x30,0x83,0xe2,0xf0,0xff,0xff,0x1a, -0x00,0x00,0xa0,0xe3,0xad,0xfe,0xff,0xea,0x00,0x10,0x93,0xe5,0x72,0x3e,0x8c,0xe2, -0x04,0x30,0x83,0xe2,0x00,0x20,0x92,0xe5,0x01,0x13,0x83,0xe0,0xaf,0x50,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xa5,0xfe,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5, -0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2, -0x01,0x11,0x8c,0xe0,0x28,0x10,0x91,0xe5,0x00,0x10,0xc0,0xe5,0x00,0x10,0x93,0xe5, -0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2, -0x01,0x11,0x8c,0xe0,0x28,0x10,0x91,0xe5,0x21,0x14,0xa0,0xe1,0x01,0x10,0xc0,0xe5, -0x00,0x10,0x93,0xe5,0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0, -0x6e,0x1e,0x81,0xe2,0x01,0x11,0x8c,0xe0,0xba,0x12,0xd1,0xe1,0x02,0x10,0xc0,0xe5, -0x00,0x10,0x93,0xe5,0x81,0x41,0x81,0xe0,0x84,0x11,0x61,0xe0,0x02,0x10,0x81,0xe0, -0x01,0x20,0x82,0xe2,0x6e,0x1e,0x81,0xe2,0x04,0x00,0x52,0xe3,0x01,0x11,0x8c,0xe0, -0x2b,0x10,0xd1,0xe5,0x03,0x10,0xc0,0xe5,0x04,0x00,0x80,0xe2,0xda,0xff,0xff,0x1a, -0x00,0x00,0xa0,0xe3,0x7d,0xfe,0xff,0xea,0x00,0x30,0x93,0xe5,0x47,0x1f,0xa0,0xe3, -0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0,0x6e,0x1d,0x81,0xe2,0x01,0x10,0x8c,0xe0, -0x0c,0x10,0x81,0xe2,0x7d,0x50,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x73,0xfe,0xff,0xea, -0x00,0x30,0x93,0xe5,0x47,0x1f,0xa0,0xe3,0x00,0x20,0x92,0xe5,0x93,0x01,0x01,0xe0, -0x6e,0x1d,0x81,0xe2,0x01,0x10,0x8c,0xe0,0x24,0x10,0x81,0xe2,0x73,0x50,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x69,0xfe,0xff,0xea,0x20,0x19,0x00,0x00,0xf0,0x41,0x2d,0xe9, -0x41,0xce,0x80,0xe2,0x18,0x40,0x9d,0xe5,0xb2,0x5f,0x8c,0xe2,0x29,0x00,0x51,0xe3, -0x01,0xf1,0x8f,0x90,0x37,0x00,0x00,0xea,0x02,0x01,0x00,0xea,0xf8,0x00,0x00,0xea, -0xf1,0x00,0x00,0xea,0xe5,0x00,0x00,0xea,0xe2,0x00,0x00,0xea,0x31,0x00,0x00,0xea, -0x30,0x00,0x00,0xea,0x9e,0x00,0x00,0xea,0x92,0x00,0x00,0xea,0x86,0x00,0x00,0xea, -0x7a,0x00,0x00,0xea,0x6e,0x00,0x00,0xea,0x62,0x00,0x00,0xea,0x29,0x00,0x00,0xea, -0x1a,0x00,0x00,0xea,0x20,0x00,0x00,0xea,0xa9,0x00,0x00,0xea,0xa2,0x00,0x00,0xea, -0x9f,0x00,0x00,0xea,0x98,0x00,0x00,0xea,0xbc,0x00,0x00,0xea,0x21,0x00,0x00,0xea, -0x20,0x00,0x00,0xea,0x1f,0x00,0x00,0xea,0xa8,0x00,0x00,0xea,0x1b,0x00,0x00,0xea, -0x1a,0x00,0x00,0xea,0xbc,0x00,0x00,0xea,0x13,0x00,0x00,0xea,0x19,0x00,0x00,0xea, -0x18,0x00,0x00,0xea,0xbe,0x00,0x00,0xea,0x45,0x00,0x00,0xea,0x15,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x13,0x00,0x00,0xea,0x12,0x00,0x00,0xea,0x11,0x00,0x00,0xea, -0x10,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea,0x04,0x00,0x00,0xea, -0x6e,0x0d,0x80,0xe2,0x04,0x10,0xa0,0xe1,0x08,0x00,0x80,0xe2,0x00,0x20,0x92,0xe5, -0x3a,0x50,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x04,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x35,0x50,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x08,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x00,0x50,0xe3,0x3c,0x01,0x00,0x0a, -0x00,0x00,0x52,0xe3,0x00,0x00,0x53,0x13,0x39,0x01,0x00,0x0a,0x00,0x00,0x54,0xe3, -0x37,0x01,0x00,0x0a,0x05,0x10,0x41,0xe2,0x23,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90, -0x31,0x01,0x00,0xea,0x26,0x01,0x00,0xea,0x1a,0x01,0x00,0xea,0x2e,0x01,0x00,0xea, -0x2d,0x01,0x00,0xea,0x2c,0x01,0x00,0xea,0x2b,0x01,0x00,0xea,0x2a,0x01,0x00,0xea, -0x29,0x01,0x00,0xea,0xfe,0x00,0x00,0xea,0x27,0x01,0x00,0xea,0x26,0x01,0x00,0xea, -0x25,0x01,0x00,0xea,0x24,0x01,0x00,0xea,0x23,0x01,0x00,0xea,0x22,0x01,0x00,0xea, -0x21,0x01,0x00,0xea,0x20,0x01,0x00,0xea,0x1f,0x01,0x00,0xea,0xe5,0x00,0x00,0xea, -0x1d,0x01,0x00,0xea,0x1c,0x01,0x00,0xea,0x1b,0x01,0x00,0xea,0x1a,0x01,0x00,0xea, -0x19,0x01,0x00,0xea,0x18,0x01,0x00,0xea,0x17,0x01,0x00,0xea,0x16,0x01,0x00,0xea, -0x15,0x01,0x00,0xea,0x14,0x01,0x00,0xea,0x13,0x01,0x00,0xea,0x12,0x01,0x00,0xea, -0x11,0x01,0x00,0xea,0x10,0x01,0x00,0xea,0xc7,0x00,0x00,0xea,0xb7,0x00,0x00,0xea, -0xa1,0x00,0x00,0xea,0x00,0x30,0x93,0xe5,0x71,0x0e,0x80,0xe2,0x04,0x00,0x80,0xe2, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x01,0x80,0xe0,0xfb,0x4f,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2, -0x03,0x00,0x80,0xe0,0x20,0x00,0x80,0xe2,0xf0,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3,0x04,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x1c,0x00,0x80,0xe2,0xe5,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3,0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2,0x03,0x00,0x80,0xe0,0x18,0x00,0x80,0xe2, -0xda,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5, -0x47,0xcf,0xa0,0xe3,0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0, -0x6e,0x3d,0x83,0xe2,0x03,0x00,0x80,0xe0,0x14,0x00,0x80,0xe2,0xcf,0x4f,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2, -0x03,0x00,0x80,0xe0,0x10,0x00,0x80,0xe2,0xc4,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x04,0x00,0x85,0xe2,0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xbe,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x02,0x00,0x8c,0xe2, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0xb8,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x07,0x0c,0x80,0xe2,0x75,0xff,0xff,0xea,0x07,0x0c,0x80,0xe2, -0x04,0x10,0xa0,0xe1,0x04,0x00,0x80,0xe2,0x00,0x20,0x92,0xe5,0xaf,0x4f,0x00,0xeb, -0x73,0xff,0xff,0xea,0x07,0x0c,0x80,0xe2,0x04,0x10,0xa0,0xe1,0x0c,0x00,0x80,0xe2, -0x00,0x20,0x92,0xe5,0xa9,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x6d,0x0e,0x80,0xe2,0x10,0x50,0x84,0xe2,0x0c,0x00,0x80,0xe2,0x02,0x30,0xd4,0xe5, -0x03,0xc0,0xd4,0xe5,0x00,0x10,0xd4,0xe5,0x01,0x20,0xd4,0xe5,0x04,0x40,0x84,0xe2, -0x03,0x38,0xa0,0xe1,0x05,0x00,0x54,0xe1,0x0c,0x3c,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x34,0x83,0xe1,0x04,0x30,0xa0,0xe5,0xf3,0xff,0xff,0x1a,0x5c,0xff,0xff,0xea, -0x05,0x00,0x8c,0xe2,0x04,0x10,0xa0,0xe1,0x03,0x00,0xc0,0xe3,0x00,0x20,0x92,0xe5, -0x92,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x05,0x00,0xa0,0xe1, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x8c,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x7f,0x0d,0x80,0xe2,0x3e,0x00,0x80,0xe2, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x00,0x80,0xe0,0x83,0x4f,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x82,0x0e,0x80,0xe2,0xcb,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x82,0x0e,0x80,0xe2,0x08,0x00,0x80,0xe2,0x04,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x03,0x31,0x83,0xe0,0x83,0x32,0x63,0xe0,0x83,0x01,0x80,0xe0, -0x76,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x71,0x0e,0x80,0xe2, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x70,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x72,0x0e,0x80,0xe2,0x04,0x00,0x80,0xe2, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x03,0x03,0x80,0xe0,0x67,0x4f,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x07,0x0c,0x80,0xe2,0x04,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x61,0x4f,0x00,0xeb,0x25,0xff,0xff,0xea,0x00,0x20,0xa0,0xe3, -0x00,0x10,0x93,0xe5,0x02,0xc0,0xd4,0xe5,0x03,0x70,0xd4,0xe5,0x00,0x60,0xd4,0xe5, -0x81,0x81,0x81,0xe0,0x01,0x50,0xd4,0xe5,0x0c,0xc8,0xa0,0xe1,0x04,0x40,0x84,0xe2, -0x88,0x11,0x61,0xe0,0x07,0xcc,0x8c,0xe1,0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2, -0x06,0xc0,0x8c,0xe1,0x01,0x20,0x82,0xe2,0x01,0x11,0x80,0xe0,0x05,0xc4,0x8c,0xe1, -0x40,0x00,0x52,0xe3,0x28,0xc0,0x81,0xe5,0xec,0xff,0xff,0x1a,0x10,0xff,0xff,0xea, -0xc3,0x0f,0x80,0xe2,0x01,0x5c,0x84,0xe2,0x02,0x30,0xd4,0xe5,0x03,0xc0,0xd4,0xe5, -0x00,0x10,0xd4,0xe5,0x01,0x20,0xd4,0xe5,0x04,0x40,0x84,0xe2,0x03,0x38,0xa0,0xe1, -0x05,0x00,0x54,0xe1,0x0c,0x3c,0x83,0xe1,0x01,0x30,0x83,0xe1,0x02,0x34,0x83,0xe1, -0x04,0x30,0xa0,0xe5,0xf3,0xff,0xff,0x1a,0x01,0xff,0xff,0xea,0x83,0x0f,0x80,0xe2, -0x01,0x5c,0x84,0xe2,0x02,0x30,0xd4,0xe5,0x03,0xc0,0xd4,0xe5,0x00,0x10,0xd4,0xe5, -0x01,0x20,0xd4,0xe5,0x04,0x40,0x84,0xe2,0x03,0x38,0xa0,0xe1,0x05,0x00,0x54,0xe1, -0x0c,0x3c,0x83,0xe1,0x01,0x30,0x83,0xe1,0x02,0x34,0x83,0xe1,0x04,0x30,0xa0,0xe5, -0xf3,0xff,0xff,0x1a,0xf2,0xfe,0xff,0xea,0xc3,0x0f,0x80,0xe2,0x10,0x50,0x84,0xe2, -0x02,0x10,0xd4,0xe5,0x03,0xc0,0xd4,0xe5,0x00,0x30,0xd4,0xe5,0x01,0x20,0xd4,0xe5, -0x04,0x40,0x84,0xe2,0x01,0x18,0xa0,0xe1,0x05,0x00,0x54,0xe1,0x0c,0x1c,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x34,0x83,0xe1,0x04,0x30,0xa0,0xe5,0xf3,0xff,0xff,0x1a, -0xe3,0xfe,0xff,0xea,0x00,0x20,0xa0,0xe3,0x00,0x10,0x93,0xe5,0x02,0x60,0xd4,0xe5, -0x03,0x70,0xd4,0xe5,0x00,0xc0,0xd4,0xe5,0x81,0x81,0x81,0xe0,0x01,0x50,0xd4,0xe5, -0x06,0x68,0xa0,0xe1,0x04,0x40,0x84,0xe2,0x88,0x11,0x61,0xe0,0x07,0x6c,0x86,0xe1, -0x02,0x10,0x81,0xe0,0x6e,0x1e,0x81,0xe2,0x0c,0xc0,0x86,0xe1,0x01,0x20,0x82,0xe2, -0x01,0x11,0x80,0xe0,0x05,0xc4,0x8c,0xe1,0x04,0x00,0x52,0xe3,0x28,0xc0,0x81,0xe5, -0xec,0xff,0xff,0x1a,0xce,0xfe,0xff,0xea,0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3, -0x04,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2, -0x03,0x00,0x80,0xe0,0x0c,0x00,0x80,0xe2,0x00,0x4f,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x47,0xcf,0xa0,0xe3,0x04,0x10,0xa0,0xe1, -0x00,0x20,0x92,0xe5,0x9c,0x03,0x03,0xe0,0x6e,0x3d,0x83,0xe2,0x03,0x00,0x80,0xe0, -0x24,0x00,0x80,0xe2,0xf5,0x4e,0x00,0xeb,0xb9,0xfe,0xff,0xea,0x04,0x00,0xa0,0xe3, -0xf0,0x81,0xbd,0xe8,0x04,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8,0x0c,0x00,0x51,0xe3, -0x03,0x00,0x00,0x0a,0x0d,0x00,0x51,0xe3,0x01,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x04,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0x82,0xe5, -0x00,0x10,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x10,0x40,0x2d,0xe9,0x00,0xe0,0xa0,0xe3, -0x10,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1,0x10,0xc0,0x8d,0xe2,0x01,0x1a,0xa0,0xe3, -0x01,0x01,0xa0,0xe3,0x0e,0x20,0xa0,0xe1,0x03,0x30,0xa0,0xe3,0x04,0xe0,0x2c,0xe5, -0x00,0xc0,0x8d,0xe5,0x0a,0x54,0x00,0xeb,0x00,0x00,0x50,0xe3,0x06,0x00,0x00,0x1a, -0x0c,0x20,0x9d,0xe5,0x00,0x30,0x92,0xe5,0x35,0x38,0x43,0xe2,0x01,0x30,0x43,0xe2, -0x01,0x00,0x53,0xe3,0x02,0x00,0x00,0x9a,0x04,0x00,0xa0,0xe3,0x10,0xd0,0x8d,0xe2, -0x10,0x80,0xbd,0xe8,0x04,0x30,0x92,0xe5,0x24,0x10,0x9f,0xe5,0x01,0x00,0x53,0xe1, -0xf8,0xff,0xff,0x1a,0x08,0x10,0x92,0xe5,0x03,0x00,0x51,0xe1,0xf5,0xff,0xff,0x1a, -0x10,0x30,0x92,0xe5,0x05,0x00,0x53,0xe3,0x00,0x20,0x84,0x05,0x04,0x00,0xa0,0x13, -0xf1,0xff,0xff,0xea,0x01,0x00,0x35,0x00,0x08,0x40,0x2d,0xe9,0x00,0xc0,0xa0,0xe1, -0x08,0x00,0x9d,0xe5,0x0e,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0x13,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x18,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x20,0x00,0x00,0xea, -0x24,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x2c,0x00,0x00,0xea,0x30,0x00,0x00,0xea, -0x34,0x00,0x00,0xea,0x38,0x00,0x00,0xea,0x3c,0x00,0x00,0xea,0x40,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xec,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0xa9,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x04,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x0c,0x10,0xa0,0xe1,0x00,0x20,0x92,0xe5, -0xa2,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x04,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x9d,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x08,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x98,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x0c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x93,0x4e,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x10,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x8e,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x14,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x89,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x28,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x84,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x32,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x7f,0x4e,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x40,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5, -0x7a,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x44,0x10,0x8c,0xe2, -0x00,0x20,0x92,0xe5,0x75,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x48,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x70,0x4e,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x80,0xbd,0xe8,0x4c,0x10,0x8c,0xe2,0x00,0x20,0x92,0xe5,0x6b,0x4e,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x50,0x10,0x81,0xe2,0x63,0x4e,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x00,0x30,0x93,0xe5,0x00,0x20,0x92,0xe5, -0x83,0x30,0x83,0xe0,0x83,0x11,0x8c,0xe0,0x67,0x10,0x81,0xe2,0x5b,0x4e,0x00,0xeb, -0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8,0x01,0x10,0x41,0xe2,0xf0,0x4f,0x2d,0xe9, -0x02,0x40,0xa0,0xe1,0x8c,0xd0,0x4d,0xe2,0xec,0x50,0x80,0xe2,0x23,0x00,0x51,0xe3, -0x01,0xf1,0x8f,0x90,0xc7,0x03,0x00,0xea,0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea, -0x29,0x00,0x00,0xea,0x1f,0x00,0x00,0xea,0x83,0x01,0x00,0xea,0x1e,0x01,0x00,0xea, -0x1c,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x1a,0x00,0x00,0xea,0x8d,0x01,0x00,0xea, -0x25,0x00,0x00,0xea,0x17,0x00,0x00,0xea,0xba,0x03,0x00,0xea,0x15,0x00,0x00,0xea, -0x4a,0x02,0x00,0xea,0x13,0x00,0x00,0xea,0xa4,0x02,0x00,0xea,0x32,0x00,0x00,0xea, -0x9f,0x01,0x00,0xea,0xd0,0x01,0x00,0xea,0xb2,0x03,0x00,0xea,0xb1,0x03,0x00,0xea, -0xb0,0x03,0x00,0xea,0x30,0x02,0x00,0xea,0xae,0x03,0x00,0xea,0xad,0x03,0x00,0xea, -0x08,0x00,0x00,0xea,0x07,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x12,0x00,0x00,0xea, -0x11,0x00,0x00,0xea,0x10,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x0a,0x00,0x00,0xea, -0x00,0x00,0x00,0xea,0xf0,0x00,0x00,0xea,0x02,0x60,0xd3,0xe5,0x01,0xc0,0xd3,0xe5, -0x00,0x10,0xd3,0xe5,0x03,0x20,0xd3,0xe5,0x06,0x38,0xa0,0xe1,0x0c,0x34,0x83,0xe1, -0x01,0x30,0x83,0xe1,0x02,0x3c,0x83,0xe1,0xec,0x30,0x80,0xe5,0x01,0x00,0xa0,0xe3, -0x00,0x50,0x84,0xe5,0x8c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x02,0x10,0xd3,0xe5, -0x04,0x20,0x83,0xe2,0x01,0x70,0xd3,0xe5,0x03,0xc0,0xd3,0xe5,0x00,0x60,0xd3,0xe5, -0x01,0x18,0xa0,0xe1,0x07,0x14,0x81,0xe1,0x06,0x10,0x81,0xe1,0x0c,0x1c,0x81,0xe1, -0xec,0x10,0x80,0xe5,0x02,0xc0,0xd2,0xe5,0x01,0x00,0xd2,0xe5,0x04,0x10,0xd3,0xe5, -0x03,0x20,0xd2,0xe5,0x0c,0x38,0xa0,0xe1,0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x3c,0x83,0xe1,0x04,0x30,0x85,0xe5,0xe7,0xff,0xff,0xea,0x02,0x70,0xd3,0xe5, -0x00,0x20,0xa0,0xe3,0x01,0xa0,0xd3,0xe5,0x00,0x10,0xa0,0xe3,0x01,0x80,0xa0,0xe1, -0x02,0x90,0xa0,0xe1,0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x04,0x60,0x83,0xe2, -0x07,0x78,0xa0,0xe1,0x00,0xc0,0xd3,0xe5,0x50,0x80,0x8d,0xe5,0x54,0x90,0x8d,0xe5, -0x01,0x90,0xa0,0xe1,0x03,0x80,0xd3,0xe5,0x0a,0x74,0x87,0xe1,0x02,0xa0,0xa0,0xe1, -0x68,0x10,0x8d,0xe5,0x6c,0x20,0x8d,0xe5,0x0c,0x70,0x87,0xe1,0x18,0x90,0x8d,0xe5, -0x1c,0xa0,0x8d,0xe5,0x02,0xb0,0xa0,0xe1,0x01,0xa0,0xa0,0xe1,0x08,0x7c,0x87,0xe1, -0x28,0xa0,0x8d,0xe5,0x2c,0xb0,0x8d,0xe5,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x02,0x90,0xa0,0xe1,0x08,0x10,0x8d,0xe5,0x0c,0x20,0x8d,0xe5,0x02,0xb0,0xa0,0xe1, -0xec,0x70,0x80,0xe5,0x0c,0xc0,0x83,0xe2,0x01,0x70,0xd6,0xe5,0x00,0x80,0xa0,0xe3, -0x58,0x70,0x8d,0xe5,0x5c,0x80,0x8d,0xe5,0x01,0x80,0xa0,0xe1,0x20,0x80,0x8d,0xe5, -0x24,0x90,0x8d,0xe5,0x02,0x90,0xd6,0xe5,0x00,0xa0,0xa0,0xe3,0x60,0x90,0x8d,0xe5, -0x64,0xa0,0x8d,0xe5,0x01,0xa0,0xa0,0xe1,0x30,0xa0,0x8d,0xe5,0x34,0xb0,0x8d,0xe5, -0x02,0x90,0xa0,0xe1,0x03,0x00,0xd6,0xe5,0x00,0x10,0xa0,0xe3,0x78,0x00,0x8d,0xe5, -0x7c,0x10,0x8d,0xe5,0x08,0x10,0xa0,0xe1,0x40,0x10,0x8d,0xe5,0x44,0x20,0x8d,0xe5, -0x05,0x70,0xd6,0xe5,0x00,0x80,0xa0,0xe3,0x80,0x70,0x8d,0xe5,0x84,0x80,0x8d,0xe5, -0x0a,0x80,0xa0,0xe1,0x48,0x80,0x8d,0xe5,0x4c,0x90,0x8d,0xe5,0x04,0x90,0xd3,0xe5, -0x00,0xa0,0xa0,0xe3,0x78,0x70,0x9d,0xe5,0x70,0x90,0x8d,0xe5,0x74,0xa0,0x8d,0xe5, -0x58,0xa0,0x9d,0xe5,0x07,0x7c,0xa0,0xe1,0x0a,0xa4,0xa0,0xe1,0x38,0xa0,0x8d,0xe5, -0x06,0x00,0xd6,0xe5,0x00,0x10,0xa0,0xe3,0x60,0x10,0x9d,0xe5,0x00,0x08,0xa0,0xe1, -0x01,0x18,0xa0,0xe1,0x50,0x10,0x8d,0xe5,0x00,0x10,0xa0,0xe3,0x04,0x20,0xd6,0xe5, -0x68,0x70,0x8d,0xe5,0x07,0x80,0xd6,0xe5,0x00,0x90,0xa0,0xe3,0x50,0x70,0x8d,0xe2, -0xc0,0x00,0x97,0xe8,0x10,0x10,0x8d,0xe5,0x60,0x80,0x8d,0xe5,0x64,0x90,0x8d,0xe5, -0x38,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x18,0x10,0x8d,0xe5,0x1c,0x00,0x8d,0xe5, -0x07,0xa0,0x8a,0xe1,0x70,0x80,0x8d,0xe2,0x80,0x01,0x98,0xe8,0x06,0x90,0x89,0xe1, -0x28,0x10,0x8d,0xe5,0x0c,0x10,0x8d,0xe5,0x08,0xa0,0x8a,0xe1,0x80,0x80,0x9d,0xe5, -0x07,0x90,0x89,0xe1,0x68,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x08,0x84,0xa0,0xe1, -0x06,0x90,0x89,0xe1,0x07,0xa0,0x8a,0xe1,0x14,0x80,0x8d,0xe5,0x01,0x90,0x89,0xe1, -0x60,0x80,0x9d,0xe5,0x02,0xa0,0x8a,0xe1,0x10,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8, -0x08,0x8c,0xa0,0xe1,0x06,0x90,0x89,0xe1,0x07,0xa0,0x8a,0xe1,0x18,0x70,0x8d,0xe2, -0xc0,0x00,0x97,0xe8,0x2c,0x80,0x8d,0xe5,0x06,0x90,0x89,0xe1,0x07,0xa0,0x8a,0xe1, -0x28,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x06,0x90,0x89,0xe1,0x07,0xa0,0x8a,0xe1, -0x08,0x90,0x85,0xe5,0x0c,0xa0,0x85,0xe5,0x01,0x80,0xdc,0xe5,0x00,0x90,0xa0,0xe3, -0x10,0x80,0x8d,0xe5,0x14,0x90,0x8d,0xe5,0x02,0x60,0xdc,0xe5,0x00,0x70,0xa0,0xe3, -0x18,0x60,0x8d,0xe5,0x1c,0x70,0x8d,0xe5,0x03,0x80,0xdc,0xe5,0x00,0x90,0xa0,0xe3, -0x38,0x80,0x8d,0xe5,0x3c,0x90,0x8d,0xe5,0x05,0x60,0xdc,0xe5,0x00,0x70,0xa0,0xe3, -0x50,0x60,0x8d,0xe5,0x54,0x70,0x8d,0xe5,0x0c,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3, -0x28,0x60,0x8d,0xe5,0x2c,0x70,0x8d,0xe5,0x10,0x70,0x9d,0xe5,0x07,0xa4,0xa0,0xe1, -0x06,0x60,0xdc,0xe5,0x00,0x70,0xa0,0xe3,0x10,0x60,0x8d,0xe5,0x14,0x70,0x8d,0xe5, -0x18,0x70,0x9d,0xe5,0x07,0x78,0xa0,0xe1,0x08,0x70,0x8d,0xe5,0x04,0x00,0xdc,0xe5, -0x38,0x30,0x9d,0xe5,0x24,0x00,0x8d,0xe5,0x07,0x60,0xdc,0xe5,0x00,0x70,0xa0,0xe3, -0x03,0x8c,0xa0,0xe1,0x20,0x10,0x8d,0xe5,0x30,0x10,0x8d,0xe5,0x18,0x60,0x8d,0xe5, -0x1c,0x70,0x8d,0xe5,0x08,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x40,0x10,0x8d,0xe5, -0x48,0x10,0x8d,0xe5,0x07,0xb0,0x81,0xe1,0x06,0xa0,0x8a,0xe1,0x28,0x70,0x8d,0xe2, -0xc0,0x00,0x97,0xe8,0x06,0xa0,0x8a,0xe1,0x07,0xb0,0x8b,0xe1,0x08,0xa0,0x8a,0xe1, -0x10,0x80,0x9d,0xe5,0x50,0x70,0x9d,0xe5,0x01,0xb0,0x8b,0xe1,0x08,0x88,0xa0,0xe1, -0x07,0x74,0xa0,0xe1,0x44,0x80,0x8d,0xe5,0x18,0x80,0x9d,0xe5,0x34,0x70,0x8d,0xe5, -0x20,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x08,0x8c,0xa0,0xe1,0x06,0xa0,0x8a,0xe1, -0x07,0xb0,0x8b,0xe1,0x30,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x4c,0x80,0x8d,0xe5, -0x40,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x07,0xb0,0x8b,0xe1,0x01,0x70,0xa0,0xe1, -0x06,0xa0,0x8a,0xe1,0x09,0xb0,0x8b,0xe1,0x01,0x90,0xa0,0xe1,0x48,0x10,0x8d,0xe2, -0x03,0x00,0x91,0xe8,0x08,0xa0,0x8a,0xe1,0x00,0x20,0x8a,0xe1,0x01,0x30,0x8b,0xe1, -0x10,0x20,0x85,0xe5,0x14,0x30,0x85,0xe5,0x17,0xff,0xff,0xea,0x05,0x00,0xa0,0xe1, -0x03,0x10,0xa0,0xe1,0x20,0x20,0xa0,0xe3,0x04,0x30,0x8d,0xe5,0x37,0x4d,0x00,0xeb, -0x04,0x30,0x9d,0xe5,0x20,0x00,0x85,0xe2,0x20,0x20,0xa0,0xe3,0x20,0x60,0x83,0xe2, -0x06,0x10,0xa0,0xe1,0x31,0x4d,0x00,0xeb,0x40,0x00,0x85,0xe2,0x20,0x10,0x86,0xe2, -0x20,0x20,0xa0,0xe3,0x2d,0x4d,0x00,0xeb,0x07,0xff,0xff,0xea,0x02,0x10,0xd3,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x90,0xa0,0xe3,0x01,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3, -0x00,0x80,0xa0,0xe3,0x09,0x70,0x89,0xe1,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x03,0x10,0xd3,0xe5,0x00,0x20,0xa0,0xe3,0x28,0x10,0x8d,0xe5,0x2c,0x20,0x8d,0xe5, -0x05,0x10,0xd3,0xe5,0x00,0x20,0xa0,0xe3,0x28,0xc0,0x9d,0xe5,0x20,0x10,0x8d,0xe5, -0x24,0x20,0x8d,0xe5,0x08,0x10,0xa0,0xe1,0x09,0x20,0xa0,0xe1,0x0a,0x84,0xa0,0xe1, -0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x0c,0xcc,0xa0,0xe1,0x00,0x10,0xd3,0xe5, -0x00,0x20,0xa0,0xe3,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5,0x00,0x10,0xa0,0xe3, -0x06,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3,0x30,0xa0,0x8d,0xe5,0x34,0xb0,0x8d,0xe5, -0x10,0xb0,0x9d,0xe5,0x04,0x20,0xd3,0xe5,0x38,0xc0,0x8d,0xe5,0x30,0xc0,0x9d,0xe5, -0x0b,0x68,0xa0,0xe1,0x07,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3,0x28,0x10,0x8d,0xe5, -0x08,0x60,0x86,0xe1,0x08,0x10,0x8d,0xe5,0x10,0xa0,0x8d,0xe5,0x14,0xb0,0x8d,0xe5, -0x18,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x0b,0x90,0x87,0xe1,0x20,0xb0,0x9d,0xe5, -0x0a,0x80,0x86,0xe1,0x0c,0x78,0xa0,0xe1,0x0b,0xb4,0xa0,0xe1,0x2c,0xb0,0x8d,0xe5, -0x38,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x09,0xb0,0x8b,0xe1,0x10,0x90,0x9d,0xe5, -0x08,0xa0,0x8a,0xe1,0x18,0xa0,0x8d,0xe5,0x1c,0xb0,0x8d,0xe5,0x01,0xa0,0xa0,0xe1, -0x18,0xc0,0x8d,0xe2,0x00,0x18,0x9c,0xe8,0x09,0x9c,0xa0,0xe1,0x0c,0x90,0x8d,0xe5, -0x01,0xb0,0x8b,0xe1,0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x02,0xc0,0x8c,0xe1, -0x0c,0x20,0x83,0xe2,0x0b,0x80,0x88,0xe1,0x0c,0x90,0x89,0xe1,0x08,0xc0,0x8d,0xe2, -0x00,0x18,0x9c,0xe8,0x08,0x60,0x81,0xe1,0x09,0x70,0x87,0xe1,0x08,0x10,0x83,0xe2, -0x0c,0x70,0x87,0xe1,0x0b,0x60,0x86,0xe1,0xec,0x60,0x80,0xe5,0xf0,0x70,0x80,0xe5, -0x02,0x70,0xd1,0xe5,0x01,0x60,0xd1,0xe5,0x03,0x00,0xd1,0xe5,0x08,0xc0,0xd3,0xe5, -0x07,0x18,0xa0,0xe1,0x06,0x14,0x81,0xe1,0x0c,0x10,0x81,0xe1,0x00,0x1c,0x81,0xe1, -0x08,0x10,0x85,0xe5,0x02,0xc0,0xd2,0xe5,0x01,0x00,0xd2,0xe5,0x0c,0x10,0xd3,0xe5, -0x03,0x20,0xd2,0xe5,0x0c,0x38,0xa0,0xe1,0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x3c,0x83,0xe1,0x0c,0x30,0x85,0xe5,0xa3,0xfe,0xff,0xea,0x02,0x10,0xd3,0xe5, -0x04,0x20,0x83,0xe2,0x01,0x70,0xd3,0xe5,0x00,0x60,0xd3,0xe5,0x03,0xc0,0xd3,0xe5, -0x01,0x18,0xa0,0xe1,0x07,0x14,0x81,0xe1,0x06,0x10,0x81,0xe1,0x0c,0x1c,0x81,0xe1, -0x04,0x10,0x85,0xe5,0x02,0x60,0xd2,0xe5,0x01,0xc0,0xd2,0xe5,0x04,0x10,0xd3,0xe5, -0x03,0x20,0xd2,0xe5,0x8f,0xfe,0xff,0xea,0x03,0x10,0xa0,0xe1,0x05,0x00,0xa0,0xe1, -0x20,0x20,0xa0,0xe3,0x04,0x30,0x8d,0xe5,0xb4,0x4c,0x00,0xeb,0x04,0x30,0x9d,0xe5, -0x20,0x10,0x83,0xe2,0x20,0xc0,0xd3,0xe5,0x02,0x70,0xd1,0xe5,0x24,0x20,0x83,0xe2, -0x01,0x60,0xd1,0xe5,0x03,0x00,0xd1,0xe5,0x07,0x18,0xa0,0xe1,0x06,0x14,0x81,0xe1, -0x0c,0x10,0x81,0xe1,0x00,0x1c,0x81,0xe1,0x20,0x10,0x85,0xe5,0x02,0xc0,0xd2,0xe5, -0x01,0x00,0xd2,0xe5,0x24,0x10,0xd3,0xe5,0x03,0x20,0xd2,0xe5,0x0c,0x38,0xa0,0xe1, -0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1,0x02,0x3c,0x83,0xe1,0x24,0x30,0x85,0xe5, -0x79,0xfe,0xff,0xea,0x02,0x70,0xd3,0xe5,0x04,0xc0,0x83,0xe2,0x01,0x90,0xd3,0xe5, -0x04,0x10,0x8c,0xe2,0x00,0xa0,0xd3,0xe5,0x04,0x20,0x81,0xe2,0x03,0x80,0xd3,0xe5, -0x04,0x60,0x82,0xe2,0x07,0x78,0xa0,0xe1,0x09,0x74,0x87,0xe1,0x0a,0x70,0x87,0xe1, -0x08,0x7c,0x87,0xe1,0xec,0x70,0x80,0xe5,0x02,0xa0,0xdc,0xe5,0x01,0x80,0xdc,0xe5, -0x04,0x70,0xd3,0xe5,0x03,0x00,0xdc,0xe5,0x0a,0x38,0xa0,0xe1,0x08,0x34,0x83,0xe1, -0x07,0x30,0x83,0xe1,0x00,0x3c,0x83,0xe1,0x04,0x30,0x85,0xe5,0x02,0x30,0xd1,0xe5, -0x01,0x70,0xd1,0xe5,0x03,0x00,0xd1,0xe5,0x04,0xc0,0xdc,0xe5,0x03,0x38,0xa0,0xe1, -0x07,0x34,0x83,0xe1,0x0c,0x30,0x83,0xe1,0x00,0x3c,0x83,0xe1,0x08,0x30,0x85,0xe5, -0x02,0x30,0xd2,0xe5,0x01,0xc0,0xd2,0xe5,0x04,0x00,0xd1,0xe5,0x03,0x10,0xd2,0xe5, -0x03,0x38,0xa0,0xe1,0x0c,0x34,0x83,0xe1,0x00,0x30,0x83,0xe1,0x01,0x3c,0x83,0xe1, -0x0c,0x30,0x85,0xe5,0x02,0x30,0xd6,0xe5,0x01,0x00,0xd6,0xe5,0x04,0x10,0xd2,0xe5, -0x03,0x20,0xd6,0xe5,0x03,0x38,0xa0,0xe1,0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x3c,0x83,0xe1,0x10,0x30,0x85,0xe5,0x47,0xfe,0xff,0xea,0x02,0x10,0xd3,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x90,0xa0,0xe3,0x01,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3, -0x00,0x80,0xa0,0xe3,0x09,0x70,0x89,0xe1,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x03,0x10,0xd3,0xe5,0x00,0x20,0xa0,0xe3,0x28,0x10,0x8d,0xe5,0x2c,0x20,0x8d,0xe5, -0x05,0x10,0xd3,0xe5,0x00,0x20,0xa0,0xe3,0x28,0xc0,0x9d,0xe5,0x20,0x10,0x8d,0xe5, -0x24,0x20,0x8d,0xe5,0x08,0x10,0xa0,0xe1,0x09,0x20,0xa0,0xe1,0x0a,0x84,0xa0,0xe1, -0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x0c,0xcc,0xa0,0xe1,0x00,0x10,0xd3,0xe5, -0x00,0x20,0xa0,0xe3,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5,0x00,0x10,0xa0,0xe3, -0x06,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3,0x30,0xa0,0x8d,0xe5,0x34,0xb0,0x8d,0xe5, -0x10,0xb0,0x9d,0xe5,0x04,0x20,0xd3,0xe5,0x38,0xc0,0x8d,0xe5,0x30,0xc0,0x9d,0xe5, -0x0b,0x68,0xa0,0xe1,0x07,0xa0,0xd3,0xe5,0x00,0xb0,0xa0,0xe3,0x28,0x10,0x8d,0xe5, -0x08,0x60,0x86,0xe1,0x08,0x10,0x8d,0xe5,0x10,0xa0,0x8d,0xe5,0x14,0xb0,0x8d,0xe5, -0x18,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x0b,0x90,0x87,0xe1,0x20,0xb0,0x9d,0xe5, -0x0a,0x80,0x86,0xe1,0x0c,0x78,0xa0,0xe1,0x0b,0xb4,0xa0,0xe1,0x2c,0xb0,0x8d,0xe5, -0x38,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x09,0xb0,0x8b,0xe1,0x10,0x90,0x9d,0xe5, -0x08,0xa0,0x8a,0xe1,0x18,0xa0,0x8d,0xe5,0x1c,0xb0,0x8d,0xe5,0x01,0xa0,0xa0,0xe1, -0x18,0xc0,0x8d,0xe2,0x00,0x18,0x9c,0xe8,0x09,0x9c,0xa0,0xe1,0x0c,0x90,0x8d,0xe5, -0x01,0xb0,0x8b,0xe1,0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x02,0xc0,0x8c,0xe1, -0x0c,0x20,0x83,0xe2,0x0b,0x80,0x88,0xe1,0x0c,0x90,0x89,0xe1,0x08,0xc0,0x8d,0xe2, -0x00,0x18,0x9c,0xe8,0x08,0x60,0x81,0xe1,0x09,0x70,0x87,0xe1,0x08,0x10,0x83,0xe2, -0x0c,0x70,0x87,0xe1,0x0b,0x60,0x86,0xe1,0xec,0x60,0x80,0xe5,0xf0,0x70,0x80,0xe5, -0x02,0x70,0xd1,0xe5,0x01,0x60,0xd1,0xe5,0x03,0x00,0xd1,0xe5,0x08,0xc0,0xd3,0xe5, -0x07,0x18,0xa0,0xe1,0x06,0x14,0x81,0xe1,0x0c,0x10,0x81,0xe1,0x00,0x1c,0x81,0xe1, -0x0c,0x10,0x85,0xe5,0x02,0xc0,0xd2,0xe5,0x01,0x00,0xd2,0xe5,0x0c,0x10,0xd3,0xe5, -0x03,0x20,0xd2,0xe5,0x0c,0x38,0xa0,0xe1,0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1, -0x02,0x3c,0x83,0xe1,0x08,0x30,0x85,0xe5,0xe3,0xfd,0xff,0xea,0x02,0x10,0xd3,0xe5, -0x04,0x20,0x83,0xe2,0x01,0x60,0xd3,0xe5,0x00,0xc0,0xd3,0xe5,0x03,0x00,0xd3,0xe5, -0x01,0x18,0xa0,0xe1,0x06,0x14,0x81,0xe1,0x0c,0x10,0x81,0xe1,0x00,0x1c,0x81,0xe1, -0x08,0x10,0x85,0xe5,0x03,0x00,0x51,0xe3,0x01,0xf1,0x8f,0x90,0xd6,0xfd,0xff,0xea, -0x90,0x01,0x00,0xea,0x7b,0x01,0x00,0xea,0x70,0x01,0x00,0xea,0x6f,0x01,0x00,0xea, -0x02,0x10,0xd3,0xe5,0x00,0x60,0xa0,0xe3,0x00,0x70,0xa0,0xe3,0x06,0xb0,0xa0,0xe1, -0x07,0xc0,0xa0,0xe1,0x01,0x80,0xd3,0xe5,0x10,0x60,0x8d,0xe5,0x14,0x70,0x8d,0xe5, -0x04,0x20,0x83,0xe2,0x00,0xa0,0xd3,0xe5,0x01,0x18,0xa0,0xe1,0x18,0xb0,0x8d,0xe5, -0x1c,0xc0,0x8d,0xe5,0x03,0xc0,0xd3,0xe5,0x08,0x14,0x81,0xe1,0x28,0x60,0x8d,0xe5, -0x2c,0x70,0x8d,0xe5,0x0a,0x10,0x81,0xe1,0x20,0xc0,0x8d,0xe5,0x07,0xc0,0xa0,0xe1, -0x0c,0x80,0xa0,0xe1,0x06,0x70,0xa0,0xe1,0x08,0x70,0x8d,0xe5,0x0c,0x80,0x8d,0xe5, -0x20,0x80,0x9d,0xe5,0x08,0x1c,0x81,0xe1,0xec,0x10,0x80,0xe5,0x02,0x90,0xd2,0xe5, -0x00,0xa0,0xa0,0xe3,0x03,0xa0,0xd2,0xe5,0x00,0xb0,0xa0,0xe3,0x01,0x00,0xd2,0xe5, -0x00,0x10,0xa0,0xe3,0x40,0xa0,0x8d,0xe5,0x44,0xb0,0x8d,0xe5,0x09,0x98,0xa0,0xe1, -0x05,0xb0,0xd2,0xe5,0x00,0xc0,0xa0,0xe3,0x0a,0xac,0xa0,0xe1,0x48,0xb0,0x8d,0xe5, -0x4c,0xc0,0x8d,0xe5,0x04,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3,0x30,0x60,0x8d,0xe5, -0x34,0x70,0x8d,0xe5,0x00,0x74,0xa0,0xe1,0x00,0x60,0xa0,0xe3,0x10,0x70,0x8d,0xe5, -0x06,0x00,0xd2,0xe5,0x00,0x10,0xa0,0xe3,0x18,0x90,0x8d,0xe5,0x04,0x70,0xd2,0xe5, -0x28,0xa0,0x8d,0xe5,0x07,0x80,0xd2,0xe5,0x00,0x90,0xa0,0xe3,0x10,0x30,0x8d,0xe2, -0x0c,0x00,0x93,0xe8,0x20,0x80,0x8d,0xe5,0x24,0x90,0x8d,0xe5,0x18,0xa0,0x8d,0xe2, -0x00,0x06,0x9a,0xe8,0x48,0x80,0x9d,0xe5,0x0a,0x30,0x83,0xe1,0x30,0xb0,0x8d,0xe2, -0x00,0x0c,0x9b,0xe8,0x09,0x20,0x82,0xe1,0x00,0x98,0xa0,0xe1,0x28,0x10,0x8d,0xe2, -0x03,0x00,0x91,0xe8,0x08,0x84,0xa0,0xe1,0x0a,0x20,0x82,0xe1,0x20,0xa0,0x9d,0xe5, -0x0b,0x30,0x83,0xe1,0x06,0xb0,0xa0,0xe1,0x00,0x20,0x82,0xe1,0x01,0x30,0x83,0xe1, -0x06,0x20,0x82,0xe1,0x07,0x30,0x83,0xe1,0x0a,0xac,0xa0,0xe1,0x08,0x30,0x83,0xe1, -0x06,0x20,0x82,0xe1,0x0c,0xa0,0x8d,0xe5,0x02,0x80,0x86,0xe1,0x08,0x60,0x8d,0xe5, -0x03,0x90,0x89,0xe1,0x08,0x10,0x8d,0xe2,0x03,0x00,0x91,0xe8,0x00,0x80,0x88,0xe1, -0x01,0x90,0x89,0xe1,0x08,0x80,0x85,0xe5,0x0c,0x90,0x85,0xe5,0x76,0xfd,0xff,0xea, -0x03,0x10,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x20,0x20,0xa0,0xe3,0x04,0x30,0x8d,0xe5, -0x96,0x4b,0x00,0xeb,0x04,0x30,0x9d,0xe5,0x00,0xb0,0xa0,0xe3,0x00,0xa0,0xa0,0xe3, -0x0b,0x90,0x8b,0xe1,0x20,0x00,0x83,0xe2,0x01,0x10,0xd0,0xe5,0x00,0x20,0xa0,0xe3, -0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5,0x02,0x60,0xd0,0xe5,0x00,0x70,0xa0,0xe3, -0x18,0x60,0x8d,0xe5,0x1c,0x70,0x8d,0xe5,0x0a,0x60,0xa0,0xe1,0x03,0x10,0xd0,0xe5, -0x00,0x20,0xa0,0xe3,0x0b,0x70,0xa0,0xe1,0x08,0x60,0x8d,0xe5,0x0c,0x70,0x8d,0xe5, -0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5,0x05,0x10,0xd0,0xe5,0x00,0x20,0xa0,0xe3, -0x30,0x10,0x8d,0xe5,0x34,0x20,0x8d,0xe5,0x20,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3, -0x28,0x60,0x8d,0xe5,0x2c,0x70,0x8d,0xe5,0x06,0x10,0xd0,0xe5,0x00,0x20,0xa0,0xe3, -0x20,0x60,0x9d,0xe5,0x10,0x70,0x9d,0xe5,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x00,0x10,0xa0,0xe3,0x18,0x20,0x9d,0xe5,0x06,0x6c,0xa0,0xe1,0x07,0xa4,0xa0,0xe1, -0x02,0x88,0xa0,0xe1,0x04,0x20,0xd0,0xe5,0x08,0x60,0x8d,0xe5,0x07,0x60,0xd0,0xe5, -0x00,0x70,0xa0,0xe3,0x0a,0x80,0x88,0xe1,0x10,0x00,0x9d,0xe5,0x18,0x60,0x8d,0xe5, -0x1c,0x70,0x8d,0xe5,0x28,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x00,0x08,0xa0,0xe1, -0x06,0xa0,0x88,0xe1,0x07,0xb0,0x89,0xe1,0x20,0xa0,0x8d,0xe5,0x24,0xb0,0x8d,0xe5, -0x20,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x08,0xc0,0x8d,0xe2,0x00,0x18,0x9c,0xe8, -0x30,0x80,0x9d,0xe5,0x08,0x10,0x8d,0xe5,0x0b,0x90,0x89,0xe1,0x0c,0xa0,0x8a,0xe1, -0x20,0x90,0x8d,0xe5,0x24,0xa0,0x8d,0xe5,0x00,0xc0,0xa0,0xe1,0x18,0xa0,0x9d,0xe5, -0x08,0x74,0xa0,0xe1,0x20,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x28,0x00,0x83,0xe2, -0x0a,0xac,0xa0,0xe1,0x02,0x90,0x89,0xe1,0x01,0x80,0x88,0xe1,0x0c,0xa0,0x8d,0xe5, -0x09,0x70,0x87,0xe1,0x08,0x60,0x81,0xe1,0x07,0xc0,0x8c,0xe1,0x08,0x80,0x8d,0xe2, -0x80,0x01,0x98,0xe8,0x06,0xb0,0x81,0xe1,0x00,0x90,0xa0,0xe3,0x00,0xa0,0xa0,0xe3, -0x30,0x20,0x83,0xe2,0x07,0xb0,0x8b,0xe1,0x08,0xc0,0x8c,0xe1,0x20,0xb0,0x85,0xe5, -0x24,0xc0,0x85,0xe5,0x00,0x80,0xa0,0xe3,0x00,0xb0,0xa0,0xe3,0x38,0x80,0x8d,0xe5, -0x3c,0x90,0x8d,0xe5,0x01,0x80,0xd0,0xe5,0x00,0x90,0xa0,0xe3,0x48,0xa0,0x8d,0xe5, -0x4c,0xb0,0x8d,0xe5,0x02,0xb0,0xd0,0xe5,0x00,0xc0,0xa0,0xe3,0x3c,0x10,0x8d,0xe5, -0x10,0xb0,0x8d,0xe5,0x14,0xc0,0x8d,0xe5,0x03,0x60,0xd0,0xe5,0x00,0x70,0xa0,0xe3, -0x4c,0x10,0x8d,0xe5,0x28,0x60,0x8d,0xe5,0x2c,0x70,0x8d,0xe5,0x05,0xa0,0xd0,0xe5, -0x00,0xb0,0xa0,0xe3,0x20,0xa0,0x8d,0xe5,0x24,0xb0,0x8d,0xe5,0x28,0x60,0xd3,0xe5, -0x00,0x70,0xa0,0xe3,0x18,0x60,0x8d,0xe5,0x1c,0x70,0x8d,0xe5,0x08,0x74,0xa0,0xe1, -0x00,0x60,0xa0,0xe3,0x38,0x70,0x8d,0xe5,0x00,0x70,0xa0,0xe3,0x06,0x80,0xd0,0xe5, -0x00,0x90,0xa0,0xe3,0x30,0x80,0x8d,0xe5,0x34,0x90,0x8d,0xe5,0x10,0x90,0x9d,0xe5, -0x09,0x98,0xa0,0xe1,0x48,0x90,0x8d,0xe5,0x48,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8, -0x07,0xb0,0xd0,0xe5,0x00,0xc0,0xa0,0xe3,0x08,0x60,0x8d,0xe5,0x0c,0x70,0x8d,0xe5, -0x38,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x40,0xb0,0x8d,0xe5,0x44,0xc0,0x8d,0xe5, -0x04,0x00,0xd0,0xe5,0x07,0x90,0x89,0xe1,0x28,0x70,0x9d,0xe5,0x06,0x80,0x88,0xe1, -0x08,0x10,0x8d,0xe5,0x10,0x80,0x8d,0xe5,0x14,0x90,0x8d,0xe5,0x10,0xa0,0x8d,0xe2, -0x00,0x06,0x9a,0xe8,0x07,0x7c,0xa0,0xe1,0x30,0x80,0x9d,0xe5,0x0c,0x00,0x8d,0xe5, -0x07,0xb0,0xa0,0xe1,0x18,0x70,0x8d,0xe2,0xc0,0x00,0x97,0xe8,0x07,0xa0,0x8a,0xe1, -0x20,0x70,0x9d,0xe5,0x06,0x90,0x89,0xe1,0x09,0x60,0x8b,0xe1,0x07,0x74,0xa0,0xe1, -0x2c,0x70,0x8d,0xe5,0x0a,0x70,0x81,0xe1,0x18,0x60,0x8d,0xe5,0x1c,0x70,0x8d,0xe5, -0x08,0x78,0xa0,0xe1,0x18,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x08,0x90,0x8d,0xe2, -0x00,0x03,0x99,0xe8,0x08,0xa0,0x8a,0xe1,0x09,0xb0,0x8b,0xe1,0x08,0xa0,0x8d,0xe5, -0x0c,0xb0,0x8d,0xe5,0x34,0xa0,0x83,0xe2,0x40,0x90,0x9d,0xe5,0x28,0x10,0x8d,0xe5, -0x08,0xc0,0x8d,0xe2,0x00,0x18,0x9c,0xe8,0x10,0x10,0x8d,0xe5,0x09,0x9c,0xa0,0xe1, -0x14,0x90,0x8d,0xe5,0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x0b,0x80,0x88,0xe1, -0x0c,0x90,0x89,0xe1,0x08,0x60,0x81,0xe1,0x10,0x10,0x8d,0xe2,0x03,0x00,0x91,0xe8, -0x09,0x70,0x87,0xe1,0x38,0x80,0x83,0xe2,0x40,0xc0,0x83,0xe2,0x00,0x60,0x86,0xe1, -0x01,0x70,0x87,0xe1,0x28,0x60,0x85,0xe5,0x2c,0x70,0x85,0xe5,0x3c,0x60,0x83,0xe2, -0x02,0xb0,0xd2,0xe5,0x44,0x00,0x83,0xe2,0x01,0x70,0xd2,0xe5,0x30,0x10,0xd3,0xe5, -0x0b,0xb8,0xa0,0xe1,0x08,0x10,0x8d,0xe5,0x48,0x10,0x83,0xe2,0x03,0x90,0xd2,0xe5, -0x07,0x74,0x8b,0xe1,0x08,0xb0,0x9d,0xe5,0x4c,0x20,0x83,0xe2,0x0b,0x70,0x87,0xe1, -0x09,0x9c,0x87,0xe1,0x30,0x90,0x85,0xe5,0x02,0x90,0xda,0xe5,0x01,0x70,0xda,0xe5, -0x34,0xb0,0xd3,0xe5,0x03,0xa0,0xda,0xe5,0x09,0x98,0xa0,0xe1,0x07,0x94,0x89,0xe1, -0x0b,0xb0,0x89,0xe1,0x0a,0xac,0x8b,0xe1,0x34,0xa0,0x85,0xe5,0x02,0xb0,0xd8,0xe5, -0x01,0x90,0xd8,0xe5,0x38,0xa0,0xd3,0xe5,0x03,0x80,0xd8,0xe5,0x0b,0x78,0xa0,0xe1, -0x09,0x74,0x87,0xe1,0x0a,0x70,0x87,0xe1,0x08,0x7c,0x87,0xe1,0x38,0x70,0x85,0xe5, -0x02,0x90,0xd6,0xe5,0x01,0xa0,0xd6,0xe5,0x03,0x70,0xd6,0xe5,0x3c,0x80,0xd3,0xe5, -0x09,0x68,0xa0,0xe1,0x0a,0x64,0x86,0xe1,0x08,0x60,0x86,0xe1,0x07,0x6c,0x86,0xe1, -0x3c,0x60,0x85,0xe5,0x02,0xa0,0xdc,0xe5,0x01,0x80,0xdc,0xe5,0x03,0x60,0xdc,0xe5, -0x40,0x70,0xd3,0xe5,0x0a,0xc8,0xa0,0xe1,0x08,0xc4,0x8c,0xe1,0x07,0xc0,0x8c,0xe1, -0x06,0xcc,0x8c,0xe1,0x40,0xc0,0x85,0xe5,0x02,0x80,0xd0,0xe5,0x01,0x70,0xd0,0xe5, -0x03,0xc0,0xd0,0xe5,0x44,0x60,0xd3,0xe5,0x08,0x08,0xa0,0xe1,0x07,0x04,0x80,0xe1, -0x06,0x00,0x80,0xe1,0x0c,0x0c,0x80,0xe1,0x44,0x00,0x85,0xe5,0x02,0x70,0xd1,0xe5, -0x01,0x60,0xd1,0xe5,0x03,0x00,0xd1,0xe5,0x48,0xc0,0xd3,0xe5,0x07,0x18,0xa0,0xe1, -0x06,0x14,0x81,0xe1,0x0c,0x10,0x81,0xe1,0x00,0x1c,0x81,0xe1,0x48,0x10,0x85,0xe5, -0x02,0xc0,0xd2,0xe5,0x01,0x00,0xd2,0xe5,0x4c,0x10,0xd3,0xe5,0x03,0x20,0xd2,0xe5, -0x0c,0x38,0xa0,0xe1,0x00,0x34,0x83,0xe1,0x01,0x30,0x83,0xe1,0x02,0x3c,0x83,0xe1, -0x4c,0x30,0x85,0xe5,0x64,0xfc,0xff,0xea,0x00,0x00,0xa0,0xe3,0x64,0xfc,0xff,0xea, -0x02,0x10,0xd2,0xe5,0x01,0x00,0xd2,0xe5,0x04,0x30,0xd3,0xe5,0x03,0x20,0xd2,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x10,0x30,0x85,0xe5,0x58,0xfc,0xff,0xea,0x02,0xc0,0xd2,0xe5,0x04,0x10,0x82,0xe2, -0x01,0x60,0xd2,0xe5,0x03,0x00,0xd2,0xe5,0x04,0x30,0xd3,0xe5,0x0c,0xc8,0xa0,0xe1, -0x06,0xc4,0x8c,0xe1,0x03,0x30,0x8c,0xe1,0x00,0x3c,0x83,0xe1,0x10,0x30,0x85,0xe5, -0x02,0xc0,0xd1,0xe5,0x01,0x00,0xd1,0xe5,0x04,0x30,0xd2,0xe5,0x03,0x20,0xd1,0xe5, -0x0c,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x14,0x30,0x85,0xe5,0x44,0xfc,0xff,0xea,0x02,0x00,0xd2,0xe5,0x00,0x10,0xa0,0xe3, -0x00,0x90,0xa0,0xe3,0x01,0xa0,0xd2,0xe5,0x00,0xb0,0xa0,0xe3,0x00,0x80,0xa0,0xe3, -0x09,0x70,0x89,0xe1,0x10,0x00,0x8d,0xe5,0x14,0x10,0x8d,0xe5,0x03,0x00,0xd2,0xe5, -0x00,0x10,0xa0,0xe3,0x28,0x00,0x8d,0xe5,0x2c,0x10,0x8d,0xe5,0x05,0x00,0xd2,0xe5, -0x00,0x10,0xa0,0xe3,0x28,0xc0,0x9d,0xe5,0x20,0x00,0x8d,0xe5,0x24,0x10,0x8d,0xe5, -0x08,0x00,0xa0,0xe1,0x09,0x10,0xa0,0xe1,0x0a,0x84,0xa0,0xe1,0x38,0x00,0x8d,0xe5, -0x3c,0x10,0x8d,0xe5,0x0c,0xcc,0xa0,0xe1,0x04,0x00,0xd3,0xe5,0x00,0x10,0xa0,0xe3, -0x18,0x00,0x8d,0xe5,0x1c,0x10,0x8d,0xe5,0x00,0x00,0xa0,0xe3,0x06,0xa0,0xd2,0xe5, -0x00,0xb0,0xa0,0xe3,0x30,0xa0,0x8d,0xe5,0x34,0xb0,0x8d,0xe5,0x10,0xb0,0x9d,0xe5, -0x04,0x10,0xd2,0xe5,0x38,0xc0,0x8d,0xe5,0x30,0xc0,0x9d,0xe5,0x0b,0x68,0xa0,0xe1, -0x07,0xa0,0xd2,0xe5,0x00,0xb0,0xa0,0xe3,0x28,0x00,0x8d,0xe5,0x08,0x60,0x86,0xe1, -0x08,0x00,0x8d,0xe5,0x10,0xa0,0x8d,0xe5,0x14,0xb0,0x8d,0xe5,0x18,0xb0,0x8d,0xe2, -0x00,0x0c,0x9b,0xe8,0x10,0x30,0x9d,0xe5,0x0b,0x90,0x87,0xe1,0x20,0xb0,0x9d,0xe5, -0x0a,0x80,0x86,0xe1,0x0c,0x78,0xa0,0xe1,0x03,0x3c,0xa0,0xe1,0x0b,0xb4,0xa0,0xe1, -0x0c,0x30,0x8d,0xe5,0x08,0x30,0x82,0xe2,0x2c,0xb0,0x8d,0xe5,0x38,0xb0,0x8d,0xe2, -0x00,0x0c,0x9b,0xe8,0x08,0xa0,0x8a,0xe1,0x09,0xb0,0x8b,0xe1,0x18,0xa0,0x8d,0xe5, -0x1c,0xb0,0x8d,0xe5,0x18,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x28,0x90,0x8d,0xe2, -0x00,0x03,0x99,0xe8,0x01,0xb0,0x8b,0xe1,0x00,0xa0,0x8a,0xe1,0x0b,0x90,0x89,0xe1, -0x08,0xc0,0x8d,0xe2,0x00,0x18,0x9c,0xe8,0x0a,0x80,0x88,0xe1,0x09,0x70,0x87,0xe1, -0x08,0x60,0x80,0xe1,0x0b,0x60,0x86,0xe1,0x0c,0x70,0x87,0xe1,0x10,0x60,0x85,0xe5, -0x14,0x70,0x85,0xe5,0x01,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3,0x08,0x60,0x8d,0xe5, -0x0c,0x70,0x8d,0xe5,0x02,0x70,0xd3,0xe5,0x00,0x80,0xa0,0xe3,0x10,0x70,0x8d,0xe5, -0x14,0x80,0x8d,0xe5,0x03,0x80,0xd3,0xe5,0x00,0x90,0xa0,0xe3,0x10,0xc0,0x9d,0xe5, -0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5,0x05,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3, -0x0c,0x88,0xa0,0xe1,0x20,0x60,0x8d,0xe5,0x24,0x70,0x8d,0xe5,0x08,0x60,0xd2,0xe5, -0x00,0x70,0xa0,0xe3,0x18,0x60,0x8d,0xe5,0x1c,0x70,0x8d,0xe5,0x06,0x60,0xd3,0xe5, -0x00,0x70,0xa0,0xe3,0x30,0x60,0x8d,0xe5,0x34,0x70,0x8d,0xe5,0x00,0x60,0xa0,0xe3, -0x08,0x70,0x9d,0xe5,0x07,0xa4,0xa0,0xe1,0x00,0x70,0xa0,0xe3,0x08,0x60,0x8d,0xe5, -0x0c,0x70,0x8d,0xe5,0x07,0x60,0xd3,0xe5,0x00,0x70,0xa0,0xe3,0x08,0x20,0x8a,0xe1, -0x18,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x10,0x60,0x8d,0xe5,0x14,0x70,0x8d,0xe5, -0x04,0x30,0xd3,0xe5,0x08,0xb0,0x82,0xe1,0x08,0x00,0x8d,0xe5,0x20,0x20,0x9d,0xe5, -0x0c,0x30,0x8d,0xe5,0x00,0x30,0x80,0xe1,0x03,0xc0,0xa0,0xe1,0x28,0x30,0x9d,0xe5, -0x08,0x80,0x8d,0xe2,0x80,0x01,0x98,0xe8,0x09,0xc0,0x8c,0xe1,0x00,0xc0,0x8c,0xe1, -0x02,0xa4,0xa0,0xe1,0x03,0x6c,0xa0,0xe1,0x08,0xc0,0x8c,0xe1,0x10,0x80,0x9d,0xe5, -0x0c,0xa0,0x8a,0xe1,0x06,0xb0,0x8b,0xe1,0x30,0x60,0x9d,0xe5,0x07,0xb0,0x8b,0xe1, -0x0b,0x90,0x80,0xe1,0x08,0x7c,0xa0,0xe1,0x09,0x20,0x80,0xe1,0x06,0x38,0xa0,0xe1, -0x02,0x60,0x80,0xe1,0x0a,0x30,0x83,0xe1,0x03,0x70,0x87,0xe1,0x18,0x60,0x85,0xe5, -0x1c,0x70,0x85,0xe5,0xb0,0xfb,0xff,0xea,0xf8,0x40,0x2d,0xe9,0x00,0x70,0xa0,0xe1, -0x2a,0x0e,0xa0,0xe3,0x01,0x60,0xa0,0xe1,0x02,0x50,0xa0,0xe1,0x3c,0x51,0x00,0xeb, -0x00,0x10,0xa0,0xe3,0x2a,0x2e,0xa0,0xe3,0x00,0x40,0xa0,0xe1,0xcd,0x49,0x00,0xeb, -0x01,0x30,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x18,0x30,0x84,0xe5,0x06,0x10,0xa0,0xe1, -0x05,0x20,0xa0,0xe1,0xf8,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3,0x00,0x40,0x87,0x05, -0xf8,0x80,0xbd,0xe8,0x10,0x40,0x2d,0xe9,0x00,0x40,0x50,0xe2,0x10,0x80,0xbd,0x08, -0x00,0x00,0x94,0xe5,0x07,0x0c,0x00,0xeb,0x04,0x00,0xa0,0xe1,0x10,0x40,0xbd,0xe8, -0x28,0x51,0x00,0xea,0xf0,0x4f,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0x00,0xc0,0xa0,0xe3, -0x1c,0x60,0x84,0xe2,0x34,0xd0,0x4d,0xe2,0x01,0x70,0xa0,0xe1,0x00,0x00,0x90,0xe5, -0x02,0x80,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x0c,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0x34,0x0c,0x00,0xeb,0x00,0x00,0x50,0xe3,0x12,0x00,0x00,0x1a, -0x1e,0xc0,0xd4,0xe5,0x1d,0x10,0xd4,0xe5,0x1c,0xa0,0xd4,0xe5,0x1f,0x50,0xd4,0xe5, -0x0c,0xc8,0xa0,0xe1,0x20,0x30,0xd4,0xe5,0x21,0x20,0xd4,0xe5,0x01,0xc4,0x8c,0xe1, -0x23,0xb0,0xd4,0xe5,0x22,0x10,0xd4,0xe5,0x0a,0xc0,0x8c,0xe1,0x24,0xa0,0xd4,0xe5, -0x05,0xcc,0x8c,0xe1,0x25,0x50,0xd4,0xe5,0x01,0x00,0x5c,0xe3,0x27,0xc0,0xd4,0xe5, -0x14,0x50,0x8d,0xe5,0x26,0x50,0xd4,0xe5,0x02,0x00,0x00,0x0a,0x12,0x08,0xa0,0xe3, -0x34,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x05,0x58,0xa0,0xe1,0x0c,0x00,0x8d,0xe5, -0x1c,0x50,0x8d,0xe5,0x00,0x50,0xa0,0xe1,0x1c,0x90,0x9d,0xe5,0x14,0x00,0x9d,0xe5, -0x00,0x94,0x89,0xe1,0x05,0x00,0xa0,0xe1,0x1c,0x90,0x8d,0xe5,0x0a,0x90,0x89,0xe1, -0x0c,0xcc,0x89,0xe1,0x0c,0xc0,0x84,0xe5,0x00,0xc0,0xd6,0xe7,0x01,0x00,0x80,0xe2, -0x0c,0x00,0x50,0xe3,0x0c,0x50,0x85,0xe0,0xfa,0xff,0xff,0x1a,0x01,0x18,0xa0,0xe1, -0x02,0x24,0x81,0xe1,0x03,0x30,0x82,0xe1,0x0b,0xbc,0x83,0xe1,0x01,0x00,0x5b,0xe3, -0x0f,0x00,0x00,0x0a,0x04,0x30,0x4b,0xe2,0x01,0x00,0x53,0xe3,0xe2,0xff,0xff,0x8a, -0x05,0x00,0x5b,0xe3,0x58,0x00,0x00,0x0a,0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5, -0x0c,0x30,0xa0,0xe1,0x28,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3,0x00,0xc0,0x8d,0xe5, -0xf9,0x0b,0x00,0xeb,0x70,0x31,0x9f,0xe5,0x00,0x00,0x50,0xe3,0x03,0x00,0xa0,0x01, -0xd6,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x06,0x10,0xa0,0xe1, -0x08,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xee,0x0b,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xcd,0xff,0xff,0x1a,0x1e,0x30,0xd4,0xe5,0x22,0x20,0xd4,0xe5, -0x1d,0x10,0xd4,0xe5,0x21,0x90,0xd4,0xe5,0x03,0x38,0xa0,0xe1,0x1c,0xe0,0xd4,0xe5, -0x1f,0xa0,0xd4,0xe5,0x02,0x28,0xa0,0xe1,0x20,0xc0,0xd4,0xe5,0x01,0x34,0x83,0xe1, -0x23,0x10,0xd4,0xe5,0x09,0x24,0x82,0xe1,0x0e,0x30,0x83,0xe1,0x0c,0x20,0x82,0xe1, -0x0a,0xac,0x93,0xe1,0x01,0x1c,0x82,0xe1,0x00,0x10,0x87,0xe5,0x22,0x00,0x00,0x0a, -0x00,0xc0,0x94,0xe5,0x24,0x90,0x84,0xe2,0x00,0x30,0xa0,0xe1,0x00,0x00,0x8d,0xe5, -0x09,0x10,0xa0,0xe1,0x0a,0x20,0xa0,0xe1,0x0c,0x00,0xa0,0xe1,0xd2,0x0b,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xb1,0xff,0xff,0x1a,0x04,0x00,0xa0,0xe1,0x00,0x10,0x97,0xe5, -0x08,0x20,0xa0,0xe1,0x09,0x30,0xa0,0xe1,0xea,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xa9,0xff,0xff,0x0a,0x08,0xa0,0x9a,0xe2,0x0a,0x70,0xa0,0x01,0x16,0x00,0x00,0x1a, -0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x2c,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xbf,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3, -0x9e,0xff,0xff,0x1a,0x2c,0x30,0x9d,0xe5,0x03,0x50,0x85,0xe0,0x07,0x70,0x85,0xe0, -0x00,0x00,0x57,0xe3,0x12,0x08,0xa0,0x13,0x98,0xff,0xff,0xea,0x0a,0x30,0xa0,0xe1, -0x04,0x00,0xa0,0xe1,0x08,0x20,0xa0,0xe1,0xd2,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x08,0xa0,0xa0,0x13,0x08,0xa0,0xa0,0x03,0x00,0x00,0x88,0x05,0x00,0x30,0xa0,0xe3, -0x03,0x70,0xa0,0xe1,0x03,0x20,0xd6,0xe7,0x01,0x30,0x83,0xe2,0x03,0x00,0x5a,0xe1, -0x02,0x70,0x87,0xe0,0xfa,0xff,0xff,0x8a,0xe0,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe3, -0x00,0x00,0x94,0xe5,0x24,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xa0,0x0b,0x00,0xeb,0x00,0x00,0x50,0xe3,0x7f,0xff,0xff,0x1a, -0x24,0x30,0x9d,0xe5,0x18,0x30,0x84,0xe5,0x9a,0xff,0xff,0xea,0x01,0x00,0x12,0x00, -0xf0,0x4f,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0x04,0x00,0x90,0xe5,0x02,0x60,0xa0,0xe1, -0x26,0x5c,0xa0,0xe1,0x01,0xb0,0xa0,0xe3,0x26,0xe4,0xa0,0xe1,0x26,0xc8,0xa0,0xe1, -0x1c,0xb0,0xc4,0xe5,0x20,0x94,0xa0,0xe1,0x20,0xa8,0xa0,0xe1,0x20,0x8c,0xa0,0xe1, -0x24,0x00,0xc4,0xe5,0x00,0x30,0xa0,0xe3,0x25,0x90,0xc4,0xe5,0x1c,0xd0,0x4d,0xe2, -0x02,0xb0,0xa0,0xe3,0x0c,0x50,0x8d,0xe5,0x03,0x20,0xa0,0xe1,0x1d,0x30,0xc4,0xe5, -0x01,0x70,0xa0,0xe1,0x1e,0x30,0xc4,0xe5,0x03,0x10,0xa0,0xe1,0x1f,0x30,0xc4,0xe5, -0x1c,0x50,0x84,0xe2,0x20,0xb0,0xc4,0xe5,0x21,0x30,0xc4,0xe5,0x22,0x30,0xc4,0xe5, -0x23,0x30,0xc4,0xe5,0x26,0xa0,0xc4,0xe5,0x27,0x80,0xc4,0xe5,0x28,0x60,0xc4,0xe5, -0x29,0xe0,0xc4,0xe5,0x2a,0xc0,0xc4,0xe5,0x0c,0x30,0x9d,0xe5,0x2b,0x30,0xc4,0xe5, -0x02,0x30,0xd5,0xe7,0x01,0x20,0x82,0xe2,0x10,0x00,0x52,0xe3,0x03,0x10,0x81,0xe0, -0xfa,0xff,0xff,0x1a,0x00,0x00,0x56,0xe3,0x06,0xc0,0xa0,0x01,0x06,0x00,0x00,0x0a, -0x00,0x30,0xa0,0xe3,0x03,0xc0,0xa0,0xe1,0x03,0x20,0xd7,0xe7,0x01,0x30,0x83,0xe2, -0x03,0x00,0x56,0xe1,0x02,0xc0,0x8c,0xe0,0xfa,0xff,0xff,0x8a,0x01,0x10,0x8c,0xe0, -0x00,0x00,0x94,0xe5,0x00,0xc0,0x61,0xe2,0x10,0x20,0xa0,0xe3,0x05,0x10,0xa0,0xe1, -0x00,0x30,0xa0,0xe3,0x14,0xc0,0x8d,0xe5,0x34,0x0b,0x00,0xeb,0x00,0xc0,0x50,0xe2, -0x02,0x00,0x00,0x0a,0x0c,0x00,0xa0,0xe1,0x1c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x0c,0x30,0xa0,0xe1,0x00,0x00,0x94,0xe5,0x07,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1, -0x2a,0x0b,0x00,0xeb,0x00,0xc0,0x50,0xe2,0xf5,0xff,0xff,0x1a,0x0c,0x30,0xa0,0xe1, -0x00,0x00,0x94,0xe5,0x14,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3,0x23,0x0b,0x00,0xeb, -0x00,0xc0,0x50,0xe2,0xee,0xff,0xff,0x1a,0x04,0xe0,0x94,0xe5,0x01,0x30,0xa0,0xe3, -0x18,0x30,0x84,0xe5,0x05,0x10,0xa0,0xe1,0x00,0x00,0x94,0xe5,0x0c,0x20,0xa0,0xe3, -0x03,0xe0,0x8e,0xe0,0x0c,0x30,0xa0,0xe1,0x04,0xe0,0x84,0xe5,0x00,0xc0,0x8d,0xe5, -0x41,0x0b,0x00,0xeb,0x00,0x30,0x50,0xe2,0x11,0x00,0x00,0x1a,0x1e,0x00,0xd4,0xe5, -0x1d,0x70,0xd4,0xe5,0x1c,0x20,0xd4,0xe5,0x1f,0x60,0xd4,0xe5,0x00,0x08,0xa0,0xe1, -0x20,0x10,0xd4,0xe5,0x21,0xc0,0xd4,0xe5,0x07,0x04,0x80,0xe1,0x23,0x80,0xd4,0xe5, -0x22,0x70,0xd4,0xe5,0x02,0x00,0x80,0xe1,0x26,0x90,0xd4,0xe5,0x06,0x6c,0x80,0xe1, -0x24,0x20,0xd4,0xe5,0x25,0x00,0xd4,0xe5,0x01,0x00,0x56,0xe3,0x27,0xa0,0xd4,0xe5, -0x01,0x00,0x00,0x0a,0x12,0xc8,0xa0,0xe3,0xcd,0xff,0xff,0xea,0x09,0x98,0xa0,0xe1, -0x03,0x60,0xa0,0xe1,0x00,0x04,0x89,0xe1,0x02,0x20,0x80,0xe1,0x0a,0xac,0x82,0xe1, -0x0c,0xa0,0x84,0xe5,0x03,0x20,0xd5,0xe7,0x01,0x30,0x83,0xe2,0x0c,0x00,0x53,0xe3, -0x02,0x60,0x86,0xe0,0xfa,0xff,0xff,0x1a,0x07,0x38,0xa0,0xe1,0x0c,0x34,0x83,0xe1, -0x01,0x30,0x83,0xe1,0x08,0x8c,0x83,0xe1,0x04,0x30,0x48,0xe2,0x01,0x00,0x53,0xe3, -0xeb,0xff,0xff,0x8a,0x05,0x00,0x58,0xe3,0x14,0x00,0x00,0x0a,0x00,0xc0,0xa0,0xe3, -0x00,0x00,0x94,0xe5,0x0c,0x30,0xa0,0xe1,0x10,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0x10,0x0b,0x00,0xeb,0x00,0xc0,0x50,0xe2,0xb0,0xff,0xff,0x1a, -0x10,0x30,0x9d,0xe5,0x03,0x60,0x86,0xe0,0x00,0x00,0x56,0xe3,0xdc,0xff,0xff,0x1a, -0x04,0x30,0x94,0xe5,0x01,0x30,0x43,0xe2,0x0a,0x00,0x53,0xe1,0xd8,0xff,0xff,0x1a, -0x05,0x00,0x58,0xe3,0x44,0xc0,0x9f,0xe5,0x00,0xc0,0xa0,0x13,0xa4,0xff,0xff,0xea, -0x00,0xc0,0xa0,0xe3,0x18,0x70,0x84,0xe2,0x00,0x00,0x94,0xe5,0x0c,0x30,0xa0,0xe1, -0x07,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0xfa,0x0a,0x00,0xeb, -0x00,0xc0,0x50,0xe2,0x9a,0xff,0xff,0x1a,0x01,0x30,0xd7,0xe4,0x05,0x00,0x57,0xe1, -0x03,0xc0,0x8c,0xe0,0xfb,0xff,0xff,0x1a,0x06,0x60,0x8c,0xe0,0xda,0xff,0xff,0xea, -0x02,0x00,0x12,0x00,0x00,0x30,0xa0,0xe1,0xf0,0x01,0x2d,0xe9,0x0c,0xc0,0x93,0xe5, -0x00,0x00,0xa0,0xe3,0x01,0x50,0xa0,0xe3,0x00,0x20,0xa0,0xe1,0x8c,0x52,0xc3,0xe5, -0xa3,0x1f,0x83,0xe2,0x00,0x40,0xa0,0xe1,0x04,0x80,0xa0,0xe3,0x2c,0x74,0xa0,0xe1, -0x2c,0x68,0xa0,0xe1,0x2c,0x5c,0xa0,0xe1,0x8d,0x02,0xc3,0xe5,0x8e,0x02,0xc3,0xe5, -0x8f,0x02,0xc3,0xe5,0x90,0x82,0xc3,0xe5,0x91,0x02,0xc3,0xe5,0x92,0x02,0xc3,0xe5, -0x93,0x02,0xc3,0xe5,0x94,0xc2,0xc3,0xe5,0x95,0x72,0xc3,0xe5,0x96,0x62,0xc3,0xe5, -0x97,0x52,0xc3,0xe5,0x02,0x00,0xd1,0xe7,0x01,0x20,0x82,0xe2,0x0c,0x00,0x52,0xe3, -0x00,0x40,0x84,0xe0,0xfa,0xff,0xff,0x1a,0x00,0x40,0x64,0xe2,0x00,0x00,0x93,0xe5, -0x24,0x28,0xa0,0xe1,0x24,0x54,0xa0,0xe1,0x24,0xcc,0xa0,0xe1,0x98,0x42,0xc3,0xe5, -0x9a,0x22,0xc3,0xe5,0x10,0x20,0xa0,0xe3,0x99,0x52,0xc3,0xe5,0x9b,0xc2,0xc3,0xe5, -0x00,0x30,0xa0,0xe3,0xf0,0x01,0xbd,0xe8,0x9c,0x0a,0x00,0xea,0x70,0x40,0x2d,0xe9, -0x01,0x50,0xa0,0xe1,0x01,0x50,0x45,0xe2,0x00,0x40,0xa0,0xe1,0x02,0x60,0xa0,0xe1, -0xcf,0xff,0xff,0xeb,0x23,0x00,0x55,0xe3,0x05,0xf1,0x8f,0x90,0xf7,0x00,0x00,0xea, -0xf8,0x00,0x00,0xea,0x21,0x00,0x00,0xea,0x20,0x00,0x00,0xea,0xf3,0x00,0x00,0xea, -0xf2,0x00,0x00,0xea,0xf1,0x00,0x00,0xea,0xf0,0x00,0x00,0xea,0xef,0x00,0x00,0xea, -0xee,0x00,0x00,0xea,0xed,0x00,0x00,0xea,0xec,0x00,0x00,0xea,0xeb,0x00,0x00,0xea, -0xea,0x00,0x00,0xea,0xe9,0x00,0x00,0xea,0xe8,0x00,0x00,0xea,0x22,0x00,0x00,0xea, -0xe6,0x00,0x00,0xea,0x58,0x00,0x00,0xea,0xe4,0x00,0x00,0xea,0x7c,0x00,0x00,0xea, -0xe2,0x00,0x00,0xea,0xe1,0x00,0x00,0xea,0xe0,0x00,0x00,0xea,0x9e,0x00,0x00,0xea, -0xde,0x00,0x00,0xea,0xdd,0x00,0x00,0xea,0xdc,0x00,0x00,0xea,0xdb,0x00,0x00,0xea, -0xda,0x00,0x00,0xea,0xd9,0x00,0x00,0xea,0xa7,0x00,0x00,0xea,0xa6,0x00,0x00,0xea, -0xd6,0x00,0x00,0xea,0xb8,0x00,0x00,0xea,0xd4,0x00,0x00,0xea,0x6f,0x01,0x00,0xea, -0x00,0x30,0x96,0xe5,0x04,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xbd,0x31,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5, -0x03,0x30,0xd6,0xe5,0xbf,0x31,0xc4,0xe5,0x04,0x00,0xa0,0xe1,0x6f,0x1f,0x84,0xe2, -0x00,0x30,0xa0,0xe3,0x70,0x40,0xbd,0xe8,0xf0,0xfe,0xff,0xea,0x08,0x30,0x96,0xe5, -0x18,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xbd,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5,0x0b,0x30,0xd6,0xe5, -0xbf,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0xc0,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xc1,0x31,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5, -0x0f,0x30,0xd6,0xe5,0xc3,0x31,0xc4,0xe5,0x10,0x30,0x96,0xe5,0xc4,0x31,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc5,0x31,0xc4,0xe5,0xb2,0x31,0xd6,0xe1, -0xc6,0x31,0xc4,0xe5,0x13,0x30,0xd6,0xe5,0xc7,0x31,0xc4,0xe5,0x14,0x30,0x96,0xe5, -0xc8,0x31,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc9,0x31,0xc4,0xe5, -0xb6,0x31,0xd6,0xe1,0xca,0x31,0xc4,0xe5,0x17,0x30,0xd6,0xe5,0xcb,0x31,0xc4,0xe5, -0x18,0x30,0x96,0xe5,0xcc,0x31,0xc4,0xe5,0x18,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xcd,0x31,0xc4,0xe5,0xba,0x31,0xd6,0xe1,0xce,0x31,0xc4,0xe5,0x1b,0x30,0xd6,0xe5, -0xcf,0x31,0xc4,0xe5,0x1c,0x30,0x96,0xe5,0xd0,0x31,0xc4,0xe5,0x1c,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xd1,0x31,0xc4,0xe5,0xbe,0x31,0xd6,0xe1,0xd2,0x31,0xc4,0xe5, -0x1f,0x30,0xd6,0xe5,0xd3,0x31,0xc4,0xe5,0xc2,0xff,0xff,0xea,0x08,0x30,0x96,0xe5, -0x10,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xbd,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5,0x0b,0x30,0xd6,0xe5, -0xbf,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0xc0,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xc1,0x31,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5, -0x0f,0x30,0xd6,0xe5,0xc3,0x31,0xc4,0xe5,0x10,0x30,0x96,0xe5,0xc4,0x31,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc5,0x31,0xc4,0xe5,0xb2,0x31,0xd6,0xe1, -0xc6,0x31,0xc4,0xe5,0x13,0x30,0xd6,0xe5,0xc7,0x31,0xc4,0xe5,0x14,0x30,0x96,0xe5, -0xc8,0x31,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc9,0x31,0xc4,0xe5, -0xb6,0x31,0xd6,0xe1,0xca,0x31,0xc4,0xe5,0x17,0x30,0xd6,0xe5,0xcb,0x31,0xc4,0xe5, -0x9c,0xff,0xff,0xea,0x00,0x30,0x96,0xe5,0x10,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5, -0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xbd,0x31,0xc4,0xe5,0xb2,0x30,0xd6,0xe1, -0xbe,0x31,0xc4,0xe5,0x03,0x30,0xd6,0xe5,0xbf,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5, -0xc0,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc1,0x31,0xc4,0xe5, -0xb6,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5,0x07,0x30,0xd6,0xe5,0xc3,0x31,0xc4,0xe5, -0x0c,0x30,0x96,0xe5,0xc4,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xc5,0x31,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0xc6,0x31,0xc4,0xe5,0x0f,0x30,0xd6,0xe5, -0xc7,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0xc8,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xc9,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0xca,0x31,0xc4,0xe5, -0x0b,0x30,0xd6,0xe5,0xcb,0x31,0xc4,0xe5,0x76,0xff,0xff,0xea,0x08,0x30,0x96,0xe5, -0x01,0x30,0x43,0xe2,0x04,0x00,0x53,0xe3,0x00,0x20,0xa0,0x83,0x71,0xff,0xff,0x8a, -0x04,0x30,0x96,0xe5,0x04,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xbd,0x31,0xc4,0xe5,0xb6,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5, -0x07,0x30,0xd6,0xe5,0xbf,0x31,0xc4,0xe5,0x66,0xff,0xff,0xea,0x08,0x30,0x96,0xe5, -0x08,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x33,0x32,0xa0,0xe1, -0xbd,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5,0x0b,0x30,0xd6,0xe5, -0xbf,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0xc0,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x33,0x32,0xa0,0xe1,0xc1,0x31,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5, -0x0f,0x30,0xd6,0xe5,0xc3,0x31,0xc4,0xe5,0x52,0xff,0xff,0xea,0x00,0x30,0x96,0xe5, -0x0c,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xbd,0x31,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5,0x03,0x30,0xd6,0xe5, -0xbf,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5,0xc0,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xc1,0x31,0xc4,0xe5,0xb6,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5, -0x07,0x30,0xd6,0xe5,0xc3,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0xc4,0x31,0xc4,0xe5, -0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc5,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1, -0xc6,0x31,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0xc7,0x31,0xc4,0xe5,0x35,0xff,0xff,0xea, -0x00,0x00,0xa0,0xe3,0x70,0x80,0xbd,0xe8,0x00,0x30,0x96,0xe5,0x48,0x20,0xa0,0xe3, -0xbc,0x31,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xbd,0x31,0xc4,0xe5, -0xb2,0x30,0xd6,0xe1,0xbe,0x31,0xc4,0xe5,0x03,0x30,0xd6,0xe5,0xbf,0x31,0xc4,0xe5, -0x04,0x30,0x96,0xe5,0xc0,0x31,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xc1,0x31,0xc4,0xe5,0xb6,0x30,0xd6,0xe1,0xc2,0x31,0xc4,0xe5,0x07,0x30,0xd6,0xe5, -0xc3,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5,0xc4,0x31,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xc5,0x31,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0xc6,0x31,0xc4,0xe5, -0x0b,0x30,0xd6,0xe5,0xc7,0x31,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0xc8,0x31,0xc4,0xe5, -0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xc9,0x31,0xc4,0xe5,0xbe,0x30,0xd6,0xe1, -0xca,0x31,0xc4,0xe5,0x0f,0x30,0xd6,0xe5,0xcb,0x31,0xc4,0xe5,0x10,0x30,0x96,0xe5, -0xcc,0x31,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xcd,0x31,0xc4,0xe5, -0xb2,0x31,0xd6,0xe1,0xce,0x31,0xc4,0xe5,0x13,0x30,0xd6,0xe5,0xcf,0x31,0xc4,0xe5, -0x14,0x30,0x96,0xe5,0xd0,0x31,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xd1,0x31,0xc4,0xe5,0xb6,0x31,0xd6,0xe1,0xd2,0x31,0xc4,0xe5,0x17,0x30,0xd6,0xe5, -0xd3,0x31,0xc4,0xe5,0x18,0x30,0x96,0xe5,0xd4,0x31,0xc4,0xe5,0x18,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xd5,0x31,0xc4,0xe5,0xba,0x31,0xd6,0xe1,0xd6,0x31,0xc4,0xe5, -0x1b,0x30,0xd6,0xe5,0xd7,0x31,0xc4,0xe5,0x1c,0x30,0x96,0xe5,0xd8,0x31,0xc4,0xe5, -0x1c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xd9,0x31,0xc4,0xe5,0xbe,0x31,0xd6,0xe1, -0xda,0x31,0xc4,0xe5,0x1f,0x30,0xd6,0xe5,0xdb,0x31,0xc4,0xe5,0x20,0x30,0x96,0xe5, -0xdc,0x31,0xc4,0xe5,0x20,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xdd,0x31,0xc4,0xe5, -0xb2,0x32,0xd6,0xe1,0xde,0x31,0xc4,0xe5,0x23,0x30,0xd6,0xe5,0xdf,0x31,0xc4,0xe5, -0x24,0x30,0x96,0xe5,0xe0,0x31,0xc4,0xe5,0x24,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xe1,0x31,0xc4,0xe5,0xb6,0x32,0xd6,0xe1,0xe2,0x31,0xc4,0xe5,0x27,0x30,0xd6,0xe5, -0xe3,0x31,0xc4,0xe5,0x28,0x30,0x96,0xe5,0xe4,0x31,0xc4,0xe5,0x28,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xe5,0x31,0xc4,0xe5,0xba,0x32,0xd6,0xe1,0xe6,0x31,0xc4,0xe5, -0x2b,0x30,0xd6,0xe5,0xe7,0x31,0xc4,0xe5,0x2c,0x30,0x96,0xe5,0xe8,0x31,0xc4,0xe5, -0x2c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xe9,0x31,0xc4,0xe5,0xbe,0x32,0xd6,0xe1, -0xea,0x31,0xc4,0xe5,0x2f,0x30,0xd6,0xe5,0xeb,0x31,0xc4,0xe5,0x34,0x30,0x96,0xe5, -0xec,0x31,0xc4,0xe5,0x34,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xed,0x31,0xc4,0xe5, -0xb6,0x33,0xd6,0xe1,0xee,0x31,0xc4,0xe5,0x37,0x30,0xd6,0xe5,0xef,0x31,0xc4,0xe5, -0x30,0x30,0xd6,0xe5,0xf0,0x31,0xc4,0xe5,0x31,0x30,0xd6,0xe5,0xf1,0x31,0xc4,0xe5, -0x32,0x30,0xd6,0xe5,0xf2,0x31,0xc4,0xe5,0x38,0x30,0xd6,0xe5,0xf3,0x31,0xc4,0xe5, -0x3c,0x30,0x96,0xe5,0xf4,0x31,0xc4,0xe5,0x3c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0xf5,0x31,0xc4,0xe5,0xbe,0x33,0xd6,0xe1,0xf6,0x31,0xc4,0xe5,0x3f,0x30,0xd6,0xe5, -0xf7,0x31,0xc4,0xe5,0x40,0x30,0x96,0xe5,0xf8,0x31,0xc4,0xe5,0x40,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xf9,0x31,0xc4,0xe5,0xb2,0x34,0xd6,0xe1,0xfa,0x31,0xc4,0xe5, -0x43,0x30,0xd6,0xe5,0xfb,0x31,0xc4,0xe5,0x44,0x30,0x96,0xe5,0xfc,0x31,0xc4,0xe5, -0x44,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0xfd,0x31,0xc4,0xe5,0xb6,0x34,0xd6,0xe1, -0xfe,0x31,0xc4,0xe5,0x47,0x30,0xd6,0xe5,0xff,0x31,0xc4,0xe5,0x99,0xfe,0xff,0xea, -0x60,0x30,0x96,0xe5,0x04,0x20,0xa0,0xe3,0xbc,0x31,0xc4,0xe5,0x60,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0xbd,0x31,0xc4,0xe5,0xb2,0x36,0xd6,0xe1,0xbe,0x31,0xc4,0xe5, -0x63,0x30,0xd6,0xe5,0xbf,0x31,0xc4,0xe5,0x8e,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe1, -0xf0,0x0f,0x2d,0xe9,0x0c,0xc0,0x93,0xe5,0x21,0x2c,0xa0,0xe1,0x21,0x64,0xa0,0xe1, -0x21,0xb8,0xa0,0xe1,0x98,0x12,0xc3,0xe5,0x01,0x90,0xa0,0xe3,0x00,0x00,0xa0,0xe3, -0x2c,0xa4,0xa0,0xe1,0x2c,0x88,0xa0,0xe1,0x2c,0x7c,0xa0,0xe1,0x8c,0x92,0xc3,0xe5, -0x08,0xd0,0x4d,0xe2,0x8d,0x02,0xc3,0xe5,0x05,0x90,0xa0,0xe3,0x04,0x20,0x8d,0xe5, -0x8e,0x02,0xc3,0xe5,0x00,0x40,0xa0,0xe1,0x8f,0x02,0xc3,0xe5,0xa3,0x2f,0x83,0xe2, -0x90,0x92,0xc3,0xe5,0x00,0x50,0xa0,0xe1,0x91,0x02,0xc3,0xe5,0x92,0x02,0xc3,0xe5, -0x93,0x02,0xc3,0xe5,0x94,0xc2,0xc3,0xe5,0x95,0xa2,0xc3,0xe5,0x96,0x82,0xc3,0xe5, -0x97,0x72,0xc3,0xe5,0x99,0x62,0xc3,0xe5,0x9a,0xb2,0xc3,0xe5,0x04,0x10,0x9d,0xe5, -0x9b,0x12,0xc3,0xe5,0x04,0x10,0xd2,0xe7,0x01,0x40,0x84,0xe2,0x10,0x00,0x54,0xe3, -0x01,0x50,0x85,0xe0,0xfa,0xff,0xff,0x1a,0x00,0x50,0x65,0xe2,0x00,0x00,0x93,0xe5, -0x25,0x14,0xa0,0xe1,0x25,0x48,0xa0,0xe1,0x25,0xcc,0xa0,0xe1,0x9c,0x52,0xc3,0xe5, -0x9d,0x12,0xc3,0xe5,0x02,0x10,0xa0,0xe1,0x9e,0x42,0xc3,0xe5,0x14,0x20,0xa0,0xe3, -0x9f,0xc2,0xc3,0xe5,0x00,0x30,0xa0,0xe3,0x08,0xd0,0x8d,0xe2,0xf0,0x0f,0xbd,0xe8, -0xbe,0x08,0x00,0xea,0x10,0xc0,0x90,0xe5,0xf0,0x4f,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0x34,0xd0,0x4d,0xe2,0x01,0x50,0xa0,0xe1,0x00,0x00,0x5c,0xe3,0x02,0x60,0xa0,0xe1, -0x03,0x70,0xa0,0xe1,0x32,0x00,0x00,0x0a,0x0c,0x00,0x56,0xe1,0x0c,0x60,0xa0,0x21, -0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x05,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xd7,0x08,0x00,0xeb,0x00,0x80,0x50,0xe2, -0x21,0x00,0x00,0x1a,0x00,0x00,0x57,0xe3,0x00,0x60,0x87,0x15,0x00,0x00,0x56,0xe3, -0x14,0x00,0x94,0xe5,0x06,0x20,0xa0,0x01,0x06,0x00,0x00,0x0a,0x00,0x30,0xa0,0xe3, -0x03,0x20,0xa0,0xe1,0x03,0x10,0xd5,0xe7,0x01,0x30,0x83,0xe2,0x03,0x00,0x56,0xe1, -0x01,0x20,0x82,0xe0,0xfa,0xff,0xff,0x8a,0x10,0x30,0x94,0xe5,0x00,0x20,0x82,0xe0, -0x14,0x20,0x84,0xe5,0x03,0x60,0x66,0xe0,0x00,0x00,0x56,0xe3,0x10,0x60,0x84,0xe5, -0x10,0x00,0x00,0x1a,0x00,0x00,0x94,0xe5,0x2c,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3, -0x06,0x30,0xa0,0xe1,0x00,0x60,0x8d,0xe5,0xbb,0x08,0x00,0xeb,0x00,0x80,0x50,0xe2, -0x05,0x00,0x00,0x1a,0x14,0x30,0x94,0xe5,0x2c,0x20,0x9d,0xe5,0x03,0x30,0x82,0xe0, -0x00,0x00,0x53,0xe3,0x6f,0x00,0x00,0x0a,0x12,0x88,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x03,0x10,0xa0,0xe3,0x90,0xff,0xff,0xeb,0x08,0x00,0xa0,0xe1,0x34,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x1c,0x80,0x84,0xe2,0x00,0x00,0x90,0xe5,0x0c,0x30,0xa0,0xe1, -0x08,0x10,0xa0,0xe1,0x0c,0x20,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0xa6,0x08,0x00,0xeb, -0x00,0x30,0x50,0xe2,0xef,0xff,0xff,0x1a,0x1e,0x20,0xd4,0xe5,0x1d,0xc0,0xd4,0xe5, -0x1c,0xa0,0xd4,0xe5,0x1f,0x00,0xd4,0xe5,0x02,0x28,0xa0,0xe1,0x23,0x90,0xd4,0xe5, -0x20,0xb0,0xd4,0xe5,0x0c,0x24,0x82,0xe1,0x21,0x10,0xd4,0xe5,0x22,0xc0,0xd4,0xe5, -0x0a,0x20,0x82,0xe1,0x18,0x90,0x8d,0xe5,0x00,0x0c,0x82,0xe1,0x25,0x20,0xd4,0xe5, -0x24,0xa0,0xd4,0xe5,0x01,0x00,0x50,0xe3,0x27,0x00,0xd4,0xe5,0x14,0x20,0x8d,0xe5, -0x26,0x20,0xd4,0xe5,0xdb,0xff,0xff,0x1a,0x02,0x28,0xa0,0xe1,0x14,0x90,0x9d,0xe5, -0x0c,0x30,0x8d,0xe5,0x1c,0x20,0x8d,0xe5,0x03,0x20,0xa0,0xe1,0x1c,0x30,0x9d,0xe5, -0x09,0x34,0x83,0xe1,0x0a,0x90,0x83,0xe1,0x1c,0x30,0x8d,0xe5,0x00,0x9c,0x89,0xe1, -0x02,0x30,0xa0,0xe1,0x0c,0x90,0x84,0xe5,0x03,0x00,0xd8,0xe7,0x01,0x30,0x83,0xe2, -0x0c,0x00,0x53,0xe3,0x00,0x20,0x82,0xe0,0xfa,0xff,0xff,0x1a,0x0c,0xc8,0xa0,0xe1, -0x14,0x20,0x84,0xe5,0x18,0x20,0x9d,0xe5,0x01,0x14,0x8c,0xe1,0x0b,0xb0,0x81,0xe1, -0x02,0xbc,0x8b,0xe1,0x02,0x00,0x5b,0xe3,0x10,0x00,0x00,0x0a,0x04,0x30,0x4b,0xe2, -0x01,0x00,0x53,0xe3,0x12,0x88,0xa0,0x83,0xc2,0xff,0xff,0x8a,0x05,0x00,0x5b,0xe3, -0x2f,0x00,0x00,0x0a,0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x24,0x10,0x8d,0xe2, -0x04,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x6a,0x08,0x00,0xeb, -0x00,0x00,0x50,0xe3,0xc8,0x80,0x9f,0xe5,0x00,0x80,0xa0,0x11,0xb5,0xff,0xff,0xea, -0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x08,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x5f,0x08,0x00,0xeb,0x00,0x80,0x50,0xe2, -0xa9,0xff,0xff,0x1a,0x1e,0x20,0xd4,0xe5,0x1d,0x00,0xd4,0xe5,0x1c,0x30,0xd4,0xe5, -0x1f,0x10,0xd4,0xe5,0x02,0x28,0xa0,0xe1,0x00,0x24,0x82,0xe1,0x03,0x30,0x82,0xe1, -0x01,0x1c,0x83,0xe1,0x00,0x00,0x51,0xe3,0x28,0x10,0x8d,0xe5,0x74,0x80,0x9f,0x05, -0x9d,0xff,0xff,0x0a,0x14,0xc0,0x94,0xe5,0x28,0x30,0x8d,0xe2,0x04,0x00,0x83,0xe2, -0x01,0x20,0xd3,0xe4,0x00,0x00,0x53,0xe1,0x02,0x80,0x88,0xe0,0xfb,0xff,0xff,0x1a, -0x0c,0x80,0x88,0xe0,0x10,0x10,0x84,0xe5,0x14,0x80,0x84,0xe5,0x06,0x00,0x51,0xe1, -0x01,0x60,0xa0,0x31,0x65,0xff,0xff,0xea,0x04,0x00,0xa0,0xe1,0x50,0xfd,0xff,0xeb, -0x90,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x20,0x10,0x8d,0xe2, -0x04,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x3a,0x08,0x00,0xeb, -0x00,0x80,0x50,0xe2,0x87,0xff,0xff,0x1a,0x20,0x30,0x9d,0xe5,0x18,0x30,0x84,0xe5, -0xc3,0xff,0xff,0xea,0x01,0x00,0x12,0x00,0x03,0x00,0x12,0x00,0xf0,0x4f,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0x04,0x00,0x90,0xe5,0x02,0x60,0xa0,0xe1,0x00,0x30,0xa0,0xe3, -0x01,0xc0,0xa0,0xe3,0x01,0x80,0x41,0xe2,0x54,0xd0,0x4d,0xe2,0x1c,0x50,0x84,0xe2, -0x1c,0xc0,0xc4,0xe5,0x20,0x74,0xa0,0xe1,0x20,0xe8,0xa0,0xe1,0x20,0x2c,0xa0,0xe1, -0x1d,0x30,0xc4,0xe5,0x1e,0x30,0xc4,0xe5,0x1f,0x30,0xc4,0xe5,0x20,0xc0,0xc4,0xe5, -0x21,0x30,0xc4,0xe5,0x22,0x30,0xc4,0xe5,0x23,0x30,0xc4,0xe5,0x24,0x00,0xc4,0xe5, -0x25,0x70,0xc4,0xe5,0x26,0xe0,0xc4,0xe5,0x27,0x20,0xc4,0xe5,0x23,0x00,0x58,0xe3, -0x08,0xf1,0x8f,0x90,0x23,0x00,0x00,0xea,0x02,0x03,0x00,0xea,0x01,0x03,0x00,0xea, -0x00,0x03,0x00,0xea,0xfb,0x02,0x00,0xea,0xda,0x02,0x00,0xea,0xa7,0x02,0x00,0xea, -0x9c,0x02,0x00,0xea,0x89,0x02,0x00,0xea,0x7e,0x02,0x00,0xea,0x4d,0x02,0x00,0xea, -0x42,0x02,0x00,0xea,0x37,0x02,0x00,0xea,0xf6,0x02,0x00,0xea,0x2b,0x02,0x00,0xea, -0x01,0x02,0x00,0xea,0xf6,0x01,0x00,0xea,0x6b,0x01,0x00,0xea,0x2f,0x01,0x00,0xea, -0xf3,0x00,0x00,0xea,0x8d,0x00,0x00,0xea,0xee,0x02,0x00,0xea,0xed,0x02,0x00,0xea, -0xec,0x02,0x00,0xea,0x7f,0x00,0x00,0xea,0xea,0x02,0x00,0xea,0xe9,0x02,0x00,0xea, -0xe2,0x00,0x00,0xea,0xe1,0x00,0x00,0xea,0xe6,0x02,0x00,0xea,0x59,0x00,0x00,0xea, -0xbe,0x00,0x00,0xea,0xbd,0x00,0x00,0xea,0xb2,0x00,0x00,0xea,0xe1,0x02,0x00,0xea, -0xc3,0x00,0x00,0xea,0x1c,0x00,0x00,0xea,0x18,0x20,0xa0,0xe3,0x14,0xa0,0xa0,0xe3, -0x00,0x30,0xa0,0xe3,0x03,0x70,0xa0,0xe1,0x03,0x10,0xd5,0xe7,0x01,0x30,0x83,0xe2, -0x0a,0x00,0x53,0xe1,0x01,0x70,0x87,0xe0,0xfa,0xff,0xff,0x3a,0x00,0x70,0x67,0xe2, -0x0a,0x00,0x84,0xe0,0x27,0x34,0xa0,0xe1,0x27,0xe8,0xa0,0xe1,0x27,0xcc,0xa0,0xe1, -0x1c,0x00,0x80,0xe2,0x0a,0xa0,0x84,0xe0,0x05,0x10,0xa0,0xe1,0x1c,0x70,0xca,0xe5, -0x01,0x30,0xc0,0xe5,0x00,0x30,0xa0,0xe3,0x02,0xe0,0xc0,0xe5,0x03,0xc0,0xc0,0xe5, -0x00,0x00,0x94,0xe5,0xb1,0x07,0x00,0xeb,0x00,0x70,0x50,0xe2,0x6c,0x03,0x00,0x0a, -0x07,0x00,0xa0,0xe1,0x54,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x00,0x30,0xa0,0xe3, -0x24,0xc0,0xa0,0xe3,0x60,0x00,0xa0,0xe3,0x30,0x70,0x84,0xe2,0x20,0x20,0xa0,0xe3, -0x03,0x10,0xa0,0xe1,0x28,0x00,0xc4,0xe5,0x07,0x00,0xa0,0xe1,0x29,0x30,0xc4,0xe5, -0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5,0x2c,0xc0,0xc4,0xe5,0x2d,0x30,0xc4,0xe5, -0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x42,0x45,0x00,0xeb,0x06,0x00,0xa0,0xe1, -0x3d,0x45,0x00,0xeb,0x1e,0x00,0x50,0xe3,0x1f,0x20,0xa0,0x83,0xf8,0x03,0x00,0x9a, -0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x50,0xa0,0x84,0xe2,0x20,0x70,0x86,0xe2, -0x36,0x45,0x00,0xeb,0x20,0x20,0xa0,0xe3,0x0a,0x00,0xa0,0xe1,0x00,0x10,0xa0,0xe3, -0x34,0x45,0x00,0xeb,0x07,0x00,0xa0,0xe1,0x2f,0x45,0x00,0xeb,0x1e,0x00,0x50,0xe3, -0x1f,0x20,0xa0,0x83,0xe6,0x03,0x00,0x9a,0x0a,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1, -0x70,0xa0,0x84,0xe2,0x40,0x70,0x86,0xe2,0x28,0x45,0x00,0xeb,0x20,0x20,0xa0,0xe3, -0x0a,0x00,0xa0,0xe1,0x00,0x10,0xa0,0xe3,0x26,0x45,0x00,0xeb,0x07,0x00,0xa0,0xe1, -0x21,0x45,0x00,0xeb,0x1e,0x00,0x50,0xe3,0x1f,0x20,0xa0,0x83,0xd4,0x03,0x00,0x9a, -0x0a,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x1c,0x45,0x00,0xeb,0x74,0xa0,0xa0,0xe3, -0x78,0x20,0xa0,0xe3,0xad,0xff,0xff,0xea,0x08,0x20,0xa0,0xe3,0x1c,0xa0,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x1e,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3, -0x29,0x30,0xc4,0xe5,0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5, -0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5, -0xb2,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5, -0x04,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x35,0x30,0xc4,0xe5,0xb6,0x30,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x07,0x30,0xd6,0xe5, -0x37,0x30,0xc4,0xe5,0x8d,0xff,0xff,0xea,0x08,0x30,0x96,0xe5,0x05,0x00,0x53,0xe3, -0x03,0xf1,0x8f,0x90,0x87,0xff,0xff,0xea,0xd2,0x02,0x00,0xea,0xa8,0x02,0x00,0xea, -0x70,0x02,0x00,0xea,0x6f,0x02,0x00,0xea,0x8e,0x02,0x00,0xea,0x8d,0x02,0x00,0xea, -0x00,0x30,0xa0,0xe3,0x10,0x20,0xa0,0xe3,0x14,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x29,0x30,0xc4,0xe5,0x28,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x24,0xa0,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5, -0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5, -0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5,0xb6,0x30,0xd6,0xe1, -0x36,0x30,0xc4,0xe5,0x07,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x38,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x39,0x30,0xc4,0xe5, -0xbe,0x30,0xd6,0xe1,0x3a,0x30,0xc4,0xe5,0x0f,0x30,0xd6,0xe5,0x3b,0x30,0xc4,0xe5, -0x08,0x30,0x96,0xe5,0x3c,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x3d,0x30,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0x3e,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5, -0x3f,0x30,0xc4,0xe5,0x51,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x1c,0xa0,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x20,0x20,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x21,0x10,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0xa2,0xff,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x1c,0xa0,0xa0,0xe3, -0x20,0x20,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5, -0x99,0xff,0xff,0xea,0x04,0x20,0xa0,0xe3,0x18,0xa0,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x23,0x10,0xa0,0xe3,0x1c,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x29,0x30,0xc4,0xe5, -0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5, -0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5, -0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1, -0x32,0x30,0xc4,0xe5,0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x27,0xff,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x1c,0x20,0xa0,0xe3, -0x29,0x30,0xc4,0xe5,0x18,0xa0,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5, -0xe8,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3,0x14,0x20,0xa0,0xe3,0x13,0x10,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5,0x2c,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5, -0x28,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5, -0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5, -0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1, -0x32,0x30,0xc4,0xe5,0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5, -0x34,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5, -0xb6,0x30,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x07,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5, -0x08,0x30,0x96,0xe5,0x38,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x39,0x30,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0x3a,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5, -0x3b,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x3c,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x3d,0x30,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0x3e,0x30,0xc4,0xe5, -0x0f,0x30,0xd6,0xe5,0x3f,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x40,0x30,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x41,0x30,0xc4,0xe5,0xb2,0x31,0xd6,0xe1, -0x42,0x30,0xc4,0xe5,0x13,0x30,0xd6,0xe5,0x43,0x30,0xc4,0xe5,0xe3,0xfe,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x14,0x20,0xa0,0xe3,0x12,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x29,0x30,0xc4,0xe5,0x2c,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x28,0xa0,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5, -0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5, -0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5,0xba,0x30,0xd6,0xe1, -0x36,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5, -0x38,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x39,0x30,0xc4,0xe5, -0xbe,0x30,0xd6,0xe1,0x3a,0x30,0xc4,0xe5,0x0f,0x30,0xd6,0xe5,0x3b,0x30,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x3c,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x3d,0x30,0xc4,0xe5,0xb2,0x31,0xd6,0xe1,0x3e,0x30,0xc4,0xe5,0x13,0x30,0xd6,0xe5, -0x3f,0x30,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x40,0x30,0xc4,0xe5,0x14,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x41,0x30,0xc4,0xe5,0xb6,0x31,0xd6,0xe1,0x42,0x30,0xc4,0xe5, -0x17,0x30,0xd6,0xe5,0x43,0x30,0xc4,0xe5,0xa8,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3, -0x11,0xc0,0xa0,0xe3,0x50,0x00,0xa0,0xe3,0x30,0x70,0x84,0xe2,0x20,0x20,0xa0,0xe3, -0x03,0x10,0xa0,0xe1,0x28,0x00,0xc4,0xe5,0x07,0x00,0xa0,0xe1,0x29,0x30,0xc4,0xe5, -0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5,0x2c,0xc0,0xc4,0xe5,0x2d,0x30,0xc4,0xe5, -0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x06,0x44,0x00,0xeb,0x06,0x00,0xa0,0xe1, -0x01,0x44,0x00,0xeb,0x1e,0x00,0x50,0xe3,0x1f,0x20,0xa0,0x83,0x02,0x00,0x00,0x8a, -0x06,0x00,0xa0,0xe1,0xfc,0x43,0x00,0xeb,0x00,0x20,0xa0,0xe1,0x07,0x00,0xa0,0xe1, -0x06,0x10,0xa0,0xe1,0xf9,0x43,0x00,0xeb,0x20,0x30,0x96,0xe5,0x68,0x20,0xa0,0xe3, -0x64,0xa0,0xa0,0xe3,0x50,0x30,0xc4,0xe5,0x20,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x51,0x30,0xc4,0xe5,0xb2,0x32,0xd6,0xe1,0x52,0x30,0xc4,0xe5,0x23,0x30,0xd6,0xe5, -0x53,0x30,0xc4,0xe5,0x24,0x30,0x96,0xe5,0x54,0x30,0xc4,0xe5,0x24,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x55,0x30,0xc4,0xe5,0xb6,0x32,0xd6,0xe1,0x56,0x30,0xc4,0xe5, -0x27,0x30,0xd6,0xe5,0x57,0x30,0xc4,0xe5,0x28,0x30,0x96,0xe5,0x58,0x30,0xc4,0xe5, -0x28,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x59,0x30,0xc4,0xe5,0xba,0x32,0xd6,0xe1, -0x5a,0x30,0xc4,0xe5,0x2b,0x30,0xd6,0xe5,0x5b,0x30,0xc4,0xe5,0x2c,0x30,0x96,0xe5, -0x5c,0x30,0xc4,0xe5,0x2c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x5d,0x30,0xc4,0xe5, -0xbe,0x32,0xd6,0xe1,0x5e,0x30,0xc4,0xe5,0x2f,0x30,0xd6,0xe5,0x5f,0x30,0xc4,0xe5, -0x30,0x30,0x96,0xe5,0x60,0x30,0xc4,0xe5,0x30,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x61,0x30,0xc4,0xe5,0xb2,0x33,0xd6,0xe1,0x62,0x30,0xc4,0xe5,0x33,0x30,0xd6,0xe5, -0x63,0x30,0xc4,0xe5,0x34,0x30,0x96,0xe5,0x64,0x30,0xc4,0xe5,0x34,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x65,0x30,0xc4,0xe5,0xb6,0x33,0xd6,0xe1,0x66,0x30,0xc4,0xe5, -0x37,0x30,0xd6,0xe5,0x67,0x30,0xc4,0xe5,0x38,0x30,0x96,0xe5,0x68,0x30,0xc4,0xe5, -0x38,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x69,0x30,0xc4,0xe5,0xba,0x33,0xd6,0xe1, -0x6a,0x30,0xc4,0xe5,0x3b,0x30,0xd6,0xe5,0x6b,0x30,0xc4,0xe5,0x3c,0x30,0x96,0xe5, -0x6c,0x30,0xc4,0xe5,0x3c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x6d,0x30,0xc4,0xe5, -0xbe,0x33,0xd6,0xe1,0x6e,0x30,0xc4,0xe5,0x3f,0x30,0xd6,0xe5,0x6f,0x30,0xc4,0xe5, -0x40,0x30,0x96,0xe5,0x70,0x30,0xc4,0xe5,0x40,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x71,0x30,0xc4,0xe5,0xb2,0x34,0xd6,0xe1,0x72,0x30,0xc4,0xe5,0x43,0x30,0xd6,0xe5, -0x73,0x30,0xc4,0xe5,0x44,0x30,0x96,0xe5,0x74,0x30,0xc4,0xe5,0x44,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x75,0x30,0xc4,0xe5,0xb6,0x34,0xd6,0xe1,0x76,0x30,0xc4,0xe5, -0x47,0x30,0xd6,0xe5,0x77,0x30,0xc4,0xe5,0x48,0x30,0x96,0xe5,0x78,0x30,0xc4,0xe5, -0x48,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x79,0x30,0xc4,0xe5,0xba,0x34,0xd6,0xe1, -0x7a,0x30,0xc4,0xe5,0x4b,0x30,0xd6,0xe5,0x7b,0x30,0xc4,0xe5,0x4c,0x30,0x96,0xe5, -0x7c,0x30,0xc4,0xe5,0x4c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x7d,0x30,0xc4,0xe5, -0xbe,0x34,0xd6,0xe1,0x7e,0x30,0xc4,0xe5,0x4f,0x30,0xd6,0xe5,0x7f,0x30,0xc4,0xe5, -0x1e,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x18,0xa0,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5, -0x10,0x10,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0xde,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3, -0x0c,0x20,0xa0,0xe3,0x0f,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5, -0x24,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x20,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5, -0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5, -0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x03,0x30,0xd6,0xe5, -0x33,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5,0xba,0x30,0xd6,0xe1,0x36,0x30,0xc4,0xe5, -0x0b,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x38,0x30,0xc4,0xe5, -0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x39,0x30,0xc4,0xe5,0xbe,0x30,0xd6,0xe1, -0x3a,0x30,0xc4,0xe5,0x0f,0x30,0xd6,0xe5,0x3b,0x30,0xc4,0xe5,0xeb,0xfd,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x18,0xa0,0xa0,0xe3, -0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x0e,0x10,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0xab,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x18,0xa0,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x0c,0x10,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0xa1,0xfe,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x1c,0xa0,0xa0,0xe3, -0x29,0x30,0xc4,0xe5,0x20,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x0b,0x10,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0x28,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3,0x0a,0xc0,0xa0,0xe3, -0x28,0x00,0xa0,0xe3,0x30,0x70,0x84,0xe2,0x20,0x20,0xa0,0xe3,0x03,0x10,0xa0,0xe1, -0x28,0x00,0xc4,0xe5,0x07,0x00,0xa0,0xe1,0x29,0x30,0xc4,0xe5,0x2a,0x30,0xc4,0xe5, -0x2b,0x30,0xc4,0xe5,0x2c,0xc0,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x2b,0x43,0x00,0xeb,0x06,0x00,0xa0,0xe1,0x26,0x43,0x00,0xeb, -0x1e,0x00,0x50,0xe3,0x1f,0x20,0xa0,0x83,0x02,0x00,0x00,0x8a,0x06,0x00,0xa0,0xe1, -0x21,0x43,0x00,0xeb,0x00,0x20,0xa0,0xe1,0x07,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1, -0x1e,0x43,0x00,0xeb,0x20,0x30,0x96,0xe5,0x40,0x20,0xa0,0xe3,0x3c,0xa0,0xa0,0xe3, -0x50,0x30,0xc4,0xe5,0x20,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x51,0x30,0xc4,0xe5, -0xb2,0x32,0xd6,0xe1,0x52,0x30,0xc4,0xe5,0x23,0x30,0xd6,0xe5,0x53,0x30,0xc4,0xe5, -0x24,0x30,0x96,0xe5,0x54,0x30,0xc4,0xe5,0x24,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x55,0x30,0xc4,0xe5,0xb6,0x32,0xd6,0xe1,0x56,0x30,0xc4,0xe5,0x27,0x30,0xd6,0xe5, -0x57,0x30,0xc4,0xe5,0x9d,0xfd,0xff,0xea,0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x18,0xa0,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x09,0x10,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x5d,0xfe,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3,0x08,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x18,0xa0,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x33,0x31,0xa0,0xe1,0x53,0xfe,0xff,0xea,0x00,0x30,0xa0,0xe3,0x04,0x20,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x18,0xa0,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x1c,0x20,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x07,0x10,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x41,0xfe,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x10,0x20,0xa0,0xe3,0x06,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5, -0x29,0x30,0xc4,0xe5,0x28,0x20,0xa0,0xe3,0x2a,0x30,0xc4,0xe5,0x24,0xa0,0xa0,0xe3, -0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5, -0x03,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5, -0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5,0xb6,0x30,0xd6,0xe1, -0x36,0x30,0xc4,0xe5,0x07,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x38,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x39,0x30,0xc4,0xe5, -0xba,0x30,0xd6,0xe1,0x3a,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x3b,0x30,0xc4,0xe5, -0x0c,0x30,0x96,0xe5,0x3c,0x30,0xc4,0xe5,0x0c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x3d,0x30,0xc4,0xe5,0xbe,0x30,0xd6,0xe1,0x3e,0x30,0xc4,0xe5,0x0f,0x30,0xd6,0xe5, -0x3f,0x30,0xc4,0xe5,0x45,0xfd,0xff,0xea,0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3, -0x05,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5,0x20,0x20,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x1c,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5, -0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5, -0x30,0x30,0xc4,0xe5,0x04,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5, -0xb6,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x07,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5, -0x00,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5,0x00,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x35,0x30,0xc4,0xe5,0xb2,0x30,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x03,0x30,0xd6,0xe5, -0x37,0x30,0xc4,0xe5,0x25,0xfd,0xff,0xea,0x04,0x10,0xa0,0xe3,0x00,0x30,0xa0,0xe3, -0x28,0x10,0xc4,0xe5,0xfc,0xfd,0xff,0xea,0x00,0x30,0xa0,0xe3,0x2c,0x10,0xc4,0xe5, -0x28,0x30,0xc4,0xe5,0x18,0x20,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x14,0xa0,0xa0,0xe3, -0x2a,0x30,0xc4,0xe5,0x2b,0x30,0xc4,0xe5,0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5, -0x2f,0x30,0xc4,0xe5,0x15,0xfd,0xff,0xea,0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3, -0x18,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5,0x18,0x20,0x82,0xe2, -0x2a,0x30,0xc4,0xe5,0x1c,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5, -0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x30,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5, -0xba,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x35,0x30,0xc4,0xe5,0xb2,0x31,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x13,0x30,0xd6,0xe5, -0x37,0x30,0xc4,0xe5,0xf5,0xfc,0xff,0xea,0x00,0x30,0xa0,0xe3,0x18,0x10,0xa0,0xe3, -0x04,0x20,0xa0,0xe3,0x29,0x30,0xc4,0xe5,0x28,0x20,0xc4,0xe5,0x01,0xa0,0xa0,0xe1, -0x2a,0x30,0xc4,0xe5,0x01,0x20,0x82,0xe0,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5, -0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x30,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5, -0xba,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5, -0xde,0xfc,0xff,0xea,0x00,0x30,0xa0,0xe3,0x0c,0x20,0xa0,0xe3,0x18,0x10,0xa0,0xe3, -0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5,0x18,0x20,0x82,0xe2,0x2a,0x30,0xc4,0xe5, -0x20,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5,0x2d,0x30,0xc4,0xe5, -0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x30,0x30,0xc4,0xe5, -0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5,0xba,0x30,0xd6,0xe1, -0x32,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5, -0x34,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x35,0x30,0xc4,0xe5, -0xb2,0x31,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x13,0x30,0xd6,0xe5,0x37,0x30,0xc4,0xe5, -0x14,0x30,0x96,0xe5,0x38,0x30,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x39,0x30,0xc4,0xe5,0xb6,0x31,0xd6,0xe1,0x3a,0x30,0xc4,0xe5,0x17,0x30,0xd6,0xe5, -0x3b,0x30,0xc4,0xe5,0xb5,0xfc,0xff,0xea,0x00,0x30,0xa0,0xe3,0x14,0x20,0xa0,0xe3, -0x18,0x10,0xa0,0xe3,0x28,0x20,0xc4,0xe5,0x29,0x30,0xc4,0xe5,0x18,0x20,0x82,0xe2, -0x2a,0x30,0xc4,0xe5,0x28,0xa0,0xa0,0xe3,0x2b,0x30,0xc4,0xe5,0x2c,0x10,0xc4,0xe5, -0x2d,0x30,0xc4,0xe5,0x2e,0x30,0xc4,0xe5,0x2f,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5, -0x30,0x30,0xc4,0xe5,0x08,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x31,0x30,0xc4,0xe5, -0xba,0x30,0xd6,0xe1,0x32,0x30,0xc4,0xe5,0x0b,0x30,0xd6,0xe5,0x33,0x30,0xc4,0xe5, -0x10,0x30,0x96,0xe5,0x34,0x30,0xc4,0xe5,0x10,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1, -0x35,0x30,0xc4,0xe5,0xb2,0x31,0xd6,0xe1,0x36,0x30,0xc4,0xe5,0x13,0x30,0xd6,0xe5, -0x37,0x30,0xc4,0xe5,0x14,0x30,0x96,0xe5,0x38,0x30,0xc4,0xe5,0x14,0x30,0x96,0xe5, -0x23,0x34,0xa0,0xe1,0x39,0x30,0xc4,0xe5,0xb6,0x31,0xd6,0xe1,0x3a,0x30,0xc4,0xe5, -0x17,0x30,0xd6,0xe5,0x3b,0x30,0xc4,0xe5,0x18,0x30,0x96,0xe5,0x3c,0x30,0xc4,0xe5, -0x18,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x3d,0x30,0xc4,0xe5,0xba,0x31,0xd6,0xe1, -0x3e,0x30,0xc4,0xe5,0x1b,0x30,0xd6,0xe5,0x3f,0x30,0xc4,0xe5,0x1c,0x30,0x96,0xe5, -0x40,0x30,0xc4,0xe5,0x1c,0x30,0x96,0xe5,0x23,0x34,0xa0,0xe1,0x41,0x30,0xc4,0xe5, -0xbe,0x31,0xd6,0xe1,0x42,0x30,0xc4,0xe5,0x1f,0x30,0xd6,0xe5,0x43,0x30,0xc4,0xe5, -0x7a,0xfc,0xff,0xea,0x04,0xc0,0x94,0xe5,0x01,0x30,0xa0,0xe3,0x18,0x30,0x84,0xe5, -0x05,0x10,0xa0,0xe1,0x00,0x00,0x94,0xe5,0x0c,0x20,0xa0,0xe3,0x03,0xc0,0x8c,0xe0, -0x07,0x30,0xa0,0xe1,0x04,0xc0,0x84,0xe5,0x00,0x70,0x8d,0xe5,0x62,0x04,0x00,0xeb, -0x00,0x30,0x50,0xe2,0x12,0x00,0x00,0x1a,0x1e,0xc0,0xd4,0xe5,0x1d,0xa0,0xd4,0xe5, -0x1c,0x00,0xd4,0xe5,0x1f,0x70,0xd4,0xe5,0x0c,0xc8,0xa0,0xe1,0x20,0x20,0xd4,0xe5, -0x21,0x10,0xd4,0xe5,0x0a,0xa4,0x8c,0xe1,0x23,0xb0,0xd4,0xe5,0x22,0xc0,0xd4,0xe5, -0x00,0x00,0x8a,0xe1,0x24,0x90,0xd4,0xe5,0x07,0x7c,0x80,0xe1,0x25,0x00,0xd4,0xe5, -0x26,0xa0,0xd4,0xe5,0x01,0x00,0x57,0xe3,0x27,0x70,0xd4,0xe5,0x18,0x00,0x8d,0xe5, -0x01,0x00,0x00,0x0a,0x12,0x78,0xa0,0xe3,0x70,0xfc,0xff,0xea,0x0a,0xa8,0xa0,0xe1, -0x20,0x30,0x8d,0xe5,0x10,0xa0,0x8d,0xe5,0x03,0xa0,0xa0,0xe1,0x10,0x30,0x9d,0xe5, -0x00,0x34,0x83,0xe1,0x09,0x00,0x83,0xe1,0x0a,0x30,0xa0,0xe1,0x07,0x0c,0x80,0xe1, -0x10,0x00,0x8d,0xe5,0x0c,0x00,0x84,0xe5,0x03,0x00,0xd5,0xe7,0x01,0x30,0x83,0xe2, -0x0c,0x00,0x53,0xe3,0x00,0xa0,0x8a,0xe0,0xfa,0xff,0xff,0x1a,0x0c,0xc8,0xa0,0xe1, -0x01,0x14,0x8c,0xe1,0x02,0x20,0x81,0xe1,0x0b,0x9c,0x82,0xe1,0x04,0x30,0x49,0xe2, -0x01,0x00,0x53,0xe3,0xe6,0xff,0xff,0x8a,0x05,0x00,0x59,0xe3,0x50,0x00,0x00,0x0a, -0x00,0xc0,0xa0,0xe3,0x00,0x00,0x94,0xe5,0x4c,0x10,0x8d,0xe2,0x04,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x2b,0x04,0x00,0xeb,0x00,0x70,0x50,0xe2, -0x4e,0xfc,0xff,0x1a,0x4c,0x30,0x9d,0xe5,0x03,0xa0,0x8a,0xe0,0x00,0x00,0x5a,0xe3, -0xd7,0xff,0xff,0x1a,0x04,0x30,0x94,0xe5,0x10,0xa0,0x9d,0xe5,0x01,0x30,0x43,0xe2, -0x0a,0x00,0x53,0xe1,0xd2,0xff,0xff,0x1a,0x05,0x00,0x59,0xe3,0xd4,0x7e,0x9f,0x05, -0x42,0xfc,0xff,0x0a,0x23,0x00,0x58,0xe3,0x08,0xf1,0x8f,0x90,0x36,0x00,0x00,0xea, -0x66,0x00,0x00,0xea,0x21,0x00,0x00,0xea,0x20,0x00,0x00,0xea,0x3b,0xfc,0xff,0xea, -0x3a,0xfc,0xff,0xea,0x39,0xfc,0xff,0xea,0x38,0xfc,0xff,0xea,0x37,0xfc,0xff,0xea, -0x36,0xfc,0xff,0xea,0x35,0xfc,0xff,0xea,0x34,0xfc,0xff,0xea,0x33,0xfc,0xff,0xea, -0x32,0xfc,0xff,0xea,0x31,0xfc,0xff,0xea,0x30,0xfc,0xff,0xea,0x9e,0x02,0x00,0xea, -0x2e,0xfc,0xff,0xea,0xf5,0x01,0x00,0xea,0x2c,0xfc,0xff,0xea,0x7c,0x01,0x00,0xea, -0x2a,0xfc,0xff,0xea,0x29,0xfc,0xff,0xea,0x28,0xfc,0xff,0xea,0x61,0x01,0x00,0xea, -0x26,0xfc,0xff,0xea,0x25,0xfc,0xff,0xea,0x24,0xfc,0xff,0xea,0x23,0xfc,0xff,0xea, -0x22,0xfc,0xff,0xea,0x21,0xfc,0xff,0xea,0x0f,0x01,0x00,0xea,0x0e,0x01,0x00,0xea, -0x1e,0xfc,0xff,0xea,0xe7,0x00,0x00,0xea,0x1c,0xfc,0xff,0xea,0x30,0x00,0x00,0xea, -0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x05,0xfb,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x09,0x00,0x00,0x1a,0x1e,0x10,0xd4,0xe5,0x1d,0x00,0xd4,0xe5,0x1c,0x30,0xd4,0xe5, -0x1f,0x20,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x00,0x30,0x86,0xe5,0x08,0xfc,0xff,0xea,0xe8,0x7d,0x9f,0xe5, -0x06,0xfc,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x18,0xb0,0x84,0xe2,0x00,0x00,0x94,0xe5, -0x04,0x20,0xa0,0xe3,0x0b,0x10,0xa0,0xe1,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0xd9,0x03,0x00,0xeb,0x00,0x70,0x50,0xe2,0xfc,0xfb,0xff,0x1a,0x01,0x30,0xdb,0xe4, -0x05,0x00,0x5b,0xe1,0x03,0x70,0x87,0xe0,0xfb,0xff,0xff,0x1a,0x0a,0xa0,0x87,0xe0, -0x9e,0xff,0xff,0xea,0x07,0x00,0xa0,0xe1,0x47,0x41,0x00,0xeb,0x00,0x20,0xa0,0xe1, -0x26,0xfc,0xff,0xea,0x07,0x00,0xa0,0xe1,0x43,0x41,0x00,0xeb,0x00,0x20,0xa0,0xe1, -0x14,0xfc,0xff,0xea,0x06,0x00,0xa0,0xe1,0x3f,0x41,0x00,0xeb,0x00,0x20,0xa0,0xe1, -0x02,0xfc,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1, -0x04,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xd4,0xfa,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xd8,0xff,0xff,0x1a,0x1e,0x10,0xd4,0xe5,0x1d,0x00,0xd4,0xe5, -0x1c,0x30,0xd4,0xe5,0x1f,0x20,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x60,0x30,0x86,0xe5,0xd7,0xfb,0xff,0xea, -0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x48,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xc1,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xc5,0xff,0xff,0x1a,0x1e,0x10,0xd4,0xe5,0x1d,0x00,0xd4,0xe5,0x1f,0x20,0xd4,0xe5, -0x1c,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x00,0x30,0x86,0xe5,0x22,0x10,0xd4,0xe5,0x21,0x00,0xd4,0xe5, -0x23,0x20,0xd4,0xe5,0x20,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x04,0x30,0x86,0xe5,0x26,0x10,0xd4,0xe5, -0x25,0x00,0xd4,0xe5,0x27,0x20,0xd4,0xe5,0x24,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x08,0x30,0x86,0xe5, -0x2a,0x10,0xd4,0xe5,0x29,0x00,0xd4,0xe5,0x2b,0x20,0xd4,0xe5,0x28,0x30,0xd4,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x0c,0x30,0x86,0xe5,0x2e,0x10,0xd4,0xe5,0x2d,0x00,0xd4,0xe5,0x2f,0x20,0xd4,0xe5, -0x2c,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x10,0x30,0x86,0xe5,0x32,0x10,0xd4,0xe5,0x31,0x00,0xd4,0xe5, -0x33,0x20,0xd4,0xe5,0x30,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x14,0x30,0x86,0xe5,0x36,0x10,0xd4,0xe5, -0x35,0x00,0xd4,0xe5,0x37,0x20,0xd4,0xe5,0x34,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x18,0x30,0x86,0xe5, -0x3a,0x10,0xd4,0xe5,0x39,0x00,0xd4,0xe5,0x3b,0x20,0xd4,0xe5,0x38,0x30,0xd4,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x1c,0x30,0x86,0xe5,0x3e,0x10,0xd4,0xe5,0x3d,0x00,0xd4,0xe5,0x3f,0x20,0xd4,0xe5, -0x3c,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x20,0x30,0x86,0xe5,0x42,0x10,0xd4,0xe5,0x41,0x00,0xd4,0xe5, -0x43,0x20,0xd4,0xe5,0x40,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x24,0x30,0x86,0xe5,0x46,0x10,0xd4,0xe5, -0x45,0x00,0xd4,0xe5,0x47,0x20,0xd4,0xe5,0x44,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x28,0x30,0x86,0xe5, -0x4a,0x10,0xd4,0xe5,0x49,0x00,0xd4,0xe5,0x4b,0x20,0xd4,0xe5,0x48,0x30,0xd4,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x2c,0x30,0x86,0xe5,0x4e,0x10,0xd4,0xe5,0x4d,0x00,0xd4,0xe5,0x4f,0x20,0xd4,0xe5, -0x4c,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x34,0x30,0x86,0xe5,0x50,0x30,0xd4,0xe5,0x30,0x30,0xc6,0xe5, -0x51,0x30,0xd4,0xe5,0x31,0x30,0xc6,0xe5,0x52,0x30,0xd4,0xe5,0x32,0x30,0xc6,0xe5, -0x53,0x30,0xd4,0xe5,0x38,0x30,0xc6,0xe5,0x56,0x10,0xd4,0xe5,0x55,0x00,0xd4,0xe5, -0x57,0x20,0xd4,0xe5,0x54,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x3c,0x30,0x86,0xe5,0x5a,0x10,0xd4,0xe5, -0x59,0x00,0xd4,0xe5,0x5b,0x20,0xd4,0xe5,0x58,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x40,0x30,0x86,0xe5, -0x5e,0x10,0xd4,0xe5,0x5d,0x00,0xd4,0xe5,0x5c,0x30,0xd4,0xe5,0x5f,0x20,0xd4,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x44,0x30,0x86,0xe5,0x35,0xfb,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x05,0x10,0xa0,0xe1,0x0c,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x1f,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3,0x23,0xff,0xff,0x1a,0x1e,0x10,0xd4,0xe5, -0x1d,0x00,0xd4,0xe5,0x1f,0x20,0xd4,0xe5,0x1c,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x00,0x30,0x86,0xe5, -0x22,0x10,0xd4,0xe5,0x21,0x00,0xd4,0xe5,0x23,0x20,0xd4,0xe5,0x20,0x30,0xd4,0xe5, -0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1, -0x04,0x30,0x86,0xe5,0x26,0x10,0xd4,0xe5,0x25,0x00,0xd4,0xe5,0x24,0x30,0xd4,0xe5, -0x27,0x20,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x08,0x30,0x86,0xe5,0x10,0xfb,0xff,0xea,0x00,0xc0,0xa0,0xe3, -0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x08,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xfa,0xf9,0xff,0xeb,0x00,0x00,0x50,0xe3,0xfe,0xfe,0xff,0x1a, -0x1d,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x00,0xb0,0xa0,0xe3,0x1f,0x80,0xd4,0xe5, -0x00,0x90,0xa0,0xe3,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5,0x1e,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5,0x21,0x90,0xd4,0xe5, -0x00,0xa0,0xa0,0xe3,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x1c,0x10,0xd4,0xe5, -0x00,0x20,0xa0,0xe3,0x30,0x90,0x8d,0xe5,0x34,0xa0,0x8d,0xe5,0x0b,0x90,0x8b,0xe1, -0x18,0x50,0x9d,0xe5,0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5,0x22,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x05,0x88,0xa0,0xe1,0x38,0x20,0x8d,0xe5,0x3c,0x30,0x8d,0xe5, -0x10,0x30,0x9d,0xe5,0x38,0x10,0x9d,0xe5,0x10,0x00,0x8d,0xe5,0x03,0xa4,0xa0,0xe1, -0x23,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x20,0x40,0xd4,0xe5,0x0a,0x80,0x88,0xe1, -0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x0b,0x30,0xa0,0xe1,0x14,0x40,0x8d,0xe5, -0x28,0x40,0x9d,0xe5,0x04,0x2c,0xa0,0xe1,0x20,0x50,0x8d,0xe2,0x30,0x00,0x95,0xe8, -0x04,0xa0,0x88,0xe1,0x30,0x80,0x9d,0xe5,0x05,0xb0,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x03,0xb0,0x8b,0xe1,0x01,0x98,0xa0,0xe1,0x10,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8, -0x18,0x10,0x9d,0xe5,0x08,0x54,0xa0,0xe1,0x02,0xa0,0x8a,0xe1,0x03,0xb0,0x8b,0xe1, -0x0a,0x40,0x80,0xe1,0x0b,0x50,0x85,0xe1,0x01,0x3c,0xa0,0xe1,0x04,0x80,0x80,0xe1, -0x05,0x90,0x89,0xe1,0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1,0x08,0x20,0x86,0xe5, -0x0c,0x30,0x86,0xe5,0xc5,0xfa,0xff,0xea,0x08,0x30,0x96,0xe5,0x01,0x30,0x43,0xe2, -0x04,0x00,0x53,0xe3,0xc1,0xfa,0xff,0x8a,0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1, -0x05,0x10,0xa0,0xe1,0x04,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0xab,0xf9,0xff,0xeb,0x00,0x00,0x50,0xe3,0xaf,0xfe,0xff,0x1a,0x1e,0x10,0xd4,0xe5, -0x1d,0x00,0xd4,0xe5,0x1c,0x30,0xd4,0xe5,0x1f,0x20,0xd4,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x04,0x30,0x86,0xe5, -0xae,0xfa,0xff,0xea,0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1, -0x10,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x98,0xf9,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x9c,0xfe,0xff,0x1a,0x1d,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3, -0x1e,0x80,0xd4,0xe5,0x00,0x90,0xa0,0xe3,0x10,0x20,0x8d,0xe5,0x14,0x30,0x8d,0xe5, -0x1c,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x18,0x80,0x8d,0xe5,0x1c,0x90,0x8d,0xe5, -0x1f,0x90,0xd4,0xe5,0x00,0xa0,0xa0,0xe3,0x20,0x20,0x8d,0xe5,0x24,0x30,0x8d,0xe5, -0x22,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x18,0x30,0x9d,0xe5,0x28,0x90,0x8d,0xe5, -0x2c,0xa0,0x8d,0xe5,0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x10,0x20,0x9d,0xe5, -0x21,0xa0,0xd4,0xe5,0x00,0xb0,0xa0,0xe3,0x03,0x88,0xa0,0xe1,0x10,0x00,0x8d,0xe5, -0x30,0xa0,0x8d,0xe5,0x34,0xb0,0x8d,0xe5,0x02,0xa4,0xa0,0xe1,0x23,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x00,0xb0,0xa0,0xe3,0x0a,0x10,0x88,0xe1,0x0c,0xb0,0x8d,0xe5, -0x40,0x20,0x8d,0xe5,0x44,0x30,0x8d,0xe5,0x0b,0x20,0x8b,0xe1,0x18,0x10,0x8d,0xe5, -0x1c,0x20,0x8d,0xe5,0x28,0x20,0x9d,0xe5,0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8, -0x20,0x30,0xd4,0xe5,0x02,0x2c,0xa0,0xe1,0x14,0x30,0x8d,0xe5,0x08,0x20,0x8d,0xe5, -0x20,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x38,0x30,0x9d,0xe5,0x02,0xa0,0x8a,0xe1, -0x30,0x20,0x9d,0xe5,0x01,0x90,0x89,0xe1,0x18,0x90,0x8d,0xe5,0x1c,0xa0,0x8d,0xe5, -0x03,0x38,0xa0,0xe1,0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x02,0x24,0xa0,0xe1, -0x24,0x30,0x8d,0xe5,0x2c,0x20,0x8d,0xe5,0x08,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8, -0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1,0x10,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8, -0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1,0x10,0x90,0x8d,0xe5,0x14,0xa0,0x8d,0xe5, -0x28,0x00,0x8d,0xe5,0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x28,0x90,0x8d,0xe2, -0x00,0x03,0x99,0xe8,0x40,0x50,0x9d,0xe5,0x20,0x00,0x8d,0xe5,0x0a,0x80,0x88,0xe1, -0x0b,0x90,0x89,0xe1,0x10,0x80,0x8d,0xe5,0x14,0x90,0x8d,0xe5,0x10,0xb0,0x8d,0xe2, -0x00,0x0c,0x9b,0xe8,0x05,0x3c,0xa0,0xe1,0x20,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8, -0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1,0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1, -0x0c,0x00,0x86,0xe8,0x26,0x10,0xd4,0xe5,0x25,0x00,0xd4,0xe5,0x27,0x20,0xd4,0xe5, -0x24,0x30,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1, -0x02,0x3c,0x83,0xe1,0x08,0x30,0x86,0xe5,0x2a,0x10,0xd4,0xe5,0x29,0x00,0xd4,0xe5, -0x28,0x30,0xd4,0xe5,0x2b,0x20,0xd4,0xe5,0x01,0x18,0xa0,0xe1,0x00,0x14,0x81,0xe1, -0x03,0x30,0x81,0xe1,0x02,0x3c,0x83,0xe1,0x0c,0x30,0x86,0xe5,0x37,0xfa,0xff,0xea, -0x00,0xc0,0xa0,0xe3,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3, -0x0c,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x21,0xf9,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x25,0xfe,0xff,0x1a,0x1d,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x1e,0x80,0xd4,0xe5, -0x00,0x90,0xa0,0xe3,0x10,0x20,0x8d,0xe5,0x14,0x30,0x8d,0xe5,0x1c,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x18,0x80,0x8d,0xe5,0x1c,0x90,0x8d,0xe5,0x1f,0x90,0xd4,0xe5, -0x00,0xa0,0xa0,0xe3,0x20,0x20,0x8d,0xe5,0x24,0x30,0x8d,0xe5,0x22,0x10,0xd4,0xe5, -0x00,0x20,0xa0,0xe3,0x18,0x30,0x9d,0xe5,0x28,0x90,0x8d,0xe5,0x2c,0xa0,0x8d,0xe5, -0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x10,0x20,0x9d,0xe5,0x21,0xa0,0xd4,0xe5, -0x00,0xb0,0xa0,0xe3,0x03,0x88,0xa0,0xe1,0x10,0x00,0x8d,0xe5,0x30,0xa0,0x8d,0xe5, -0x34,0xb0,0x8d,0xe5,0x02,0xa4,0xa0,0xe1,0x23,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3, -0x00,0xb0,0xa0,0xe3,0x0a,0x10,0x88,0xe1,0x0c,0xb0,0x8d,0xe5,0x40,0x20,0x8d,0xe5, -0x44,0x30,0x8d,0xe5,0x0b,0x20,0x8b,0xe1,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5, -0x28,0x20,0x9d,0xe5,0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x20,0x30,0xd4,0xe5, -0x02,0x2c,0xa0,0xe1,0x14,0x30,0x8d,0xe5,0x08,0x20,0x8d,0xe5,0x20,0x20,0x8d,0xe2, -0x06,0x00,0x92,0xe8,0x38,0x30,0x9d,0xe5,0x02,0xa0,0x8a,0xe1,0x30,0x20,0x9d,0xe5, -0x01,0x90,0x89,0xe1,0x18,0x90,0x8d,0xe5,0x1c,0xa0,0x8d,0xe5,0x03,0x38,0xa0,0xe1, -0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x02,0x24,0xa0,0xe1,0x24,0x30,0x8d,0xe5, -0x2c,0x20,0x8d,0xe5,0x08,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1, -0x02,0xa0,0x8a,0xe1,0x10,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1, -0x02,0xa0,0x8a,0xe1,0x10,0x90,0x8d,0xe5,0x14,0xa0,0x8d,0xe5,0x28,0x00,0x8d,0xe5, -0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8, -0x40,0x50,0x9d,0xe5,0x20,0x00,0x8d,0xe5,0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1, -0x10,0x80,0x8d,0xe5,0x14,0x90,0x8d,0xe5,0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8, -0x05,0x3c,0xa0,0xe1,0x20,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x0a,0x80,0x88,0xe1, -0x0b,0x90,0x89,0xe1,0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1,0x08,0x20,0x86,0xe5, -0x0c,0x30,0x86,0xe5,0x00,0xb0,0xa0,0xe3,0x25,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3, -0x27,0x80,0xd4,0xe5,0x00,0x90,0xa0,0xe3,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x26,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5, -0x0b,0x90,0x8b,0xe1,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x29,0x10,0xd4,0xe5, -0x00,0x20,0xa0,0xe3,0x30,0x10,0x8d,0xe5,0x34,0x20,0x8d,0xe5,0x24,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x20,0x20,0x8d,0xe5,0x24,0x30,0x8d,0xe5,0x2a,0x10,0xd4,0xe5, -0x00,0x20,0xa0,0xe3,0x18,0x30,0x9d,0xe5,0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5, -0x10,0x20,0x9d,0xe5,0x03,0x88,0xa0,0xe1,0x38,0x10,0x9d,0xe5,0x10,0x00,0x8d,0xe5, -0x02,0xa4,0xa0,0xe1,0x2b,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x28,0x40,0xd4,0xe5, -0x0a,0x80,0x88,0xe1,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x0b,0x30,0xa0,0xe1, -0x14,0x40,0x8d,0xe5,0x28,0x40,0x9d,0xe5,0x04,0x2c,0xa0,0xe1,0x20,0x50,0x8d,0xe2, -0x30,0x00,0x95,0xe8,0x04,0xa0,0x88,0xe1,0x30,0x80,0x9d,0xe5,0x05,0xb0,0x89,0xe1, -0x02,0xa0,0x8a,0xe1,0x03,0xb0,0x8b,0xe1,0x01,0x98,0xa0,0xe1,0x10,0x30,0x8d,0xe2, -0x0c,0x00,0x93,0xe8,0x18,0x10,0x9d,0xe5,0x08,0x54,0xa0,0xe1,0x02,0xa0,0x8a,0xe1, -0x03,0xb0,0x8b,0xe1,0x0a,0x40,0x80,0xe1,0x0b,0x50,0x85,0xe1,0x01,0x3c,0xa0,0xe1, -0x04,0x80,0x80,0xe1,0x05,0x90,0x89,0xe1,0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1, -0x10,0x20,0x86,0xe5,0x14,0x30,0x86,0xe5,0x90,0xf9,0xff,0xea,0x00,0xc0,0xa0,0xe3, -0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x18,0x20,0xa0,0xe3,0x0c,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0x7a,0xf8,0xff,0xeb,0x00,0x00,0x50,0xe3,0x7e,0xfd,0xff,0x1a, -0x1d,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x00,0xb0,0xa0,0xe3,0x1f,0x80,0xd4,0xe5, -0x00,0x90,0xa0,0xe3,0x0c,0xb0,0x8d,0xe5,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x1e,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5, -0x21,0x90,0xd4,0xe5,0x00,0xa0,0xa0,0xe3,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5, -0x1c,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x30,0x90,0x8d,0xe5,0x34,0xa0,0x8d,0xe5, -0x20,0x20,0x8d,0xe5,0x24,0x30,0x8d,0xe5,0x22,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3, -0x18,0x30,0x9d,0xe5,0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x10,0x20,0x9d,0xe5, -0x03,0x88,0xa0,0xe1,0x10,0x00,0x8d,0xe5,0x02,0xa4,0xa0,0xe1,0x23,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x0a,0x10,0x88,0xe1,0x40,0x20,0x8d,0xe5,0x44,0x30,0x8d,0xe5, -0x0b,0x20,0x8b,0xe1,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5,0x28,0x20,0x9d,0xe5, -0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x20,0x30,0xd4,0xe5,0x02,0x2c,0xa0,0xe1, -0x14,0x30,0x8d,0xe5,0x08,0x20,0x8d,0xe5,0x20,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8, -0x38,0x30,0x9d,0xe5,0x02,0xa0,0x8a,0xe1,0x30,0x20,0x9d,0xe5,0x01,0x90,0x89,0xe1, -0x18,0x90,0x8d,0xe5,0x1c,0xa0,0x8d,0xe5,0x03,0x38,0xa0,0xe1,0x18,0xa0,0x8d,0xe2, -0x00,0x06,0x9a,0xe8,0x02,0x24,0xa0,0xe1,0x24,0x30,0x8d,0xe5,0x2c,0x20,0x8d,0xe5, -0x08,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x10,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x10,0x90,0x8d,0xe5,0x14,0xa0,0x8d,0xe5,0x28,0x00,0x8d,0xe5,0x10,0xb0,0x8d,0xe2, -0x00,0x0c,0x9b,0xe8,0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x40,0x50,0x9d,0xe5, -0x20,0x00,0x8d,0xe5,0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1,0x10,0x80,0x8d,0xe5, -0x14,0x90,0x8d,0xe5,0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8,0x05,0x3c,0xa0,0xe1, -0x20,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1, -0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1,0x08,0x20,0x86,0xe5,0x0c,0x30,0x86,0xe5, -0x00,0xb0,0xa0,0xe3,0x25,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x27,0x80,0xd4,0xe5, -0x00,0x90,0xa0,0xe3,0x0c,0xb0,0x8d,0xe5,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5, -0x26,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5, -0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x29,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3, -0x18,0x50,0x9d,0xe5,0x30,0x10,0x8d,0xe5,0x34,0x20,0x8d,0xe5,0x24,0x10,0xd4,0xe5, -0x00,0x20,0xa0,0xe3,0x05,0x88,0xa0,0xe1,0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5, -0x2a,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3,0x38,0x20,0x8d,0xe5,0x3c,0x30,0x8d,0xe5, -0x2b,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x10,0x30,0x9d,0xe5,0x40,0x10,0x8d,0xe5, -0x44,0x20,0x8d,0xe5,0x28,0x20,0xd4,0xe5,0x03,0xa4,0xa0,0xe1,0x14,0x20,0x8d,0xe5, -0x0a,0x10,0x88,0xe1,0x0b,0x20,0x8b,0xe1,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5, -0x28,0x20,0x9d,0xe5,0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x02,0x2c,0xa0,0xe1, -0x08,0x20,0x8d,0xe5,0x20,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1, -0x02,0xa0,0x8a,0xe1,0x18,0x90,0x8d,0xe5,0x1c,0xa0,0x8d,0xe5,0x30,0x20,0x9d,0xe5, -0x18,0xa0,0x8d,0xe2,0x00,0x06,0x9a,0xe8,0x10,0x00,0x8d,0xe5,0x38,0x30,0x9d,0xe5, -0x02,0x24,0xa0,0xe1,0x28,0x00,0x8d,0xe5,0x40,0x50,0x9d,0xe5,0x2c,0x20,0x8d,0xe5, -0x08,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x03,0x38,0xa0,0xe1,0x20,0x00,0x8d,0xe5, -0x24,0x30,0x8d,0xe5,0x05,0x3c,0xa0,0xe1,0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x10,0x20,0x8d,0xe2,0x06,0x00,0x92,0xe8,0x01,0x90,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x10,0x90,0x8d,0xe5,0x14,0xa0,0x8d,0xe5,0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8, -0x28,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1, -0x10,0x80,0x8d,0xe5,0x14,0x90,0x8d,0xe5,0x10,0xb0,0x8d,0xe2,0x00,0x0c,0x9b,0xe8, -0x20,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0x0a,0x80,0x88,0xe1,0x0b,0x90,0x89,0xe1, -0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1,0x10,0x20,0x86,0xe5,0x14,0x30,0x86,0xe5, -0x00,0xb0,0xa0,0xe3,0x2d,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3,0x2f,0x80,0xd4,0xe5, -0x00,0x90,0xa0,0xe3,0x10,0x10,0x8d,0xe5,0x14,0x20,0x8d,0xe5,0x2e,0x20,0xd4,0xe5, -0x00,0x30,0xa0,0xe3,0x28,0x80,0x8d,0xe5,0x2c,0x90,0x8d,0xe5,0x0b,0x90,0x8b,0xe1, -0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x31,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3, -0x30,0x10,0x8d,0xe5,0x34,0x20,0x8d,0xe5,0x2c,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3, -0x20,0x20,0x8d,0xe5,0x24,0x30,0x8d,0xe5,0x32,0x10,0xd4,0xe5,0x00,0x20,0xa0,0xe3, -0x18,0x30,0x9d,0xe5,0x38,0x10,0x8d,0xe5,0x3c,0x20,0x8d,0xe5,0x10,0x20,0x9d,0xe5, -0x03,0x88,0xa0,0xe1,0x02,0xa4,0xa0,0xe1,0x33,0x20,0xd4,0xe5,0x00,0x30,0xa0,0xe3, -0x0a,0x80,0x88,0xe1,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x0b,0x30,0xa0,0xe1, -0x30,0x40,0xd4,0xe5,0x38,0x10,0x9d,0xe5,0x10,0x00,0x8d,0xe5,0x14,0x40,0x8d,0xe5, -0x28,0x40,0x9d,0xe5,0x04,0x2c,0xa0,0xe1,0x20,0x50,0x8d,0xe2,0x30,0x00,0x95,0xe8, -0x04,0xa0,0x88,0xe1,0x30,0x80,0x9d,0xe5,0x05,0xb0,0x89,0xe1,0x02,0xa0,0x8a,0xe1, -0x03,0xb0,0x8b,0xe1,0x01,0x98,0xa0,0xe1,0x10,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8, -0x18,0x10,0x9d,0xe5,0x08,0x54,0xa0,0xe1,0x02,0xa0,0x8a,0xe1,0x03,0xb0,0x8b,0xe1, -0x0a,0x40,0x80,0xe1,0x0b,0x50,0x85,0xe1,0x01,0x3c,0xa0,0xe1,0x04,0x80,0x80,0xe1, -0x05,0x90,0x89,0xe1,0x08,0x20,0x80,0xe1,0x09,0x30,0x83,0xe1,0x18,0x20,0x86,0xe5, -0x1c,0x30,0x86,0xe5,0x8d,0xf8,0xff,0xea,0x02,0x00,0x12,0x00,0x04,0x00,0x12,0x00, -0x10,0x40,0x2d,0xe9,0x10,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe3,0x10,0x30,0x8d,0xe2, -0x01,0x1a,0xa0,0xe3,0x04,0x20,0xa0,0xe1,0x04,0x40,0x23,0xe5,0x07,0x02,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x03,0x30,0xa0,0xe3,0x05,0x43,0x00,0xeb,0x04,0x00,0x50,0xe1, -0x0c,0x30,0x9d,0x05,0x04,0x00,0xa0,0x11,0x04,0x08,0x93,0x05,0x20,0x04,0xa0,0x01, -0xff,0x00,0x00,0x02,0x10,0xd0,0x8d,0xe2,0x10,0x80,0xbd,0xe8,0x10,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0xe9,0xff,0xff,0xeb,0x00,0x00,0x54,0xe3,0x09,0x00,0xa0,0x03, -0x10,0x80,0xbd,0x08,0x20,0x00,0x50,0xe3,0x08,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3, -0x09,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a,0x02,0x00,0xa0,0xe3, -0x10,0x80,0xbd,0xe8,0x04,0x00,0xa0,0xe1,0x10,0x40,0xbd,0xe8,0x94,0x17,0x00,0xea, -0x04,0x00,0xa0,0xe1,0x10,0x40,0xbd,0xe8,0x65,0x06,0x00,0xea,0x04,0x00,0xa0,0xe1, -0x10,0x40,0xbd,0xe8,0xf8,0x0e,0x00,0xea,0x10,0x40,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0xd2,0xff,0xff,0xeb,0x20,0x00,0x50,0xe3,0x06,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3, -0x07,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x10,0x80,0xbd,0x18,0x04,0x00,0xa0,0xe1, -0x10,0x40,0xbd,0xe8,0xb0,0x17,0x00,0xea,0x04,0x00,0xa0,0xe1,0x10,0x40,0xbd,0xe8, -0x81,0x06,0x00,0xea,0x04,0x00,0xa0,0xe1,0x10,0x40,0xbd,0xe8,0x14,0x0f,0x00,0xea, -0xf0,0x40,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0x0c,0xd0,0x4d,0xe2,0x01,0x70,0xa0,0xe1, -0x02,0x60,0xa0,0xe1,0x03,0x50,0xa0,0xe1,0xbc,0xff,0xff,0xeb,0x00,0x00,0x54,0xe3, -0x09,0x00,0xa0,0x03,0x06,0x00,0x00,0x0a,0x20,0x00,0x50,0xe3,0x0e,0x00,0x00,0x0a, -0x30,0x00,0x50,0xe3,0x14,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x02,0x00,0xa0,0x13, -0x01,0x00,0x00,0x0a,0x0c,0xd0,0x8d,0xe2,0xf0,0x80,0xbd,0xe8,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0xb6,0x17,0x00,0xeb,0xf5,0xff,0xff,0xea,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0x82,0x06,0x00,0xeb,0xed,0xff,0xff,0xea,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1,0x05,0x30,0xa0,0xe1, -0x00,0xc0,0x8d,0xe5,0x10,0x0f,0x00,0xeb,0xe5,0xff,0xff,0xea,0xf0,0x41,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0x08,0xd0,0x4d,0xe2,0x01,0x80,0xa0,0xe1,0x02,0x70,0xa0,0xe1, -0x03,0x60,0xa0,0xe1,0x20,0x50,0x9d,0xe5,0x90,0xff,0xff,0xeb,0x00,0x00,0x54,0xe3, -0x09,0x00,0xa0,0x03,0x06,0x00,0x00,0x0a,0x20,0x00,0x50,0xe3,0x0e,0x00,0x00,0x0a, -0x30,0x00,0x50,0xe3,0x14,0x00,0x00,0x0a,0x35,0x00,0x50,0xe3,0x02,0x00,0xa0,0x13, -0x01,0x00,0x00,0x0a,0x08,0xd0,0x8d,0xe2,0xf0,0x81,0xbd,0xe8,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x08,0x10,0xa0,0xe1,0x07,0x20,0xa0,0xe1,0x06,0x30,0xa0,0xe1, -0x20,0x10,0x8d,0xe8,0x8a,0x18,0x00,0xeb,0xf5,0xff,0xff,0xea,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x08,0x10,0xa0,0xe1,0x07,0x20,0xa0,0xe1,0x06,0x30,0xa0,0xe1, -0x20,0x10,0x8d,0xe8,0x56,0x07,0x00,0xeb,0xed,0xff,0xff,0xea,0x00,0xc0,0xe0,0xe3, -0x04,0x00,0xa0,0xe1,0x08,0x10,0xa0,0xe1,0x07,0x20,0xa0,0xe1,0x06,0x30,0xa0,0xe1, -0x20,0x10,0x8d,0xe8,0xe4,0x0f,0x00,0xeb,0xe5,0xff,0xff,0xea,0xf0,0x41,0x2d,0xe9, -0x01,0x40,0xa0,0xe1,0xb0,0x51,0x9f,0xe5,0x00,0x80,0xa0,0xe1,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0xa4,0x31,0x9f,0xe5,0x05,0x50,0x8f,0xe0,0x03,0x30,0x95,0xe7, -0x80,0x60,0x93,0xe5,0x04,0x73,0x86,0xe0,0x07,0x00,0xa0,0xe1,0x41,0x3d,0x00,0xeb, -0x00,0x00,0x54,0xe3,0x17,0x00,0x00,0x1a,0x02,0x39,0xa0,0xe3,0x04,0x33,0x86,0xe7, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5,0x04,0x33,0x96,0xe7,0x01,0x35,0x83,0xe3, -0x04,0x33,0x86,0xe7,0xa4,0x40,0xb0,0xe1,0x43,0x00,0x00,0x1a,0x60,0x31,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0xc0,0x11,0x92,0xe5,0x0c,0x10,0xc1,0xe3, -0xc0,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc0,0x11,0x92,0xe5,0x01,0x10,0xc1,0xe3, -0xc0,0x11,0x82,0xe5,0x04,0x30,0x93,0xe5,0xc0,0x21,0x93,0xe5,0x80,0x20,0x82,0xe3, -0xc0,0x21,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x02,0x30,0x44,0xe2,0x01,0x00,0x53,0xe3, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5,0x01,0x35,0xa0,0x83,0x04,0x23,0x96,0xe7, -0x19,0x00,0x00,0x9a,0x01,0x00,0x14,0xe3,0x03,0x30,0x82,0xe1,0x04,0x33,0x86,0xe7, -0xe3,0xff,0xff,0x0a,0xa4,0x40,0xb0,0xe1,0x18,0x00,0x00,0x0a,0xf0,0x30,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5,0x03,0x17,0xc1,0xe3, -0x02,0x17,0x81,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5, -0x01,0x18,0xc1,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5, -0x01,0x15,0x81,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x30,0x93,0xe5,0xc4,0x21,0x93,0xe5, -0x02,0x25,0x82,0xe3,0xc4,0x21,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x98,0xe5, -0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03,0x01,0x35,0xa0,0x13,0xe0,0xff,0xff,0xea, -0x8c,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0xc0,0x11,0x92,0xe5, -0x03,0x17,0xc1,0xe3,0xc0,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc0,0x11,0x92,0xe5, -0x01,0x18,0xc1,0xe3,0xc0,0x11,0x82,0xe5,0x04,0x30,0x93,0xe5,0xc0,0x21,0x93,0xe5, -0x02,0x25,0x82,0xe3,0xc0,0x21,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x50,0x30,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5,0x0c,0x10,0xc1,0xe3, -0x08,0x10,0x81,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5, -0x01,0x10,0xc1,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x20,0x93,0xe5,0xc4,0x11,0x92,0xe5, -0x40,0x10,0x81,0xe3,0xc4,0x11,0x82,0xe5,0x04,0x30,0x93,0xe5,0xc4,0x21,0x93,0xe5, -0x80,0x20,0x82,0xe3,0xc4,0x21,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x58,0x4e,0x01,0x00, -0x18,0x10,0x00,0x00,0x48,0x10,0x00,0x00,0xf0,0x4f,0x2d,0xe9,0x34,0xd0,0x4d,0xe2, -0x2c,0x00,0x8d,0xe5,0x01,0x00,0x71,0xe3,0x01,0x50,0xa0,0xe1,0x98,0x46,0x9f,0xe5, -0x58,0x00,0xdd,0xe5,0x28,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x04,0x40,0x8f,0xe0, -0x24,0x00,0x8d,0xe5,0xff,0x00,0x00,0x0a,0xa1,0x10,0xa0,0xe1,0x01,0xb0,0x15,0xe2, -0x01,0x60,0xa0,0x03,0x01,0x68,0xa0,0x13,0x16,0x61,0xa0,0xe1,0x20,0x10,0x8d,0xe5, -0x08,0x10,0x8d,0xe5,0x64,0xa6,0x9f,0xe5,0x04,0x90,0xa0,0xe1,0x60,0x76,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x20,0x93,0xe5,0xb4,0x61,0x82,0xe5,0x04,0x30,0x93,0xe5, -0xb4,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0xb4,0x81,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xe7,0x3c,0x00,0xeb,0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1, -0x1c,0x76,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0xb8,0x81,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xd8,0x3c,0x00,0xeb, -0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0xe0,0x75,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xc9,0x3c,0x00,0xeb,0x06,0x00,0x18,0xe1, -0xf6,0xff,0xff,0x1a,0xac,0x75,0x9f,0xe5,0x85,0x32,0xa0,0xe1,0x20,0x20,0xa0,0xe3, -0x05,0x63,0xa0,0xe1,0x02,0x90,0x85,0xe0,0x14,0x30,0x8d,0xe5,0x07,0x00,0x94,0xe7, -0x24,0xc0,0x85,0xe2,0x00,0x10,0xa0,0xe3,0x18,0xc0,0x8d,0xe5,0x0c,0x60,0x8d,0xe5, -0x03,0x00,0x80,0xe0,0x10,0x90,0x8d,0xe5,0x8a,0x3c,0x00,0xeb,0x07,0x30,0x94,0xe7, -0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x06,0x00,0x80,0xe0, -0x84,0x3c,0x00,0xeb,0x07,0x20,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x18,0xe0,0x9d,0xe5, -0x01,0x00,0x5b,0xe1,0x0a,0x30,0x94,0xe7,0x09,0xc1,0x82,0xe0,0x0e,0x01,0x82,0xe0, -0x04,0x10,0x8c,0xe5,0x04,0x10,0x80,0xe5,0x04,0x30,0x93,0xe5,0xbc,0x01,0x93,0xe5, -0x3f,0x00,0x00,0x1a,0x08,0x10,0x9d,0xe5,0x80,0x80,0x92,0xe5,0x01,0x20,0xa0,0xe3, -0x0c,0x90,0x9d,0xe5,0x12,0x01,0x80,0xe1,0x0b,0x10,0xa0,0xe1,0x09,0x60,0x88,0xe0, -0xbc,0x01,0x83,0xe5,0x30,0x20,0xa0,0xe3,0x06,0x00,0xa0,0xe1,0x6d,0x3c,0x00,0xeb, -0x00,0x00,0x55,0xe3,0x3c,0x00,0x00,0x1a,0x02,0x29,0xa0,0xe3,0x01,0x35,0xa0,0xe3, -0x05,0x23,0x88,0xe7,0x05,0x23,0x98,0xe7,0x07,0x80,0x94,0xe7,0x03,0x30,0x82,0xe1, -0x14,0xe0,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x10,0x00,0x9d,0xe5,0x01,0xc0,0xa0,0xe3, -0x02,0x32,0x83,0xe3,0x0e,0x90,0x88,0xe0,0x18,0xe0,0x9d,0xe5,0x00,0x30,0x86,0xe5, -0x00,0x21,0x88,0xe0,0x08,0x10,0x86,0xe5,0x09,0x00,0xa0,0xe1,0x04,0xc0,0x82,0xe5, -0x0e,0x31,0x88,0xe0,0x1c,0x20,0x9d,0xe5,0x04,0x20,0x83,0xe5,0x20,0x20,0xa0,0xe3, -0x04,0xc0,0x8d,0xe5,0x53,0x3c,0x00,0xeb,0x1c,0x30,0x9d,0xe5,0x00,0x00,0x5b,0xe3, -0x04,0xc0,0x9d,0xe5,0x01,0x10,0xa0,0x03,0x24,0x00,0x9d,0xe5,0x01,0x18,0xa0,0x13, -0x03,0x28,0xa0,0xe1,0x85,0xc2,0x88,0xe7,0x0a,0x30,0x94,0xe7,0x00,0x00,0x50,0xe3, -0x80,0x20,0x82,0xe3,0x1f,0xc0,0xc9,0xe3,0x04,0x20,0x89,0xe5,0x28,0x20,0x9d,0xe5, -0x08,0x20,0x89,0xe5,0x08,0x00,0x96,0xe5,0x04,0x20,0x93,0xe5,0x00,0x00,0x8c,0xe1, -0x08,0x00,0x86,0xe5,0x08,0x60,0x9d,0xe5,0xb0,0x01,0x92,0xe5,0x11,0x16,0x80,0xe1, -0x24,0x00,0x9d,0x05,0xb0,0x11,0x82,0xe5,0x16,0x00,0x00,0x1a,0x34,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x08,0xc0,0x9d,0xe5,0x80,0x60,0x92,0xe5,0x01,0x28,0xa0,0xe3, -0x0c,0xe0,0x9d,0xe5,0x12,0x0c,0x80,0xe1,0x30,0x20,0xa0,0xe3,0x0e,0x60,0x86,0xe0, -0xbc,0x01,0x83,0xe5,0x06,0x00,0xa0,0xe1,0x2e,0x3c,0x00,0xeb,0x02,0x30,0x45,0xe2, -0x00,0x20,0x96,0xe5,0x01,0x00,0x53,0xe3,0x01,0x35,0xa0,0x83,0xc1,0xff,0xff,0x8a, -0x2c,0xc0,0x9d,0xe5,0x00,0x30,0x9c,0xe5,0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03, -0x01,0x35,0xa0,0x13,0xbb,0xff,0xff,0xea,0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3, -0x04,0x10,0x93,0x15,0x04,0x10,0x93,0x05,0xc4,0x31,0x91,0x15,0xc0,0x31,0x91,0x05, -0x00,0x00,0x5b,0xe3,0x01,0x20,0x03,0x02,0x23,0x28,0xa0,0x11,0x01,0x20,0x02,0x12, -0x00,0x00,0x52,0xe3,0x1a,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3,0xa3,0x3b,0xa0,0x11, -0xa3,0x33,0xa0,0x01,0x01,0x30,0x03,0x12,0x01,0x30,0x03,0x02,0x00,0x00,0x53,0xe3, -0x13,0x00,0x00,0x0a,0x07,0x20,0x94,0xe7,0x0c,0xc0,0x9d,0xe5,0x80,0x30,0x92,0xe5, -0x0c,0x30,0x83,0xe0,0x0c,0x30,0x93,0xe5,0x68,0x00,0x13,0xe2,0x0c,0x00,0x00,0x1a, -0xb0,0xc1,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x60,0x9d,0xe5,0x01,0x30,0xa0,0x03, -0x01,0x38,0xa0,0x13,0x13,0xc6,0x1c,0xe0,0x3c,0x00,0x00,0x1a,0xb8,0x01,0x91,0xe5, -0x13,0x66,0x10,0xe0,0xce,0x00,0x00,0x1a,0x10,0x90,0x9d,0xe5,0x09,0x21,0x82,0xe0, -0x04,0x30,0x92,0xe5,0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3,0xc4,0x31,0x91,0x15, -0x2e,0x00,0x00,0x0a,0x00,0x00,0x5b,0xe3,0x23,0x28,0xa0,0x11,0x01,0x20,0x03,0x02, -0x01,0x20,0x02,0x12,0x00,0x00,0x52,0xe3,0x2a,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3, -0xa3,0x3b,0xa0,0x11,0xa3,0x33,0xa0,0x01,0x01,0x30,0x03,0x12,0x01,0x30,0x03,0x02, -0x00,0x00,0x53,0xe3,0x23,0x00,0x00,0x0a,0x07,0x30,0x94,0xe7,0x0c,0xc0,0x9d,0xe5, -0x80,0x20,0x93,0xe5,0x0c,0x20,0x82,0xe0,0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3, -0x1c,0x00,0x00,0x1a,0xb0,0x21,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x40,0x9d,0xe5, -0x01,0x00,0xa0,0x03,0x01,0x08,0xa0,0x13,0x10,0x44,0x12,0xe0,0x15,0x00,0x00,0x1a, -0xb8,0x21,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x60,0x9d,0xe5,0x01,0xb8,0xa0,0x13, -0x01,0xb0,0xa0,0x03,0x1b,0x66,0x12,0xe0,0x0e,0x00,0x00,0x1a,0x10,0x90,0x9d,0xe5, -0x09,0x31,0x83,0xe0,0x04,0x00,0x93,0xe5,0x00,0x00,0x50,0xe3,0x1a,0x00,0xa0,0x03, -0x00,0x00,0xa0,0x13,0x94,0xff,0xff,0xea,0x02,0x21,0xe0,0xe3,0x01,0x60,0xa0,0xe1, -0x08,0x20,0x8d,0xe5,0x01,0xb0,0xa0,0xe3,0x20,0x20,0x8d,0xe5,0x00,0xff,0xff,0xea, -0xc0,0x31,0x91,0xe5,0xce,0xff,0xff,0xea,0x1a,0x00,0xa0,0xe3,0x8a,0xff,0xff,0xea, -0x1c,0x00,0x8d,0xe5,0x0a,0x60,0x84,0xe0,0x07,0x80,0x84,0xe0,0x01,0x00,0xa0,0xe3, -0xef,0x3b,0x00,0xeb,0x20,0xc0,0x9d,0xe5,0x00,0x00,0x5c,0xe3,0x00,0x30,0x96,0x15, -0x00,0x30,0x96,0x05,0x04,0x10,0x93,0x15,0x04,0x10,0x93,0x05,0xc4,0x21,0x91,0x15, -0xc0,0x21,0x91,0x05,0x00,0x00,0x5b,0xe3,0x01,0x00,0x02,0x02,0x22,0x08,0xa0,0x11, -0x01,0x00,0x00,0x12,0x00,0x00,0x50,0xe3,0x74,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3, -0xa2,0x2b,0xa0,0x11,0xa2,0x23,0xa0,0x01,0x01,0x20,0x02,0x12,0x01,0x20,0x02,0x02, -0x00,0x00,0x52,0xe3,0x6f,0x00,0x00,0x0a,0x00,0x00,0x98,0xe5,0x0c,0x90,0x9d,0xe5, -0x80,0x20,0x90,0xe5,0x09,0x20,0x82,0xe0,0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3, -0x6a,0x00,0x00,0x1a,0xb0,0xc1,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x90,0x9d,0xe5, -0x01,0x20,0xa0,0x03,0x01,0x28,0xa0,0x13,0x12,0xc9,0x1c,0xe0,0x65,0x00,0x00,0x1a, -0xb8,0xc1,0x91,0xe5,0x12,0xc9,0x1c,0xe0,0x62,0x00,0x00,0x1a,0x10,0x60,0x9d,0xe5, -0x06,0x31,0x80,0xe0,0x04,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0x03,0x30,0xa0,0x03, -0x00,0x30,0xa0,0x13,0x01,0x00,0x53,0xe3,0x0a,0x30,0x94,0xe7,0x94,0xff,0xff,0x1a, -0x01,0x00,0x75,0xe3,0x04,0x00,0x00,0x0a,0x08,0xc0,0x9d,0xe5,0x00,0x00,0x5b,0xe3, -0x01,0x50,0xa0,0x03,0x01,0x58,0xa0,0x13,0x15,0x5c,0xa0,0xe1,0xb4,0x51,0x81,0xe5, -0x0a,0x80,0x84,0xe0,0x04,0x30,0x93,0xe5,0x64,0x61,0x9f,0xe5,0xb4,0x91,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x98,0xe5,0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5, -0xb4,0x91,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xac,0x3b,0x00,0xeb, -0x05,0x00,0x19,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0x30,0x61,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x99,0xe5,0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5, -0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x9d,0x3b,0x00,0xeb,0x05,0x00,0x18,0xe1, -0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0xf4,0x60,0x9f,0xe5,0x0a,0x30,0xb9,0xe7, -0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5, -0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x8e,0x3b,0x00,0xeb,0x05,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a, -0x07,0x00,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x14,0xe0,0x9d,0xe5,0x20,0x20,0xa0,0xe3, -0x0e,0x00,0x80,0xe0,0x57,0x3b,0x00,0xeb,0x07,0x30,0x94,0xe7,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x0c,0x30,0x9d,0xe5,0x03,0x00,0x80,0xe0, -0x50,0x3b,0x00,0xeb,0x07,0x20,0x94,0xe7,0x00,0x30,0xa0,0xe3,0x0a,0x10,0x94,0xe7, -0x03,0x00,0x5b,0xe1,0x10,0x40,0x9d,0xe5,0x01,0xb8,0xa0,0x13,0x18,0x60,0x9d,0xe5, -0x01,0xb0,0xa0,0x03,0x08,0x90,0x9d,0xe5,0x03,0x00,0xa0,0xe3,0x04,0xc1,0x82,0xe0, -0x06,0x21,0x82,0xe0,0x04,0x30,0x8c,0xe5,0x04,0x30,0x82,0xe5,0x04,0x30,0x91,0xe5, -0xbc,0x21,0x93,0xe5,0x1b,0xb9,0x82,0xe1,0xbc,0xb1,0x83,0xe5,0x02,0xff,0xff,0xea, -0x04,0x30,0xa0,0xe3,0xa6,0xff,0xff,0xea,0x05,0x30,0xa0,0xe3,0xa4,0xff,0xff,0xea, -0x02,0x30,0xa0,0xe3,0xa2,0xff,0xff,0xea,0x1c,0x00,0x9d,0xe5,0x28,0x20,0x9f,0xe5, -0x01,0x00,0x80,0xe2,0x02,0x00,0x50,0xe1,0x1c,0x00,0x8d,0xe5,0x6e,0xff,0xff,0x1a, -0x9e,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe5,0x69,0xff,0xff,0xea,0x84,0x4c,0x01,0x00, -0x48,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x18,0x10,0x00,0x00,0x40,0x42,0x0f,0x00, -0xf0,0x4f,0x2d,0xe9,0x44,0xd0,0x4d,0xe2,0x00,0x4f,0x9f,0xe5,0x00,0xb0,0xa0,0xe1, -0x00,0x90,0xa0,0xe3,0xf8,0x3e,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0xf4,0x5e,0x9f,0xe5, -0xf4,0x6e,0x9f,0xe5,0x03,0x30,0x84,0xe0,0xf0,0x1e,0x9f,0xe5,0x0c,0x30,0x8d,0xe5, -0xec,0x3e,0x9f,0xe5,0x06,0x60,0x84,0xe0,0x05,0x00,0x94,0xe7,0x14,0x10,0x8d,0xe5, -0x03,0x30,0x84,0xe0,0x10,0x30,0x8d,0xe5,0x0d,0x00,0x00,0xea,0x04,0x00,0x18,0xe3, -0x04,0x30,0x90,0x15,0x05,0x30,0x94,0x07,0x84,0x21,0x93,0x15,0x04,0x30,0x93,0x05, -0x22,0x2d,0xa0,0x11,0x03,0x20,0x02,0x12,0x00,0x20,0x80,0x15,0xac,0x21,0x93,0xe5, -0x01,0x00,0x12,0xe3,0xeb,0x00,0x00,0x1a,0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x0f,0x01,0x00,0x1a,0x04,0x20,0x90,0xe5,0x44,0x31,0x92,0xe5,0x44,0x31,0x82,0xe5, -0xc5,0x24,0xa0,0xe3,0x04,0x24,0x92,0xe5,0x01,0x27,0x12,0xe2,0xb8,0x01,0x00,0x0a, -0x83,0x8b,0xa0,0xe1,0x40,0x00,0x13,0xe3,0xa8,0x8b,0xa0,0xe1,0xe6,0xff,0xff,0x0a, -0x04,0x30,0x90,0xe5,0x00,0x20,0xa0,0xe3,0x68,0x7e,0x9f,0xe5,0x05,0x90,0x84,0xe0, -0x54,0x21,0x83,0xe5,0x04,0x30,0x90,0xe5,0xac,0x21,0x93,0xe5,0xac,0x21,0x83,0xe5, -0x04,0x30,0x90,0xe5,0xbc,0x21,0x93,0xe5,0xbc,0x21,0x83,0xe5,0x00,0x20,0xe0,0xe3, -0x04,0x30,0x90,0xe5,0xb4,0x21,0x83,0xe5,0x04,0x30,0x90,0xe5,0xb4,0xa1,0x93,0xe5, -0x05,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x10,0x93,0xe5, -0x6d,0x2f,0x81,0xe2,0xb4,0xa1,0x91,0xe5,0x12,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x13,0x3b,0x00,0xeb,0x00,0x00,0x5a,0xe3,0xf5,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x05,0x90,0x84,0xe0,0xfc,0x7d,0x9f,0xe5,0x04,0x30,0x93,0xe5,0xb8,0xa1,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x20,0x93,0xe5, -0xb8,0xa1,0x92,0xe5,0x00,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x04,0x3b,0x00,0xeb, -0x00,0x00,0x5a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0, -0xc0,0x7d,0x9f,0xe5,0x04,0x30,0x93,0xe5,0xb0,0x91,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x20,0x93,0xe5,0xb0,0x91,0x92,0xe5, -0xf1,0x01,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xf5,0x3a,0x00,0xeb,0x00,0x00,0x59,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x04,0x20,0x93,0xe5,0x6d,0x2f,0x82,0xe2, -0x02,0x10,0xa0,0xe3,0x7c,0x7d,0x9f,0xe5,0x00,0x10,0x82,0xe5,0x05,0x20,0x84,0xe0, -0x04,0x30,0x93,0xe5,0xb4,0xa1,0x93,0xe5,0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1, -0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb4,0xa1,0x93,0xe5,0x27,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xde,0x3a,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x2c,0x7d,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0, -0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0xb8,0xa1,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0xb8,0xa1,0x93,0xe5,0x15,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xcc,0x3a,0x00,0xeb, -0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0xe4,0x7c,0x9f,0xe5, -0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x04,0x30,0x93,0xe5,0xb0,0xa1,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb0,0xa1,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xba,0x3a,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x06,0x50,0xa0,0xe1,0x08,0x60,0x9d,0xe5,0x00,0x10,0xa0,0xe3, -0x20,0x20,0xa0,0xe3,0x05,0xa0,0x84,0xe0,0x88,0x7c,0x9f,0xe5,0x00,0x00,0x96,0xe5, -0x40,0x00,0x80,0xe2,0x7f,0x3a,0x00,0xeb,0x00,0x30,0x96,0xe5,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x80,0x00,0x80,0xe2,0x79,0x3a,0x00,0xeb, -0x05,0x30,0x94,0xe7,0x00,0x00,0xa0,0xe3,0x00,0x10,0x96,0xe5,0x04,0x20,0x93,0xe5, -0x8c,0x00,0x81,0xe5,0x9c,0x00,0x81,0xe5,0xbc,0x11,0x92,0xe5,0x02,0x10,0x81,0xe3, -0xbc,0x11,0x82,0xe5,0x02,0x18,0xa0,0xe3,0x04,0x20,0x93,0xe5,0xb4,0x11,0x82,0xe5, -0x04,0x30,0x93,0xe5,0xb4,0x31,0x93,0xe5,0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1, -0x04,0x50,0xa0,0xe1,0x0a,0x40,0xa0,0xe1,0x03,0xa0,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb4,0xa1,0x93,0xe5, -0x27,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x8d,0x3a,0x00,0xeb,0x02,0x08,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0xe8,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7, -0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5, -0xb8,0xa1,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0xb8,0xa1,0x93,0xe5,0x15,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x7b,0x3a,0x00,0xeb,0x02,0x08,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1, -0xa0,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1, -0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0xb0,0xa1,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb0,0xa1,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x69,0x3a,0x00,0xeb,0x02,0x08,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x06,0x50,0xa0,0xe1,0x08,0x60,0x9d,0xe5, -0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x00,0x00,0x96,0xe5,0x60,0x00,0x80,0xe2, -0x30,0x3a,0x00,0xeb,0x00,0x30,0x96,0xe5,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3, -0x80,0x00,0x93,0xe5,0xc0,0x00,0x80,0xe2,0x2a,0x3a,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x00,0x30,0xa0,0xe3,0x00,0x10,0x96,0xe5,0x04,0x20,0x90,0xe5,0x90,0x30,0x81,0xe5, -0xa0,0x30,0x81,0xe5,0xbc,0x11,0x92,0xe5,0x02,0x18,0x81,0xe3,0xbc,0x11,0x82,0xe5, -0x10,0x30,0xc0,0xe5,0x08,0xff,0xff,0xea,0x00,0x10,0x96,0xe5,0x08,0x00,0x80,0xe2, -0xac,0x21,0x83,0xe5,0x08,0x20,0xa0,0xe3,0x00,0x90,0xa0,0xe3,0x05,0x70,0x84,0xe0, -0x80,0x10,0x91,0xe5,0x28,0x10,0x81,0xe2,0x14,0x3a,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x3c,0x90,0xcd,0xe5,0x3d,0x90,0xcd,0xe5,0x38,0x90,0xcd,0xe5,0x39,0x90,0xcd,0xe5, -0x08,0x20,0xd0,0xe5,0x0f,0x80,0xd0,0xe5,0x0e,0x30,0xd0,0xe5,0x02,0x00,0x52,0xe3, -0x08,0x84,0x83,0xe1,0xe0,0x00,0x00,0x0a,0x14,0x00,0x00,0x8a,0x09,0x00,0x52,0xe1, -0x1e,0x00,0x00,0x1a,0x09,0x30,0xd0,0xe5,0x05,0x00,0x53,0xe3,0x43,0x01,0x00,0x0a, -0x09,0x00,0x53,0xe3,0x1e,0x02,0x00,0x0a,0x03,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11, -0x11,0x00,0x00,0x1a,0x0a,0x30,0xd0,0xe5,0x02,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11, -0x04,0x02,0x00,0x0a,0x05,0x00,0x94,0xe7,0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0xef,0xfe,0xff,0x0a,0x09,0x00,0xa0,0xe1,0x44,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x81,0x00,0x52,0xe3,0x83,0x00,0x00,0x0a,0x82,0x00,0x52,0xe3,0xab,0x00,0x00,0x0a, -0x80,0x00,0x52,0xe3,0x9b,0x00,0x00,0x0a,0x00,0x90,0xa0,0xe3,0x04,0x30,0x90,0xe5, -0x34,0x2a,0x9f,0xe5,0x05,0x00,0x94,0xe7,0xc0,0x21,0x83,0xe5,0xed,0xff,0xff,0xea, -0x01,0x00,0x52,0xe3,0xf7,0xff,0xff,0x1a,0x00,0x30,0x96,0xe5,0x04,0x20,0x90,0xe5, -0x10,0x8a,0x9f,0xe5,0x8c,0x90,0x83,0xe5,0x90,0x90,0x83,0xe5,0x02,0x30,0xa0,0xe3, -0xb4,0x31,0x82,0xe5,0x04,0x30,0x90,0xe5,0xb4,0xa1,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x97,0xe5,0x01,0x80,0x58,0xe2,0x04,0x30,0x93,0xe5,0xb4,0xa1,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x05,0x3a,0x00,0xeb,0x02,0x00,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0xc4,0x79,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xf6,0x39,0x00,0xeb,0x02,0x00,0x18,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0x88,0x79,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0xb0,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xe7,0x39,0x00,0xeb,0x02,0x00,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x02,0x18,0xa0,0xe3,0x4c,0x79,0x9f,0xe5,0x05,0xa0,0x84,0xe0,0x04,0x20,0x93,0xe5, -0xb4,0x11,0x82,0xe5,0x04,0x30,0x93,0xe5,0xb4,0x81,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb4,0x81,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xd5,0x39,0x00,0xeb,0x02,0x08,0x18,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0x04,0x79,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0xb8,0x81,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xc6,0x39,0x00,0xeb,0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0xc8,0x78,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0xb0,0x81,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0xb0,0x81,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xb7,0x39,0x00,0xeb,0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0xc0,0x94,0xe7, -0x01,0x70,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x07,0x10,0xa0,0xe1,0x02,0x30,0xa0,0xe1, -0x04,0x80,0x9c,0xe5,0x0c,0x00,0xa0,0xe1,0xc4,0xe1,0x98,0xe5,0x40,0xe0,0x8e,0xe3, -0xc4,0xe1,0x88,0xe5,0x04,0xc0,0x9c,0xe5,0xc4,0xe1,0x9c,0xe5,0x01,0xe5,0x8e,0xe3, -0xc4,0xe1,0x8c,0xe5,0x00,0x70,0x8d,0xe5,0x9a,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2, -0x77,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7,0x0a,0x30,0xd0,0xe5,0x13,0x30,0xc0,0xe5, -0x05,0x00,0x94,0xe7,0x73,0xff,0xff,0xea,0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x08,0x70,0xa0,0x01,0x3c,0x10,0x8d,0x02,0x5e,0x00,0x00,0x1a,0x0b,0x00,0xa0,0xe1, -0x07,0x20,0xa0,0xe1,0x01,0xa0,0xa0,0xe3,0x64,0x39,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x08,0x00,0x57,0xe1,0x07,0x30,0xa0,0x31,0x08,0x30,0xa0,0x21,0x0a,0x10,0xa0,0xe1, -0x0b,0x20,0xa0,0xe1,0x00,0xa0,0x8d,0xe5,0x82,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2, -0x5f,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7,0x09,0x10,0xa0,0xe1,0x09,0x20,0xa0,0xe1, -0x09,0x30,0xa0,0xe1,0x00,0xa0,0x8d,0xe5,0x7a,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1, -0x05,0x00,0x94,0xe7,0x57,0xff,0xff,0xea,0x09,0x30,0xd0,0xe5,0x06,0x00,0x53,0xe3, -0x52,0x00,0x00,0x0a,0x08,0x00,0x53,0xe3,0x89,0x00,0x00,0x0a,0x00,0x00,0x53,0xe3, -0x5d,0xff,0xff,0x1a,0x14,0x30,0x9d,0xe5,0x02,0x70,0xa0,0xe3,0x03,0x10,0x84,0xe0, -0xdd,0xff,0xff,0xea,0x10,0x20,0xc0,0xe5,0x21,0x90,0xa0,0xe3,0x4c,0xff,0xff,0xea, -0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x3e,0x00,0x00,0x1a,0x0d,0x20,0xd0,0xe5, -0x0c,0x30,0xd0,0xe5,0x02,0x34,0x83,0xe1,0x01,0x00,0x53,0xe3,0x6c,0x01,0x00,0x0a, -0x6a,0x00,0x00,0x2a,0x04,0x30,0x90,0xe5,0xc0,0x21,0x93,0xe5,0x01,0x00,0x12,0xe3, -0x3b,0x01,0x00,0x1a,0x80,0x00,0x12,0xe3,0xa4,0x00,0x00,0x0a,0x00,0x20,0x96,0xe5, -0x80,0x10,0x92,0xe5,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x9f,0x00,0x00,0x1a, -0xb0,0x11,0x93,0xe5,0x01,0x00,0x11,0xe3,0x9c,0x00,0x00,0x1a,0xb8,0x31,0x93,0xe5, -0x01,0x00,0x13,0xe3,0x84,0x30,0x92,0x05,0x98,0x00,0x00,0xea,0x09,0x30,0xd0,0xe5, -0x01,0x00,0x53,0xe3,0x20,0x00,0x00,0x0a,0x03,0x00,0x53,0xe3,0x36,0xff,0xff,0x1a, -0x0a,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x1e,0x00,0x00,0x1a,0x0d,0x10,0xd0,0xe5, -0x0c,0x20,0xd0,0xe5,0x01,0x24,0x82,0xe1,0x01,0x00,0x52,0xe3,0x74,0x00,0x00,0x0a, -0x73,0x00,0x00,0x3a,0x80,0x00,0x52,0xe3,0x71,0x00,0x00,0x0a,0x81,0x00,0x52,0xe3, -0x3a,0x00,0x00,0x1a,0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x01,0x28,0x82,0xe3, -0xc4,0x21,0x83,0xe5,0x01,0xc0,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x0c,0x10,0xa0,0xe1, -0x02,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x32,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1, -0x05,0x00,0x94,0xe7,0x0f,0xff,0xff,0xea,0x0a,0x00,0x53,0xe3,0x13,0x10,0x80,0x02, -0x08,0x70,0xa0,0x01,0x18,0xff,0xff,0x1a,0x9b,0xff,0xff,0xea,0x0a,0x30,0xd0,0xe5, -0x00,0x00,0x53,0xe3,0x1b,0x00,0x00,0x0a,0x04,0x30,0x90,0xe5,0x05,0x00,0x94,0xe7, -0xc4,0x21,0x93,0xe5,0x01,0x20,0x82,0xe3,0xc4,0x21,0x83,0xe5,0x01,0xff,0xff,0xea, -0x34,0x90,0x8d,0xe5,0x30,0x90,0x8d,0xe5,0x2c,0x90,0x8d,0xe5,0xec,0x42,0x00,0xeb, -0x00,0xa0,0xa0,0xe1,0xf1,0x42,0x00,0xeb,0x00,0x90,0xa0,0xe1,0xf6,0x42,0x00,0xeb, -0x00,0x30,0xa0,0xe1,0x00,0x00,0x97,0xe5,0x0b,0x20,0xd0,0xe5,0x01,0x20,0x42,0xe2, -0x06,0x00,0x52,0xe3,0x02,0xf1,0x8f,0x90,0xfe,0xfe,0xff,0xea,0xc2,0x00,0x00,0xea, -0x9f,0x00,0x00,0xea,0x93,0x00,0x00,0xea,0xfa,0xfe,0xff,0xea,0xf9,0xfe,0xff,0xea, -0x7a,0x00,0x00,0xea,0x58,0x00,0x00,0xea,0x0d,0x10,0xd0,0xe5,0x0c,0x20,0xd0,0xe5, -0x01,0x24,0x82,0xe1,0x01,0x00,0x52,0xe3,0x30,0x00,0x00,0x0a,0x2f,0x00,0x00,0x3a, -0x80,0x00,0x52,0xe3,0x2d,0x00,0x00,0x0a,0x81,0x00,0x52,0xe3,0x32,0x01,0x00,0x0a, -0x04,0x20,0x90,0xe5,0x03,0x90,0xa0,0xe1,0x05,0x00,0x94,0xe7,0xc4,0x31,0x92,0xe5, -0x01,0x30,0x83,0xe3,0xc4,0x31,0x82,0xe5,0xda,0xfe,0xff,0xea,0x6d,0x2f,0x82,0xe2, -0x03,0x90,0xa0,0xe3,0x11,0xfe,0xff,0xea,0x03,0x90,0xa0,0xe3,0x0f,0xfe,0xff,0xea, -0x80,0x00,0x53,0xe3,0x2b,0x00,0x00,0x0a,0x81,0x00,0x53,0xe3,0x0f,0x01,0x00,0x0a, -0x04,0x30,0x90,0xe5,0x00,0x90,0xa0,0xe3,0x05,0x00,0x94,0xe7,0xc4,0x21,0x93,0xe5, -0x01,0x20,0x82,0xe3,0xc4,0x21,0x83,0xe5,0x01,0x30,0xa0,0xe3,0x38,0x30,0xcd,0xe5, -0xc8,0xfe,0xff,0xea,0x12,0x10,0x80,0xe2,0x08,0x70,0xa0,0xe1,0x56,0xff,0xff,0xea, -0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0xe0,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2,0xbd,0xfe,0xff,0x1a,0x00,0x00,0x97,0xe5, -0x04,0x30,0x90,0xe5,0x0a,0x10,0xd0,0xe5,0x05,0x00,0x94,0xe7,0x54,0x21,0x93,0xe5, -0xfe,0x24,0xc2,0xe3,0x81,0x2c,0x82,0xe1,0x54,0x21,0x83,0xe5,0xb5,0xfe,0xff,0xea, -0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x01,0x20,0xc2,0xe3,0xc4,0x21,0x83,0xe5, -0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x40,0x20,0x82,0xe3,0xc4,0x21,0x83,0xe5, -0x93,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x01,0x20,0x82,0xe3, -0xc4,0x21,0x83,0xe5,0x8e,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0xc0,0x21,0x93,0xe5, -0x01,0x08,0x12,0xe3,0xa2,0x00,0x00,0x1a,0x02,0x05,0x12,0xe3,0x0b,0x00,0x00,0x0a, -0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5,0x40,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5, -0x68,0x00,0x11,0xe3,0x05,0x00,0x00,0x1a,0xb0,0x11,0x93,0xe5,0x01,0x08,0x11,0xe3, -0x02,0x00,0x00,0x1a,0xb8,0x31,0x93,0xe5,0x01,0x08,0x13,0xe3,0x88,0x30,0x92,0x05, -0x08,0x70,0xa0,0xe1,0x38,0x10,0x8d,0xe2,0x23,0xff,0xff,0xea,0x00,0x00,0x5a,0xe3, -0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2, -0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a, -0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5, -0x0c,0x00,0x9d,0xe5,0x34,0x20,0x9d,0xe5,0x05,0x30,0x94,0xe7,0x0e,0x20,0xc0,0xe5, -0x30,0x20,0x9d,0xe5,0x0f,0x20,0xc0,0xe5,0x2c,0x20,0x9d,0xe5,0x10,0x20,0xc0,0xe5, -0x00,0x30,0x93,0xe5,0x02,0x00,0x53,0xe3,0xdc,0x00,0x00,0x0a,0x0c,0x10,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe3,0x20,0x70,0xa0,0xe3,0x16,0x20,0xc1,0xe5, -0x17,0x30,0xc1,0xe5,0x1d,0x20,0xc1,0xe5,0x1e,0x30,0xc1,0xe5,0x02,0xff,0xff,0xea, -0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2, -0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3, -0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5, -0x2c,0x30,0x8d,0xe5,0x10,0x10,0x9d,0xe5,0x0a,0x70,0xa0,0xe3,0x34,0x30,0x9d,0xe5, -0x04,0x30,0xc1,0xe5,0x30,0x30,0x9d,0xe5,0x05,0x30,0xc1,0xe5,0x2c,0x30,0x9d,0xe5, -0x06,0x30,0xc1,0xe5,0xec,0xfe,0xff,0xea,0x0a,0x20,0xd0,0xe5,0x02,0x00,0x52,0xe3, -0xd1,0x00,0x00,0x0a,0x03,0x00,0x52,0xe3,0xc7,0x00,0x00,0x0a,0x01,0x00,0x52,0xe3, -0xbf,0x00,0x00,0x0a,0xc4,0x13,0x9f,0xe5,0x04,0x70,0xa0,0xe3,0x01,0x10,0x84,0xe0, -0xe1,0xfe,0xff,0xea,0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2, -0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1, -0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5, -0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5,0x84,0x33,0x9f,0xe5,0x34,0x10,0x9d,0xe5, -0x05,0x20,0x94,0xe7,0x03,0x30,0x84,0xe0,0x0e,0x10,0xc3,0xe5,0x30,0x10,0x9d,0xe5, -0x0f,0x10,0xc3,0xe5,0x2c,0x10,0x9d,0xe5,0x10,0x10,0xc3,0xe5,0x00,0x20,0x92,0xe5, -0x02,0x00,0x52,0xe3,0x91,0x00,0x00,0x0a,0x40,0x00,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x16,0x00,0xc3,0xe5,0x20,0x70,0xa0,0xe3,0x17,0x20,0xc3,0xe5,0x03,0x10,0xa0,0xe1, -0x1d,0x00,0xc3,0xe5,0x1e,0x20,0xc3,0xe5,0xbf,0xfe,0xff,0xea,0x15,0x42,0x00,0xeb, -0x00,0x30,0x50,0xe2,0x06,0x00,0x00,0x0a,0x24,0x00,0x8d,0xe2,0x28,0x10,0x8d,0xe2, -0x20,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x13,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3, -0x12,0x00,0x00,0x1a,0x07,0x32,0xa0,0xe3,0x1c,0x00,0x8d,0xe2,0x04,0x78,0x93,0xe5, -0x24,0x42,0x00,0xeb,0xfc,0x12,0x9f,0xe5,0x27,0x34,0xa0,0xe1,0x07,0x0e,0xa0,0xe1, -0x24,0x10,0x8d,0xe5,0x07,0x22,0xa0,0xe1,0x1c,0x10,0x9d,0xe5,0xff,0x30,0x03,0xe2, -0x07,0x76,0xa0,0xe1,0x20,0x38,0x83,0xe1,0x0f,0x10,0x01,0xe2,0x0f,0x2c,0x02,0xe2, -0x27,0x2e,0x82,0xe1,0x01,0x34,0x83,0xe1,0x20,0x20,0x8d,0xe5,0x28,0x30,0x8d,0xe5, -0x24,0x10,0x9d,0xe5,0x12,0x70,0xa0,0xe3,0x28,0x00,0x9d,0xe5,0x20,0x20,0x9d,0xe5, -0xb4,0x32,0x9f,0xe5,0x21,0xa4,0xa0,0xe1,0x20,0xe4,0xa0,0xe1,0x22,0xc4,0xa0,0xe1, -0x03,0x30,0x84,0xe0,0x08,0x10,0xc3,0xe5,0x03,0x10,0xa0,0xe1,0x09,0xa0,0xc3,0xe5, -0x0a,0x00,0xc3,0xe5,0x0b,0xe0,0xc3,0xe5,0x0c,0x20,0xc3,0xe5,0x0d,0xc0,0xc3,0xe5, -0x91,0xfe,0xff,0xea,0x40,0x10,0x8d,0xe2,0x01,0x30,0xa0,0xe3,0x08,0x30,0x61,0xe5, -0x08,0x70,0xa0,0xe1,0x8c,0xfe,0xff,0xea,0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x16,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2, -0xf3,0xfd,0xff,0x1a,0x00,0x30,0x97,0xe5,0x0d,0x60,0xd3,0xe5,0x0f,0x60,0x06,0xe2, -0x04,0x00,0x56,0xe3,0x76,0x00,0x00,0x0a,0x05,0x30,0x94,0xe7,0x04,0x30,0x93,0xe5, -0x84,0x21,0x93,0xe5,0x0f,0x28,0xc2,0xe3,0x06,0x68,0x82,0xe1,0x84,0x61,0x83,0xe5, -0xfe,0xff,0xff,0xea,0x01,0x80,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x08,0x10,0xa0,0xe1, -0x00,0x80,0x8d,0xe5,0x03,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2,0xe0,0xfd,0xff,0x1a, -0x00,0x30,0x97,0xe5,0x02,0x10,0xa0,0xe3,0x0a,0x20,0xd3,0xe5,0x03,0x00,0xa0,0xe1, -0x12,0x20,0xc3,0xe5,0x88,0xfa,0xff,0xeb,0x00,0x00,0x97,0xe5,0x03,0x10,0xa0,0xe3, -0x85,0xfa,0xff,0xeb,0x00,0x00,0x97,0xe5,0x10,0x80,0xc0,0xe5,0x05,0x00,0x94,0xe7, -0xd4,0xfd,0xff,0xea,0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x01,0x00,0x12,0xe3, -0xcf,0xff,0xff,0x1a,0x80,0x00,0x12,0xe3,0x38,0xff,0xff,0x0a,0x00,0x20,0x96,0xe5, -0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3, -0x32,0xff,0xff,0x1a,0xb0,0x11,0x93,0xe5,0x02,0x00,0x11,0xe3,0x2f,0xff,0xff,0x1a, -0xb8,0x31,0x93,0xe5,0x02,0x00,0x13,0xe3,0x8c,0x30,0x92,0x05,0x2b,0xff,0xff,0xea, -0x04,0x30,0x90,0xe5,0xc4,0x21,0x93,0xe5,0x01,0x08,0x12,0xe3,0xbc,0xff,0xff,0x1a, -0x02,0x05,0x12,0xe3,0x25,0xff,0xff,0x0a,0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5, -0xc0,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x1f,0xff,0xff,0x1a, -0xb0,0x11,0x93,0xe5,0x02,0x08,0x11,0xe3,0x1c,0xff,0xff,0x1a,0xb8,0x31,0x93,0xe5, -0x02,0x08,0x13,0xe3,0x90,0x30,0x92,0x05,0x18,0xff,0xff,0xea,0x04,0x30,0x90,0xe5, -0xc4,0x21,0x93,0xe5,0x01,0x28,0xc2,0xe3,0xc4,0x21,0x83,0xe5,0x04,0x30,0x90,0xe5, -0xc4,0x21,0x93,0xe5,0x01,0x25,0x82,0xe3,0xc4,0x21,0x83,0xe5,0x8c,0xfe,0xff,0xea, -0x00,0x10,0xa0,0xe3,0x17,0x20,0xc3,0xe5,0x16,0x10,0xc3,0xe5,0x20,0x70,0xa0,0xe3, -0x1d,0x10,0xc3,0xe5,0x03,0x10,0xa0,0xe1,0x1e,0x20,0xc3,0xe5,0x2e,0xfe,0xff,0xea, -0x40,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x16,0x20,0xc0,0xe5,0x20,0x70,0xa0,0xe3, -0x17,0x30,0xc0,0xe5,0x00,0x10,0xa0,0xe1,0x1d,0x20,0xc0,0xe5,0x1e,0x30,0xc0,0xe5, -0x25,0xfe,0xff,0xea,0xd4,0x10,0x9f,0xe5,0x01,0x70,0xd4,0xe7,0x01,0x10,0x84,0xe0, -0x1a,0x00,0x57,0xe3,0x1a,0x70,0xa0,0x23,0x1f,0xfe,0xff,0xea,0x00,0x00,0x53,0xe3, -0x0f,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1,0x13,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2, -0x0b,0x00,0x00,0x0a,0x00,0x70,0xd1,0xe5,0x17,0xfe,0xff,0xea,0x00,0x00,0x59,0xe3, -0x03,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1,0x19,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2, -0xf7,0xff,0xff,0x1a,0x88,0x10,0x9f,0xe5,0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5, -0x0d,0xfe,0xff,0xea,0x7c,0x10,0x9f,0xe5,0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5, -0x09,0xfe,0xff,0xea,0x70,0x70,0x9f,0xe5,0x35,0x20,0xa0,0xe3,0x6c,0x10,0x9f,0xe5, -0x07,0x70,0x84,0xe0,0x10,0x00,0x97,0xe5,0x01,0x10,0x84,0xe0,0x6b,0x37,0x00,0xeb, -0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x35,0x30,0x83,0xe2, -0x05,0x00,0x94,0xe7,0x10,0x20,0x97,0xe5,0x8a,0xfa,0xff,0xeb,0x79,0xff,0xff,0xea, -0xc8,0x45,0x01,0x00,0x38,0x02,0x00,0x00,0x48,0x10,0x00,0x00,0x18,0x10,0x00,0x00, -0xe0,0x01,0x00,0x00,0x0c,0x02,0x00,0x00,0xa0,0x86,0x01,0x00,0x81,0x00,0x81,0x00, -0x6c,0x02,0x00,0x00,0x18,0x02,0x00,0x00,0x55,0x09,0x00,0x00,0x58,0x02,0x00,0x00, -0xe4,0x01,0x00,0x00,0x70,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x34,0x10,0x00,0x00, -0x24,0xee,0xff,0xff,0x8c,0x30,0x9f,0xe5,0x01,0xc0,0xa0,0xe3,0xf0,0x07,0x2d,0xe9, -0xc5,0x64,0xa0,0xe3,0x80,0xa0,0x9f,0xe5,0x00,0x40,0xa0,0xe3,0x03,0x30,0x8f,0xe0, -0x78,0x70,0x9f,0xe5,0x84,0x91,0x96,0xe5,0x0a,0x20,0x83,0xe0,0x70,0x80,0x9f,0xe5, -0x0a,0x70,0x83,0xe7,0x6c,0xa0,0x9f,0xe5,0x6c,0x50,0x9f,0xe5,0x29,0x9d,0xa0,0xe1, -0x0a,0x80,0x83,0xe7,0x03,0x90,0x09,0xe2,0x60,0xa0,0x9f,0xe5,0x05,0x10,0x83,0xe0, -0x0a,0x10,0x83,0xe7,0x58,0xa0,0x9f,0xe5,0x10,0xa0,0x82,0xe5,0x54,0xa0,0x9f,0xe5, -0x80,0xa0,0x88,0xe5,0x01,0x8a,0xa0,0xe3,0x04,0x80,0x82,0xe5,0x08,0x70,0x82,0xe5, -0x0c,0x40,0x82,0xe5,0x10,0xc0,0xc1,0xe5,0x11,0xc0,0xc1,0xe5,0x04,0x60,0x81,0xe5, -0x05,0x90,0x83,0xe7,0x14,0xc0,0xc1,0xe5,0x00,0x20,0x80,0xe5,0x04,0x00,0xa0,0xe1, -0xf0,0x07,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x74,0x36,0x01,0x00,0x34,0x10,0x00,0x00, -0x00,0x50,0x00,0x40,0x00,0x60,0x00,0x40,0x18,0x10,0x00,0x00,0x1c,0x10,0x00,0x00, -0x48,0x10,0x00,0x00,0x00,0x30,0x00,0x40,0x00,0x10,0x00,0xc5,0x70,0x40,0x2d,0xe9, -0x00,0xc0,0xa0,0xe3,0x7c,0xe0,0x9f,0xe5,0x0c,0x10,0xa0,0xe1,0x14,0x20,0xa0,0xe3, -0x74,0x30,0x9f,0xe5,0x0e,0xe0,0x8f,0xe0,0x03,0x30,0x9e,0xe7,0x04,0x40,0x93,0xe5, -0x54,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5,0xac,0x51,0x94,0xe5,0xac,0x51,0x84,0xe5, -0x04,0x40,0x93,0xe5,0xbc,0x51,0x94,0xe5,0xbc,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5, -0x40,0x51,0x94,0xe5,0x01,0x50,0xc5,0xe3,0x40,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5, -0xa8,0x51,0x94,0xe5,0x03,0x50,0xc5,0xe3,0xa8,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5, -0x48,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5,0xa4,0xc1,0x84,0xe5,0x1c,0x40,0x9f,0xe5, -0x14,0xc0,0xc3,0xe5,0x04,0xc0,0x8e,0xe7,0x06,0x37,0x00,0xeb,0xc8,0x00,0xa0,0xe3, -0x70,0x40,0xbd,0xe8,0x70,0x3e,0x00,0xea,0xbc,0x35,0x01,0x00,0x48,0x10,0x00,0x00, -0x18,0x10,0x00,0x00,0xc5,0x34,0xa0,0xe3,0xf0,0x4f,0x2d,0xe9,0x04,0x34,0x93,0xe5, -0x34,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1,0xcc,0x93,0x9f,0xe5,0x10,0x20,0x8d,0xe5, -0x23,0x39,0xa0,0xe1,0x58,0x80,0x9d,0xe5,0x09,0x90,0x8f,0xe0,0x01,0x30,0x13,0xe2, -0x05,0x00,0x00,0x1a,0xb4,0x23,0x9f,0xe5,0xb4,0x03,0x9f,0xe5,0x02,0x20,0x99,0xe7, -0x10,0x30,0xc2,0xe5,0x34,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x10,0x00,0x90,0xe5, -0x08,0x10,0x8d,0xe5,0xc1,0xfb,0xff,0xeb,0x10,0x20,0x9d,0xe5,0x08,0x10,0x9d,0xe5, -0x00,0x00,0x52,0xe3,0x10,0x00,0x9d,0x05,0xf5,0xff,0xff,0x0a,0x7c,0x33,0x9f,0xe5, -0x00,0x20,0xa0,0xe3,0x14,0x10,0x8d,0xe5,0x00,0x10,0xa0,0xe3,0x74,0x53,0x9f,0xe5, -0x00,0x60,0xa0,0xe3,0x03,0x40,0x89,0xe0,0x20,0x30,0x8d,0xe5,0x18,0x10,0x8d,0xe5, -0x1c,0x20,0x8d,0xe5,0xfa,0x3f,0xa0,0xe3,0x98,0x13,0x82,0xe0,0x28,0x10,0x8d,0xe5, -0x2c,0x20,0x8d,0xe5,0x14,0x10,0x9d,0xe5,0x05,0x50,0x89,0xe0,0x24,0x90,0x8d,0xe5, -0x08,0x90,0xa0,0xe1,0x10,0x20,0x9d,0xe5,0x01,0x01,0x97,0xe8,0x08,0x00,0x52,0xe1, -0x02,0x80,0xa0,0x31,0x08,0x20,0xa0,0xe1,0xcc,0x36,0x00,0xeb,0x00,0x00,0x94,0xe5, -0x01,0x0a,0x58,0xe3,0x08,0x30,0xa0,0x31,0x01,0x3a,0xa0,0x23,0x00,0x20,0x97,0xe5, -0x03,0x10,0xa0,0xe3,0x00,0x60,0x8d,0xe5,0xea,0xf9,0xff,0xeb,0x01,0x00,0x79,0xe3, -0x06,0x00,0x00,0x0a,0xe1,0x36,0x00,0xeb,0x28,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8, -0x00,0x20,0x92,0xe0,0x01,0x30,0xa3,0xe0,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5, -0xc5,0x84,0xa0,0xe3,0x02,0xa8,0xa0,0xe3,0x04,0x34,0x98,0xe5,0x01,0x07,0x13,0xe3, -0x66,0x00,0x00,0x1a,0x00,0x30,0x94,0xe5,0x11,0x20,0xd3,0xe5,0x00,0x00,0x52,0xe3, -0x44,0x00,0x00,0x0a,0x04,0x20,0x93,0xe5,0xbc,0xb2,0x9f,0xe5,0xb4,0xa1,0x82,0xe5, -0x04,0x30,0x93,0xe5,0xb4,0x31,0x93,0xe5,0x0c,0x50,0x8d,0xe5,0x04,0x50,0xa0,0xe1, -0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2, -0x04,0x30,0x93,0xe5,0xb4,0x41,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xd3,0x36,0x00,0xeb,0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5, -0x74,0xb2,0x9f,0xe5,0x04,0x30,0x93,0xe5,0xb8,0x31,0x93,0xe5,0x03,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5, -0xb8,0x41,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xc4,0x36,0x00,0xeb, -0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x38,0xb2,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0xb0,0x31,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0xb0,0x41,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xb5,0x36,0x00,0xeb,0x02,0x08,0x14,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x0c,0x50,0x9d,0xe5,0x00,0x10,0xa0,0xe3, -0x20,0x20,0xa0,0xe3,0x00,0x00,0x95,0xe5,0x60,0x00,0x80,0xe2,0x7d,0x36,0x00,0xeb, -0x00,0x30,0x95,0xe5,0x30,0x20,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x80,0x00,0x93,0xe5, -0xc0,0x00,0x80,0xe2,0x77,0x36,0x00,0xeb,0x00,0x30,0x94,0xe5,0x00,0x20,0x95,0xe5, -0x04,0x30,0x93,0xe5,0x90,0x60,0x82,0xe5,0xa0,0x60,0x82,0xe5,0xbc,0x21,0x93,0xe5, -0x02,0x28,0x82,0xe3,0xbc,0x21,0x83,0xe5,0x02,0xb0,0xa0,0xe3,0x10,0x00,0x97,0xe5, -0x42,0xfb,0xff,0xeb,0x01,0x00,0x79,0xe3,0x05,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x97,0x36,0x00,0xeb,0x85,0x36,0x00,0xeb,0x1c,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe1, -0x53,0x00,0x00,0x9a,0x01,0x00,0x5b,0xe3,0x04,0x00,0x5b,0x13,0xa5,0xff,0xff,0x0a, -0xc5,0x34,0xa0,0xe3,0x24,0x90,0x9d,0xe5,0x04,0x34,0x93,0xe5,0x20,0x10,0x9d,0xe5, -0x23,0x39,0xa0,0xe1,0x01,0x20,0x99,0xe7,0x01,0x30,0x13,0xe2,0x10,0x30,0xc2,0x05, -0x4c,0x01,0x9f,0x05,0x66,0xff,0xff,0x0a,0x04,0x30,0x92,0xe5,0x4c,0x01,0x9f,0xe5, -0xc4,0x21,0x93,0xe5,0x01,0x20,0x82,0xe3,0xc4,0x21,0x83,0xe5,0x60,0xff,0xff,0xea, -0x00,0x30,0x94,0xe5,0x04,0x30,0x93,0xe5,0xc4,0x21,0x93,0xe5,0x71,0x0f,0x83,0xe2, -0x01,0x08,0x12,0xe3,0x15,0x00,0x00,0x1a,0x02,0x05,0x12,0xe3,0x17,0x00,0x00,0x0a, -0x00,0x10,0x95,0xe5,0x80,0x20,0x91,0xe5,0xc0,0x20,0x82,0xe2,0x0c,0xc0,0x92,0xe5, -0x68,0x00,0x1c,0xe3,0xd3,0xff,0xff,0x1a,0xb0,0xc1,0x93,0xe5,0x1b,0xbe,0x83,0xe2, -0x02,0x08,0x1c,0xe3,0x0b,0x00,0x00,0x1a,0xb8,0xc1,0x93,0xe5,0x6e,0x3f,0x83,0xe2, -0x0c,0x30,0x8d,0xe5,0x02,0xc8,0x1c,0xe2,0x06,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5, -0x00,0x00,0x53,0xe3,0x07,0x00,0x00,0x1a,0x03,0xb0,0xa0,0xe3,0xc6,0xff,0xff,0xea, -0x04,0xb0,0xa0,0xe3,0xc4,0xff,0xff,0xea,0x01,0xb0,0xa0,0xe3,0xc2,0xff,0xff,0xea, -0x05,0xb0,0xa0,0xe3,0xc0,0xff,0xff,0xea,0x00,0x30,0x90,0xe5,0x01,0x08,0x13,0xe3, -0x23,0x00,0x00,0x1a,0x02,0x35,0x13,0xe2,0x0e,0x00,0x00,0x0a,0x0c,0x30,0x92,0xe5, -0x68,0x00,0x13,0xe3,0x14,0x00,0x00,0x1a,0x00,0x30,0x9b,0xe5,0x02,0x38,0x13,0xe2, -0x11,0x00,0x00,0x1a,0x0c,0xc0,0x9d,0xe5,0x00,0x00,0x9c,0xe5,0x02,0x08,0x10,0xe3, -0x04,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5,0x00,0x00,0x53,0xe3,0xa0,0x30,0x91,0x15, -0x0c,0x20,0x92,0x15,0x22,0x38,0x43,0x10,0x10,0x10,0x9d,0xe5,0x03,0x10,0x51,0xe0, -0x10,0x10,0x8d,0xe5,0x0c,0x00,0x00,0x0a,0x14,0x20,0x9d,0xe5,0x03,0x20,0x82,0xe0, -0x14,0x20,0x8d,0xe5,0x02,0x10,0xa0,0xe1,0x3d,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3, -0xf4,0xff,0xff,0xea,0x02,0x00,0x00,0x1a,0x18,0xc0,0x9d,0xe5,0x00,0x00,0x5c,0xe1, -0xa7,0xff,0xff,0x8a,0x05,0x00,0xa0,0xe3,0x19,0xff,0xff,0xea,0x01,0x00,0xa0,0xe1, -0x17,0xff,0xff,0xea,0x0c,0x30,0xa0,0xe1,0xea,0xff,0xff,0xea,0x18,0x35,0x01,0x00, -0x48,0x10,0x00,0x00,0x05,0x30,0x04,0x00,0x18,0x10,0x00,0x00,0xa0,0x86,0x01,0x00, -0x04,0x30,0x04,0x00,0xc5,0xc4,0xa0,0xe3,0xf0,0x4f,0x2d,0xe9,0x04,0xc4,0x9c,0xe5, -0x3c,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1,0x01,0x40,0xa0,0xe1,0xec,0x94,0x9f,0xe5, -0x0c,0x20,0x8d,0xe5,0x2c,0xc9,0xa0,0xe1,0x18,0x30,0x8d,0xe5,0x09,0x90,0x8f,0xe0, -0x01,0xc0,0x1c,0xe2,0x05,0x00,0x00,0x1a,0xd4,0x34,0x9f,0xe5,0xd4,0x04,0x9f,0xe5, -0x03,0x30,0x99,0xe7,0x10,0xc0,0xc3,0xe5,0x3c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x10,0x00,0x90,0xe5,0xc1,0xfa,0xff,0xeb,0x18,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3, -0x00,0x30,0xa0,0x13,0x00,0x30,0x80,0x15,0x0c,0x50,0x97,0xe5,0x00,0x00,0x55,0xe3, -0x28,0x40,0x8d,0x05,0xfb,0x00,0x00,0x1a,0x94,0x24,0x9f,0xe5,0x02,0x80,0x99,0xe7, -0x2c,0x20,0x8d,0xe5,0x00,0x30,0x98,0xe5,0x02,0x00,0x53,0xe3,0x40,0x30,0xa0,0x13, -0x02,0x3c,0xa0,0x03,0x30,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x18,0x01,0x00,0x0a,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x10,0x00,0x8d,0xe5, -0x14,0x10,0x8d,0xe5,0x02,0x40,0x89,0xe0,0x64,0x00,0x9d,0xe5,0xfa,0x3f,0xa0,0xe3, -0x54,0x54,0x9f,0xe5,0x90,0x13,0x82,0xe0,0x04,0xa0,0x97,0xe5,0x34,0x90,0x8d,0xe5, -0x05,0x50,0x89,0xe0,0x00,0x90,0xa0,0xe1,0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5, -0x0c,0x10,0x9d,0xe5,0x0a,0x00,0x51,0xe1,0x05,0x00,0x00,0x8a,0x01,0x00,0xa0,0xe1, -0x30,0x10,0x9d,0xe5,0x97,0x3f,0x00,0xeb,0x0c,0x20,0x9d,0xe5,0x00,0x00,0x51,0xe3, -0x02,0xa0,0xa0,0x01,0x01,0x0a,0x5a,0xe3,0x01,0xaa,0xa0,0x23,0x00,0x60,0xa0,0xe3, -0x1c,0xa0,0x8d,0xe5,0x08,0x00,0xa0,0xe1,0x07,0xa0,0xa0,0xe1,0x00,0x20,0x9a,0xe5, -0x02,0x10,0xa0,0xe3,0x1c,0x30,0x9d,0xe5,0x00,0x60,0x8d,0xe5,0xd9,0xf8,0xff,0xeb, -0x01,0x00,0x79,0xe3,0x08,0x00,0x00,0x0a,0xd0,0x35,0x00,0xeb,0x00,0x00,0x59,0xe3, -0xec,0x00,0x00,0x0a,0x20,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8,0x00,0x20,0x92,0xe0, -0x01,0x30,0xa3,0xe0,0x10,0x20,0x8d,0xe5,0x14,0x30,0x8d,0xe5,0xc5,0x74,0xa0,0xe3, -0x02,0x80,0xa0,0xe3,0x04,0x34,0x97,0xe5,0x01,0x07,0x13,0xe3,0x5a,0x00,0x00,0x1a, -0x00,0x30,0x94,0xe5,0x11,0x20,0xd3,0xe5,0x00,0x00,0x52,0xe3,0x44,0x00,0x00,0x0a, -0x04,0x20,0x93,0xe5,0x94,0xb3,0x9f,0xe5,0xb4,0x81,0x82,0xe5,0x04,0x30,0x93,0xe5, -0xb4,0x31,0x93,0xe5,0x08,0x50,0x8d,0xe5,0x04,0x50,0xa0,0xe1,0x03,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5, -0xb4,0x41,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xc0,0x35,0x00,0xeb, -0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x4c,0xb3,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0xb8,0x31,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0xb8,0x41,0x93,0xe5, -0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xb1,0x35,0x00,0xeb,0x02,0x00,0x14,0xe3, -0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x10,0xb3,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0xb0,0x31,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5, -0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0xb0,0x41,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xa2,0x35,0x00,0xeb,0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x08,0x50,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3, -0x00,0x00,0x95,0xe5,0x40,0x00,0x80,0xe2,0x6a,0x35,0x00,0xeb,0x00,0x30,0x95,0xe5, -0x30,0x20,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x80,0x00,0x80,0xe2, -0x64,0x35,0x00,0xeb,0x00,0x30,0x94,0xe5,0x00,0x20,0x95,0xe5,0x04,0x30,0x93,0xe5, -0x8c,0x60,0x82,0xe5,0x9c,0x60,0x82,0xe5,0xbc,0x21,0x93,0xe5,0x02,0x20,0x82,0xe3, -0xbc,0x21,0x83,0xe5,0x02,0xb0,0xa0,0xe3,0x10,0x00,0x9a,0xe5,0x2f,0xfa,0xff,0xeb, -0x21,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a,0x01,0x00,0x79,0xe3,0x05,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x82,0x35,0x00,0xeb,0x70,0x35,0x00,0xeb,0x14,0x20,0x9d,0xe5, -0x01,0x00,0x52,0xe1,0x85,0x00,0x00,0x9a,0x01,0x00,0x5b,0xe3,0x04,0x00,0x5b,0x13, -0xa3,0xff,0xff,0x0a,0x00,0x00,0x94,0xe5,0x8f,0xff,0xff,0xea,0x00,0x30,0x94,0xe5, -0x04,0xc0,0x93,0xe5,0xc4,0x21,0x9c,0xe5,0x71,0x3f,0x8c,0xe2,0x01,0x00,0x12,0xe3, -0x14,0x00,0x00,0x1a,0x80,0x00,0x12,0xe3,0x16,0x00,0x00,0x0a,0x00,0x20,0x95,0xe5, -0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2,0x0c,0x00,0x91,0xe5,0x68,0x00,0x10,0xe3, -0xdf,0xff,0xff,0x1a,0xb0,0xe1,0x9c,0xe5,0x1b,0x0e,0x8c,0xe2,0x02,0x00,0x1e,0xe3, -0x0a,0x00,0x00,0x1a,0xb8,0xb1,0x9c,0xe5,0x6e,0xef,0x8c,0xe2,0x02,0xb0,0x1b,0xe2, -0x06,0x00,0x00,0x1a,0x8c,0xc0,0x92,0xe5,0x00,0x00,0x5c,0xe3,0x07,0x00,0x00,0x1a, -0x03,0xb0,0xa0,0xe3,0xd3,0xff,0xff,0xea,0x04,0xb0,0xa0,0xe3,0xd1,0xff,0xff,0xea, -0x01,0xb0,0xa0,0xe3,0xcf,0xff,0xff,0xea,0x05,0xb0,0xa0,0xe3,0xcd,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x0a,0x70,0xa0,0xe1,0x01,0x00,0x13,0xe3,0x19,0x00,0x00,0x1a, -0x80,0x30,0x13,0xe2,0x39,0x00,0x00,0x0a,0x0c,0x30,0x91,0xe5,0x68,0x00,0x13,0xe3, -0x13,0x00,0x00,0x1a,0x00,0x30,0x90,0xe5,0x02,0x30,0x13,0xe2,0x10,0x00,0x00,0x1a, -0x00,0x00,0x9e,0xe5,0x02,0x00,0x10,0xe3,0x30,0x00,0x00,0x1a,0x8c,0xb0,0x92,0xe5, -0x00,0x00,0x5b,0xe3,0x0b,0x00,0x00,0x0a,0x9c,0x30,0x92,0xe5,0x0c,0xb0,0x91,0xe5, -0x0c,0x00,0x9d,0xe5,0x2b,0xb8,0x43,0xe0,0x0b,0x00,0x50,0xe1,0x05,0x00,0x00,0x2a, -0x0c,0x00,0x9d,0xe5,0x0b,0x30,0x60,0xe0,0x00,0xb0,0xa0,0xe1,0x0c,0x30,0x87,0xe5, -0x02,0x00,0x00,0xea,0x00,0xb0,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x0c,0x30,0x87,0xe5, -0x00,0x10,0x97,0xe5,0x0b,0x20,0xa0,0xe1,0x28,0x00,0x9d,0xe5,0x0b,0x30,0x81,0xe0, -0x08,0x30,0x87,0xe5,0x01,0x35,0x00,0xeb,0x18,0x10,0x9d,0xe5,0x0c,0x20,0x9d,0xe5, -0x00,0x00,0x51,0xe3,0x00,0x30,0x91,0x15,0x0b,0x30,0x83,0x10,0x00,0x30,0x81,0x15, -0x01,0x00,0x72,0xe3,0x39,0x00,0x00,0x0a,0x04,0xa0,0x97,0xe5,0x0a,0x00,0x5b,0xe1, -0x36,0x00,0x00,0x3a,0x0b,0x20,0x52,0xe0,0x0c,0x20,0x8d,0xe5,0x35,0x00,0x00,0x0a, -0x28,0x30,0x9d,0xe5,0x00,0x80,0x94,0xe5,0x0b,0x30,0x83,0xe0,0x28,0x30,0x8d,0xe5, -0x26,0xff,0xff,0xea,0x34,0x90,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x2c,0x40,0x9d,0xe5, -0xc0,0x00,0x9f,0xe5,0x04,0x30,0x99,0xe7,0x10,0x20,0xc3,0xe5,0xf9,0xfe,0xff,0xea, -0x03,0xb0,0xa0,0xe1,0xdb,0xff,0xff,0xea,0x0c,0x10,0x9d,0xe5,0x04,0x00,0xa0,0xe1, -0x05,0x00,0x51,0xe1,0x01,0x50,0xa0,0x31,0x08,0x10,0x97,0xe5,0x05,0x20,0xa0,0xe1, -0xde,0x34,0x00,0xeb,0x18,0x30,0x9d,0xe5,0x08,0x20,0x97,0xe5,0x00,0x00,0x53,0xe3, -0x0c,0x30,0x97,0xe5,0x18,0x00,0x9d,0x15,0x05,0x20,0x82,0xe0,0x08,0x20,0x87,0xe5, -0x03,0x30,0x65,0xe0,0x0c,0x30,0x87,0xe5,0x00,0x30,0x90,0x15,0x05,0x30,0x83,0x10, -0x00,0x30,0x80,0x15,0x0c,0x30,0x97,0x15,0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x1a, -0x0c,0x10,0x9d,0xe5,0x05,0x40,0x84,0xe0,0x00,0x30,0x97,0xe5,0x28,0x40,0x8d,0xe5, -0x01,0x10,0x65,0xe0,0x0c,0x10,0x8d,0xe5,0x08,0x30,0x87,0xe5,0xe5,0xfe,0xff,0xea, -0x02,0x00,0x00,0x1a,0x10,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe1,0x75,0xff,0xff,0x8a, -0x05,0x00,0xa0,0xe3,0xd3,0xfe,0xff,0xea,0x64,0x00,0x9d,0xe5,0xd1,0xfe,0xff,0xea, -0x00,0x00,0xa0,0xe3,0xcf,0xfe,0xff,0xea,0x0c,0x00,0x9d,0xe5,0xcd,0xfe,0xff,0xea, -0x14,0x31,0x01,0x00,0x48,0x10,0x00,0x00,0x05,0x30,0x04,0x00,0x18,0x10,0x00,0x00, -0xa0,0x86,0x01,0x00,0xf0,0x41,0x2d,0xe9,0x01,0x40,0xa0,0xe1,0xb0,0x51,0x9f,0xe5, -0x00,0x80,0xa0,0xe1,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0xa4,0x31,0x9f,0xe5, -0x05,0x50,0x8f,0xe0,0x03,0x30,0x95,0xe7,0x80,0x60,0x93,0xe5,0x04,0x73,0x86,0xe0, -0x07,0x00,0xa0,0xe1,0xab,0x34,0x00,0xeb,0x00,0x00,0x54,0xe3,0x17,0x00,0x00,0x1a, -0x02,0x39,0xa0,0xe3,0x04,0x33,0x86,0xe7,0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5, -0x04,0x33,0x96,0xe7,0x01,0x35,0x83,0xe3,0x04,0x33,0x86,0xe7,0xa4,0x40,0xb0,0xe1, -0x43,0x00,0x00,0x1a,0x60,0x31,0x9f,0xe5,0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5, -0x1c,0x12,0x92,0xe5,0x0c,0x10,0xc1,0xe3,0x1c,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5, -0x1c,0x12,0x92,0xe5,0x01,0x10,0xc1,0xe3,0x1c,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5, -0x1c,0x22,0x93,0xe5,0x80,0x20,0x82,0xe3,0x1c,0x22,0x83,0xe5,0xf0,0x81,0xbd,0xe8, -0x02,0x30,0x44,0xe2,0x01,0x00,0x53,0xe3,0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5, -0x01,0x35,0xa0,0x83,0x04,0x23,0x96,0xe7,0x19,0x00,0x00,0x9a,0x01,0x00,0x14,0xe3, -0x03,0x30,0x82,0xe1,0x04,0x33,0x86,0xe7,0xe3,0xff,0xff,0x0a,0xa4,0x40,0xb0,0xe1, -0x18,0x00,0x00,0x0a,0xf0,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5, -0x20,0x12,0x92,0xe5,0x03,0x17,0xc1,0xe3,0x02,0x17,0x81,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x01,0x18,0xc1,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x01,0x15,0x81,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x30,0x93,0xe5,0x20,0x22,0x93,0xe5,0x02,0x25,0x82,0xe3,0x20,0x22,0x83,0xe5, -0xf0,0x81,0xbd,0xe8,0x00,0x30,0x98,0xe5,0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03, -0x01,0x35,0xa0,0x13,0xe0,0xff,0xff,0xea,0x8c,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7, -0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5,0x03,0x17,0xc1,0xe3,0x1c,0x12,0x82,0xe5, -0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5,0x01,0x18,0xc1,0xe3,0x1c,0x12,0x82,0xe5, -0x04,0x30,0x93,0xe5,0x1c,0x22,0x93,0xe5,0x02,0x25,0x82,0xe3,0x1c,0x22,0x83,0xe5, -0xf0,0x81,0xbd,0xe8,0x50,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5, -0x20,0x12,0x92,0xe5,0x0c,0x10,0xc1,0xe3,0x08,0x10,0x81,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x01,0x10,0xc1,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x40,0x10,0x81,0xe3,0x20,0x12,0x82,0xe5, -0x04,0x30,0x93,0xe5,0x20,0x22,0x93,0xe5,0x80,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5, -0xf0,0x81,0xbd,0xe8,0x00,0x2c,0x01,0x00,0x64,0x10,0x00,0x00,0x7c,0x10,0x00,0x00, -0xf0,0x4f,0x2d,0xe9,0x34,0xd0,0x4d,0xe2,0x2c,0x00,0x8d,0xe5,0x01,0x00,0x71,0xe3, -0x01,0x50,0xa0,0xe1,0x98,0x46,0x9f,0xe5,0x58,0x00,0xdd,0xe5,0x28,0x20,0x8d,0xe5, -0x1c,0x30,0x8d,0xe5,0x04,0x40,0x8f,0xe0,0x24,0x00,0x8d,0xe5,0xff,0x00,0x00,0x0a, -0xa1,0x10,0xa0,0xe1,0x01,0xb0,0x15,0xe2,0x01,0x60,0xa0,0x03,0x01,0x68,0xa0,0x13, -0x16,0x61,0xa0,0xe1,0x20,0x10,0x8d,0xe5,0x08,0x10,0x8d,0xe5,0x64,0xa6,0x9f,0xe5, -0x04,0x90,0xa0,0xe1,0x60,0x76,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x20,0x93,0xe5, -0x10,0x62,0x82,0xe5,0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x51,0x34,0x00,0xeb,0x06,0x00,0x18,0xe1, -0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0x1c,0x76,0x9f,0xe5,0x0a,0x30,0xb9,0xe7, -0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x42,0x34,0x00,0xeb,0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a, -0x04,0x90,0xa0,0xe1,0xe0,0x75,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5, -0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x33,0x34,0x00,0xeb,0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0xac,0x75,0x9f,0xe5, -0x85,0x32,0xa0,0xe1,0x20,0x20,0xa0,0xe3,0x05,0x63,0xa0,0xe1,0x02,0x90,0x85,0xe0, -0x14,0x30,0x8d,0xe5,0x07,0x00,0x94,0xe7,0x24,0xc0,0x85,0xe2,0x00,0x10,0xa0,0xe3, -0x18,0xc0,0x8d,0xe5,0x0c,0x60,0x8d,0xe5,0x03,0x00,0x80,0xe0,0x10,0x90,0x8d,0xe5, -0xf4,0x33,0x00,0xeb,0x07,0x30,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3, -0x80,0x00,0x93,0xe5,0x06,0x00,0x80,0xe0,0xee,0x33,0x00,0xeb,0x07,0x20,0x94,0xe7, -0x00,0x10,0xa0,0xe3,0x18,0xe0,0x9d,0xe5,0x01,0x00,0x5b,0xe1,0x0a,0x30,0x94,0xe7, -0x09,0xc1,0x82,0xe0,0x0e,0x01,0x82,0xe0,0x04,0x10,0x8c,0xe5,0x04,0x10,0x80,0xe5, -0x04,0x30,0x93,0xe5,0x18,0x02,0x93,0xe5,0x3f,0x00,0x00,0x1a,0x08,0x10,0x9d,0xe5, -0x80,0x80,0x92,0xe5,0x01,0x20,0xa0,0xe3,0x0c,0x90,0x9d,0xe5,0x12,0x01,0x80,0xe1, -0x0b,0x10,0xa0,0xe1,0x09,0x60,0x88,0xe0,0x18,0x02,0x83,0xe5,0x30,0x20,0xa0,0xe3, -0x06,0x00,0xa0,0xe1,0xd7,0x33,0x00,0xeb,0x00,0x00,0x55,0xe3,0x3c,0x00,0x00,0x1a, -0x02,0x29,0xa0,0xe3,0x01,0x35,0xa0,0xe3,0x05,0x23,0x88,0xe7,0x05,0x23,0x98,0xe7, -0x07,0x80,0x94,0xe7,0x03,0x30,0x82,0xe1,0x14,0xe0,0x9d,0xe5,0x00,0x10,0xa0,0xe3, -0x10,0x00,0x9d,0xe5,0x01,0xc0,0xa0,0xe3,0x02,0x32,0x83,0xe3,0x0e,0x90,0x88,0xe0, -0x18,0xe0,0x9d,0xe5,0x00,0x30,0x86,0xe5,0x00,0x21,0x88,0xe0,0x08,0x10,0x86,0xe5, -0x09,0x00,0xa0,0xe1,0x04,0xc0,0x82,0xe5,0x0e,0x31,0x88,0xe0,0x1c,0x20,0x9d,0xe5, -0x04,0x20,0x83,0xe5,0x20,0x20,0xa0,0xe3,0x04,0xc0,0x8d,0xe5,0xbd,0x33,0x00,0xeb, -0x1c,0x30,0x9d,0xe5,0x00,0x00,0x5b,0xe3,0x04,0xc0,0x9d,0xe5,0x01,0x10,0xa0,0x03, -0x24,0x00,0x9d,0xe5,0x01,0x18,0xa0,0x13,0x03,0x28,0xa0,0xe1,0x85,0xc2,0x88,0xe7, -0x0a,0x30,0x94,0xe7,0x00,0x00,0x50,0xe3,0x80,0x20,0x82,0xe3,0x1f,0xc0,0xc9,0xe3, -0x04,0x20,0x89,0xe5,0x28,0x20,0x9d,0xe5,0x08,0x20,0x89,0xe5,0x08,0x00,0x96,0xe5, -0x04,0x20,0x93,0xe5,0x00,0x00,0x8c,0xe1,0x08,0x00,0x86,0xe5,0x08,0x60,0x9d,0xe5, -0x0c,0x02,0x92,0xe5,0x11,0x16,0x80,0xe1,0x24,0x00,0x9d,0x05,0x0c,0x12,0x82,0xe5, -0x16,0x00,0x00,0x1a,0x34,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x08,0xc0,0x9d,0xe5, -0x80,0x60,0x92,0xe5,0x01,0x28,0xa0,0xe3,0x0c,0xe0,0x9d,0xe5,0x12,0x0c,0x80,0xe1, -0x30,0x20,0xa0,0xe3,0x0e,0x60,0x86,0xe0,0x18,0x02,0x83,0xe5,0x06,0x00,0xa0,0xe1, -0x98,0x33,0x00,0xeb,0x02,0x30,0x45,0xe2,0x00,0x20,0x96,0xe5,0x01,0x00,0x53,0xe3, -0x01,0x35,0xa0,0x83,0xc1,0xff,0xff,0x8a,0x2c,0xc0,0x9d,0xe5,0x00,0x30,0x9c,0xe5, -0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03,0x01,0x35,0xa0,0x13,0xbb,0xff,0xff,0xea, -0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3,0x04,0x10,0x93,0x15,0x04,0x10,0x93,0x05, -0x20,0x32,0x91,0x15,0x1c,0x32,0x91,0x05,0x00,0x00,0x5b,0xe3,0x01,0x20,0x03,0x02, -0x23,0x28,0xa0,0x11,0x01,0x20,0x02,0x12,0x00,0x00,0x52,0xe3,0x1a,0x00,0x00,0x1a, -0x00,0x00,0x5b,0xe3,0xa3,0x3b,0xa0,0x11,0xa3,0x33,0xa0,0x01,0x01,0x30,0x03,0x12, -0x01,0x30,0x03,0x02,0x00,0x00,0x53,0xe3,0x13,0x00,0x00,0x0a,0x07,0x20,0x94,0xe7, -0x0c,0xc0,0x9d,0xe5,0x80,0x30,0x92,0xe5,0x0c,0x30,0x83,0xe0,0x0c,0x30,0x93,0xe5, -0x68,0x00,0x13,0xe2,0x0c,0x00,0x00,0x1a,0x0c,0xc2,0x91,0xe5,0x00,0x00,0x5b,0xe3, -0x08,0x60,0x9d,0xe5,0x01,0x30,0xa0,0x03,0x01,0x38,0xa0,0x13,0x13,0xc6,0x1c,0xe0, -0x3c,0x00,0x00,0x1a,0x14,0x02,0x91,0xe5,0x13,0x66,0x10,0xe0,0xce,0x00,0x00,0x1a, -0x10,0x90,0x9d,0xe5,0x09,0x21,0x82,0xe0,0x04,0x30,0x92,0xe5,0x20,0x90,0x9d,0xe5, -0x00,0x00,0x59,0xe3,0x20,0x32,0x91,0x15,0x2e,0x00,0x00,0x0a,0x00,0x00,0x5b,0xe3, -0x23,0x28,0xa0,0x11,0x01,0x20,0x03,0x02,0x01,0x20,0x02,0x12,0x00,0x00,0x52,0xe3, -0x2a,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3,0xa3,0x3b,0xa0,0x11,0xa3,0x33,0xa0,0x01, -0x01,0x30,0x03,0x12,0x01,0x30,0x03,0x02,0x00,0x00,0x53,0xe3,0x23,0x00,0x00,0x0a, -0x07,0x30,0x94,0xe7,0x0c,0xc0,0x9d,0xe5,0x80,0x20,0x93,0xe5,0x0c,0x20,0x82,0xe0, -0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3,0x1c,0x00,0x00,0x1a,0x0c,0x22,0x91,0xe5, -0x00,0x00,0x5b,0xe3,0x08,0x40,0x9d,0xe5,0x01,0x00,0xa0,0x03,0x01,0x08,0xa0,0x13, -0x10,0x44,0x12,0xe0,0x15,0x00,0x00,0x1a,0x14,0x22,0x91,0xe5,0x00,0x00,0x5b,0xe3, -0x08,0x60,0x9d,0xe5,0x01,0xb8,0xa0,0x13,0x01,0xb0,0xa0,0x03,0x1b,0x66,0x12,0xe0, -0x0e,0x00,0x00,0x1a,0x10,0x90,0x9d,0xe5,0x09,0x31,0x83,0xe0,0x04,0x00,0x93,0xe5, -0x00,0x00,0x50,0xe3,0x1a,0x00,0xa0,0x03,0x00,0x00,0xa0,0x13,0x94,0xff,0xff,0xea, -0x02,0x21,0xe0,0xe3,0x01,0x60,0xa0,0xe1,0x08,0x20,0x8d,0xe5,0x01,0xb0,0xa0,0xe3, -0x20,0x20,0x8d,0xe5,0x00,0xff,0xff,0xea,0x1c,0x32,0x91,0xe5,0xce,0xff,0xff,0xea, -0x1a,0x00,0xa0,0xe3,0x8a,0xff,0xff,0xea,0x1c,0x00,0x8d,0xe5,0x0a,0x60,0x84,0xe0, -0x07,0x80,0x84,0xe0,0x01,0x00,0xa0,0xe3,0x59,0x33,0x00,0xeb,0x20,0xc0,0x9d,0xe5, -0x00,0x00,0x5c,0xe3,0x00,0x30,0x96,0x15,0x00,0x30,0x96,0x05,0x04,0x10,0x93,0x15, -0x04,0x10,0x93,0x05,0x20,0x22,0x91,0x15,0x1c,0x22,0x91,0x05,0x00,0x00,0x5b,0xe3, -0x01,0x00,0x02,0x02,0x22,0x08,0xa0,0x11,0x01,0x00,0x00,0x12,0x00,0x00,0x50,0xe3, -0x74,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3,0xa2,0x2b,0xa0,0x11,0xa2,0x23,0xa0,0x01, -0x01,0x20,0x02,0x12,0x01,0x20,0x02,0x02,0x00,0x00,0x52,0xe3,0x6f,0x00,0x00,0x0a, -0x00,0x00,0x98,0xe5,0x0c,0x90,0x9d,0xe5,0x80,0x20,0x90,0xe5,0x09,0x20,0x82,0xe0, -0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3,0x6a,0x00,0x00,0x1a,0x0c,0xc2,0x91,0xe5, -0x00,0x00,0x5b,0xe3,0x08,0x90,0x9d,0xe5,0x01,0x20,0xa0,0x03,0x01,0x28,0xa0,0x13, -0x12,0xc9,0x1c,0xe0,0x65,0x00,0x00,0x1a,0x14,0xc2,0x91,0xe5,0x12,0xc9,0x1c,0xe0, -0x62,0x00,0x00,0x1a,0x10,0x60,0x9d,0xe5,0x06,0x31,0x80,0xe0,0x04,0x30,0x93,0xe5, -0x00,0x00,0x53,0xe3,0x03,0x30,0xa0,0x03,0x00,0x30,0xa0,0x13,0x01,0x00,0x53,0xe3, -0x0a,0x30,0x94,0xe7,0x94,0xff,0xff,0x1a,0x01,0x00,0x75,0xe3,0x04,0x00,0x00,0x0a, -0x08,0xc0,0x9d,0xe5,0x00,0x00,0x5b,0xe3,0x01,0x50,0xa0,0x03,0x01,0x58,0xa0,0x13, -0x15,0x5c,0xa0,0xe1,0x10,0x52,0x81,0xe5,0x0a,0x80,0x84,0xe0,0x04,0x30,0x93,0xe5, -0x64,0x61,0x9f,0xe5,0x10,0x92,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x98,0xe5, -0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5,0x10,0x92,0x93,0xe5,0x21,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x16,0x33,0x00,0xeb,0x05,0x00,0x19,0xe1,0xf6,0xff,0xff,0x1a, -0x04,0x90,0xa0,0xe1,0x30,0x61,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5, -0x14,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x60,0x56,0xe2, -0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x07,0x33,0x00,0xeb,0x05,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1, -0xf4,0x60,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5, -0x0c,0x82,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xf8,0x32,0x00,0xeb, -0x05,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x07,0x00,0x94,0xe7,0x00,0x10,0xa0,0xe3, -0x14,0xe0,0x9d,0xe5,0x20,0x20,0xa0,0xe3,0x0e,0x00,0x80,0xe0,0xc1,0x32,0x00,0xeb, -0x07,0x30,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5, -0x0c,0x30,0x9d,0xe5,0x03,0x00,0x80,0xe0,0xba,0x32,0x00,0xeb,0x07,0x20,0x94,0xe7, -0x00,0x30,0xa0,0xe3,0x0a,0x10,0x94,0xe7,0x03,0x00,0x5b,0xe1,0x10,0x40,0x9d,0xe5, -0x01,0xb8,0xa0,0x13,0x18,0x60,0x9d,0xe5,0x01,0xb0,0xa0,0x03,0x08,0x90,0x9d,0xe5, -0x03,0x00,0xa0,0xe3,0x04,0xc1,0x82,0xe0,0x06,0x21,0x82,0xe0,0x04,0x30,0x8c,0xe5, -0x04,0x30,0x82,0xe5,0x04,0x30,0x91,0xe5,0x18,0x22,0x93,0xe5,0x1b,0xb9,0x82,0xe1, -0x18,0xb2,0x83,0xe5,0x02,0xff,0xff,0xea,0x04,0x30,0xa0,0xe3,0xa6,0xff,0xff,0xea, -0x05,0x30,0xa0,0xe3,0xa4,0xff,0xff,0xea,0x02,0x30,0xa0,0xe3,0xa2,0xff,0xff,0xea, -0x1c,0x00,0x9d,0xe5,0x28,0x20,0x9f,0xe5,0x01,0x00,0x80,0xe2,0x02,0x00,0x50,0xe1, -0x1c,0x00,0x8d,0xe5,0x6e,0xff,0xff,0x1a,0x9e,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe5, -0x69,0xff,0xff,0xea,0x2c,0x2a,0x01,0x00,0x7c,0x10,0x00,0x00,0xa0,0x86,0x01,0x00, -0x64,0x10,0x00,0x00,0x40,0x42,0x0f,0x00,0xf0,0x4f,0x2d,0xe9,0x44,0xd0,0x4d,0xe2, -0x00,0x4f,0x9f,0xe5,0x00,0xb0,0xa0,0xe1,0x00,0x90,0xa0,0xe3,0xf8,0x3e,0x9f,0xe5, -0x04,0x40,0x8f,0xe0,0xf4,0x5e,0x9f,0xe5,0xf4,0x6e,0x9f,0xe5,0x03,0x30,0x84,0xe0, -0xf0,0x1e,0x9f,0xe5,0x0c,0x30,0x8d,0xe5,0xec,0x3e,0x9f,0xe5,0x06,0x60,0x84,0xe0, -0x05,0x00,0x94,0xe7,0x14,0x10,0x8d,0xe5,0x03,0x30,0x84,0xe0,0x10,0x30,0x8d,0xe5, -0x0d,0x00,0x00,0xea,0x04,0x00,0x18,0xe3,0x04,0x30,0x90,0x15,0x05,0x30,0x94,0x07, -0xb4,0x21,0x93,0x15,0x04,0x30,0x93,0x05,0xa2,0x2c,0xa0,0x11,0x03,0x20,0x02,0x12, -0x00,0x20,0x80,0x15,0x08,0x22,0x93,0xe5,0x01,0x00,0x12,0xe3,0xeb,0x00,0x00,0x1a, -0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x0f,0x01,0x00,0x1a,0x04,0x20,0x90,0xe5, -0x34,0x31,0x92,0xe5,0x34,0x31,0x82,0xe5,0x7d,0x24,0xa0,0xe3,0x04,0x24,0x92,0xe5, -0x01,0x27,0x12,0xe2,0xb8,0x01,0x00,0x0a,0x83,0x8b,0xa0,0xe1,0x40,0x00,0x13,0xe3, -0xa8,0x8b,0xa0,0xe1,0xe6,0xff,0xff,0x0a,0x04,0x30,0x90,0xe5,0x00,0x20,0xa0,0xe3, -0x68,0x7e,0x9f,0xe5,0x05,0x90,0x84,0xe0,0x44,0x21,0x83,0xe5,0x04,0x30,0x90,0xe5, -0x08,0x22,0x93,0xe5,0x08,0x22,0x83,0xe5,0x04,0x30,0x90,0xe5,0x18,0x22,0x93,0xe5, -0x18,0x22,0x83,0xe5,0x00,0x20,0xe0,0xe3,0x04,0x30,0x90,0xe5,0x10,0x22,0x83,0xe5, -0x04,0x30,0x90,0xe5,0x10,0xa2,0x93,0xe5,0x05,0x00,0x00,0xea,0x00,0x30,0x99,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x10,0x93,0xe5,0x21,0x2e,0x81,0xe2,0x10,0xa2,0x91,0xe5, -0x12,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x7d,0x32,0x00,0xeb,0x00,0x00,0x5a,0xe3, -0xf5,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0x90,0x84,0xe0,0xfc,0x7d,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x20,0x93,0xe5,0x14,0xa2,0x92,0xe5,0x00,0x02,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x6e,0x32,0x00,0xeb,0x00,0x00,0x5a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0xc0,0x7d,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0x0c,0x92,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x20,0x93,0xe5,0x0c,0x92,0x92,0xe5,0xf1,0x01,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x5f,0x32,0x00,0xeb,0x00,0x00,0x59,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x04,0x20,0x93,0xe5,0x21,0x2e,0x82,0xe2,0x02,0x10,0xa0,0xe3,0x7c,0x7d,0x9f,0xe5, -0x00,0x10,0x82,0xe5,0x05,0x20,0x84,0xe0,0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5, -0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x10,0xa2,0x93,0xe5,0x27,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x48,0x32,0x00,0xeb, -0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x2c,0x7d,0x9f,0xe5, -0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5,0x15,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x36,0x32,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0xe4,0x7c,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0, -0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x0c,0xa2,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x24,0x32,0x00,0xeb, -0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x06,0x50,0xa0,0xe1, -0x08,0x60,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x05,0xa0,0x84,0xe0, -0x88,0x7c,0x9f,0xe5,0x00,0x00,0x96,0xe5,0x40,0x00,0x80,0xe2,0xe9,0x31,0x00,0xeb, -0x00,0x30,0x96,0xe5,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5, -0x80,0x00,0x80,0xe2,0xe3,0x31,0x00,0xeb,0x05,0x30,0x94,0xe7,0x00,0x00,0xa0,0xe3, -0x00,0x10,0x96,0xe5,0x04,0x20,0x93,0xe5,0x8c,0x00,0x81,0xe5,0x9c,0x00,0x81,0xe5, -0x18,0x12,0x92,0xe5,0x02,0x10,0x81,0xe3,0x18,0x12,0x82,0xe5,0x02,0x18,0xa0,0xe3, -0x04,0x20,0x93,0xe5,0x10,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x10,0x32,0x93,0xe5, -0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1,0x04,0x50,0xa0,0xe1,0x0a,0x40,0xa0,0xe1, -0x03,0xa0,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5,0x27,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xf7,0x31,0x00,0xeb,0x02,0x08,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1, -0xe8,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1, -0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5, -0x15,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xe5,0x31,0x00,0xeb,0x02,0x08,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0xa0,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7, -0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5, -0x0c,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xd3,0x31,0x00,0xeb,0x02,0x08,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1, -0x06,0x50,0xa0,0xe1,0x08,0x60,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3, -0x00,0x00,0x96,0xe5,0x60,0x00,0x80,0xe2,0x9a,0x31,0x00,0xeb,0x00,0x30,0x96,0xe5, -0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0xc0,0x00,0x80,0xe2, -0x94,0x31,0x00,0xeb,0x05,0x00,0x94,0xe7,0x00,0x30,0xa0,0xe3,0x00,0x10,0x96,0xe5, -0x04,0x20,0x90,0xe5,0x90,0x30,0x81,0xe5,0xa0,0x30,0x81,0xe5,0x18,0x12,0x92,0xe5, -0x02,0x18,0x81,0xe3,0x18,0x12,0x82,0xe5,0x10,0x30,0xc0,0xe5,0x08,0xff,0xff,0xea, -0x00,0x10,0x96,0xe5,0x08,0x00,0x80,0xe2,0x08,0x22,0x83,0xe5,0x08,0x20,0xa0,0xe3, -0x00,0x90,0xa0,0xe3,0x05,0x70,0x84,0xe0,0x80,0x10,0x91,0xe5,0x28,0x10,0x81,0xe2, -0x7e,0x31,0x00,0xeb,0x05,0x00,0x94,0xe7,0x3c,0x90,0xcd,0xe5,0x3d,0x90,0xcd,0xe5, -0x38,0x90,0xcd,0xe5,0x39,0x90,0xcd,0xe5,0x08,0x20,0xd0,0xe5,0x0f,0x80,0xd0,0xe5, -0x0e,0x30,0xd0,0xe5,0x02,0x00,0x52,0xe3,0x08,0x84,0x83,0xe1,0xe0,0x00,0x00,0x0a, -0x14,0x00,0x00,0x8a,0x09,0x00,0x52,0xe1,0x1e,0x00,0x00,0x1a,0x09,0x30,0xd0,0xe5, -0x05,0x00,0x53,0xe3,0x43,0x01,0x00,0x0a,0x09,0x00,0x53,0xe3,0x1e,0x02,0x00,0x0a, -0x03,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11,0x11,0x00,0x00,0x1a,0x0a,0x30,0xd0,0xe5, -0x02,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11,0x04,0x02,0x00,0x0a,0x05,0x00,0x94,0xe7, -0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0xef,0xfe,0xff,0x0a,0x09,0x00,0xa0,0xe1, -0x44,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x81,0x00,0x52,0xe3,0x83,0x00,0x00,0x0a, -0x82,0x00,0x52,0xe3,0xab,0x00,0x00,0x0a,0x80,0x00,0x52,0xe3,0x9b,0x00,0x00,0x0a, -0x00,0x90,0xa0,0xe3,0x04,0x30,0x90,0xe5,0x34,0x2a,0x9f,0xe5,0x05,0x00,0x94,0xe7, -0x1c,0x22,0x83,0xe5,0xed,0xff,0xff,0xea,0x01,0x00,0x52,0xe3,0xf7,0xff,0xff,0x1a, -0x00,0x30,0x96,0xe5,0x04,0x20,0x90,0xe5,0x10,0x8a,0x9f,0xe5,0x8c,0x90,0x83,0xe5, -0x90,0x90,0x83,0xe5,0x02,0x30,0xa0,0xe3,0x10,0x32,0x82,0xe5,0x04,0x30,0x90,0xe5, -0x10,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x97,0xe5,0x01,0x80,0x58,0xe2, -0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x6f,0x31,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x05,0xa0,0x84,0xe0,0xc4,0x79,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x60,0x31,0x00,0xeb, -0x02,0x00,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0, -0x88,0x79,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x51,0x31,0x00,0xeb,0x02,0x00,0x18,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x02,0x18,0xa0,0xe3,0x4c,0x79,0x9f,0xe5, -0x05,0xa0,0x84,0xe0,0x04,0x20,0x93,0xe5,0x10,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5, -0x10,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x3f,0x31,0x00,0xeb,0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x05,0xa0,0x84,0xe0,0x04,0x79,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x30,0x31,0x00,0xeb, -0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0, -0xc8,0x78,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x21,0x31,0x00,0xeb,0x02,0x08,0x18,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0xc0,0x94,0xe7,0x01,0x70,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x07,0x10,0xa0,0xe1,0x02,0x30,0xa0,0xe1,0x04,0x80,0x9c,0xe5,0x0c,0x00,0xa0,0xe1, -0x20,0xe2,0x98,0xe5,0x40,0xe0,0x8e,0xe3,0x20,0xe2,0x88,0xe5,0x04,0xc0,0x9c,0xe5, -0x20,0xe2,0x9c,0xe5,0x01,0xe5,0x8e,0xe3,0x20,0xe2,0x8c,0xe5,0x00,0x70,0x8d,0xe5, -0x9a,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2,0x77,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7, -0x0a,0x30,0xd0,0xe5,0x13,0x30,0xc0,0xe5,0x05,0x00,0x94,0xe7,0x73,0xff,0xff,0xea, -0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x08,0x70,0xa0,0x01,0x3c,0x10,0x8d,0x02, -0x5e,0x00,0x00,0x1a,0x0b,0x00,0xa0,0xe1,0x07,0x20,0xa0,0xe1,0x01,0xa0,0xa0,0xe3, -0xce,0x30,0x00,0xeb,0x05,0x00,0x94,0xe7,0x08,0x00,0x57,0xe1,0x07,0x30,0xa0,0x31, -0x08,0x30,0xa0,0x21,0x0a,0x10,0xa0,0xe1,0x0b,0x20,0xa0,0xe1,0x00,0xa0,0x8d,0xe5, -0x82,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2,0x5f,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7, -0x09,0x10,0xa0,0xe1,0x09,0x20,0xa0,0xe1,0x09,0x30,0xa0,0xe1,0x00,0xa0,0x8d,0xe5, -0x7a,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1,0x05,0x00,0x94,0xe7,0x57,0xff,0xff,0xea, -0x09,0x30,0xd0,0xe5,0x06,0x00,0x53,0xe3,0x52,0x00,0x00,0x0a,0x08,0x00,0x53,0xe3, -0x89,0x00,0x00,0x0a,0x00,0x00,0x53,0xe3,0x5d,0xff,0xff,0x1a,0x14,0x30,0x9d,0xe5, -0x02,0x70,0xa0,0xe3,0x03,0x10,0x84,0xe0,0xdd,0xff,0xff,0xea,0x10,0x20,0xc0,0xe5, -0x23,0x90,0xa0,0xe3,0x4c,0xff,0xff,0xea,0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x3e,0x00,0x00,0x1a,0x0d,0x20,0xd0,0xe5,0x0c,0x30,0xd0,0xe5,0x02,0x34,0x83,0xe1, -0x01,0x00,0x53,0xe3,0x6c,0x01,0x00,0x0a,0x6a,0x00,0x00,0x2a,0x04,0x30,0x90,0xe5, -0x1c,0x22,0x93,0xe5,0x01,0x00,0x12,0xe3,0x3b,0x01,0x00,0x1a,0x80,0x00,0x12,0xe3, -0xa4,0x00,0x00,0x0a,0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5,0x0c,0x10,0x91,0xe5, -0x68,0x00,0x11,0xe3,0x9f,0x00,0x00,0x1a,0x0c,0x12,0x93,0xe5,0x01,0x00,0x11,0xe3, -0x9c,0x00,0x00,0x1a,0x14,0x32,0x93,0xe5,0x01,0x00,0x13,0xe3,0x84,0x30,0x92,0x05, -0x98,0x00,0x00,0xea,0x09,0x30,0xd0,0xe5,0x01,0x00,0x53,0xe3,0x20,0x00,0x00,0x0a, -0x03,0x00,0x53,0xe3,0x36,0xff,0xff,0x1a,0x0a,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x1e,0x00,0x00,0x1a,0x0d,0x10,0xd0,0xe5,0x0c,0x20,0xd0,0xe5,0x01,0x24,0x82,0xe1, -0x01,0x00,0x52,0xe3,0x74,0x00,0x00,0x0a,0x73,0x00,0x00,0x3a,0x80,0x00,0x52,0xe3, -0x71,0x00,0x00,0x0a,0x81,0x00,0x52,0xe3,0x3a,0x00,0x00,0x1a,0x04,0x30,0x90,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x28,0x82,0xe3,0x20,0x22,0x83,0xe5,0x01,0xc0,0xa0,0xe3, -0x00,0x20,0xa0,0xe3,0x0c,0x10,0xa0,0xe1,0x02,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x32,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1,0x05,0x00,0x94,0xe7,0x0f,0xff,0xff,0xea, -0x0a,0x00,0x53,0xe3,0x13,0x10,0x80,0x02,0x08,0x70,0xa0,0x01,0x18,0xff,0xff,0x1a, -0x9b,0xff,0xff,0xea,0x0a,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x1b,0x00,0x00,0x0a, -0x04,0x30,0x90,0xe5,0x05,0x00,0x94,0xe7,0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3, -0x20,0x22,0x83,0xe5,0x01,0xff,0xff,0xea,0x34,0x90,0x8d,0xe5,0x30,0x90,0x8d,0xe5, -0x2c,0x90,0x8d,0xe5,0x56,0x3a,0x00,0xeb,0x00,0xa0,0xa0,0xe1,0x5b,0x3a,0x00,0xeb, -0x00,0x90,0xa0,0xe1,0x60,0x3a,0x00,0xeb,0x00,0x30,0xa0,0xe1,0x00,0x00,0x97,0xe5, -0x0b,0x20,0xd0,0xe5,0x01,0x20,0x42,0xe2,0x06,0x00,0x52,0xe3,0x02,0xf1,0x8f,0x90, -0xfe,0xfe,0xff,0xea,0xc2,0x00,0x00,0xea,0x9f,0x00,0x00,0xea,0x93,0x00,0x00,0xea, -0xfa,0xfe,0xff,0xea,0xf9,0xfe,0xff,0xea,0x7a,0x00,0x00,0xea,0x58,0x00,0x00,0xea, -0x0d,0x10,0xd0,0xe5,0x0c,0x20,0xd0,0xe5,0x01,0x24,0x82,0xe1,0x01,0x00,0x52,0xe3, -0x30,0x00,0x00,0x0a,0x2f,0x00,0x00,0x3a,0x80,0x00,0x52,0xe3,0x2d,0x00,0x00,0x0a, -0x81,0x00,0x52,0xe3,0x32,0x01,0x00,0x0a,0x04,0x20,0x90,0xe5,0x03,0x90,0xa0,0xe1, -0x05,0x00,0x94,0xe7,0x20,0x32,0x92,0xe5,0x01,0x30,0x83,0xe3,0x20,0x32,0x82,0xe5, -0xda,0xfe,0xff,0xea,0x21,0x2e,0x82,0xe2,0x03,0x90,0xa0,0xe3,0x11,0xfe,0xff,0xea, -0x03,0x90,0xa0,0xe3,0x0f,0xfe,0xff,0xea,0x80,0x00,0x53,0xe3,0x2b,0x00,0x00,0x0a, -0x81,0x00,0x53,0xe3,0x0f,0x01,0x00,0x0a,0x04,0x30,0x90,0xe5,0x00,0x90,0xa0,0xe3, -0x05,0x00,0x94,0xe7,0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5, -0x01,0x30,0xa0,0xe3,0x38,0x30,0xcd,0xe5,0xc8,0xfe,0xff,0xea,0x12,0x10,0x80,0xe2, -0x08,0x70,0xa0,0xe1,0x56,0xff,0xff,0xea,0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0xe0,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2, -0xbd,0xfe,0xff,0x1a,0x00,0x00,0x97,0xe5,0x04,0x30,0x90,0xe5,0x0a,0x10,0xd0,0xe5, -0x05,0x00,0x94,0xe7,0x44,0x21,0x93,0xe5,0xfe,0x24,0xc2,0xe3,0x81,0x2c,0x82,0xe1, -0x44,0x21,0x83,0xe5,0xb5,0xfe,0xff,0xea,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5, -0x01,0x20,0xc2,0xe3,0x20,0x22,0x83,0xe5,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5, -0x40,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0x93,0xff,0xff,0xea,0x04,0x30,0x90,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0x8e,0xff,0xff,0xea, -0x04,0x30,0x90,0xe5,0x1c,0x22,0x93,0xe5,0x01,0x08,0x12,0xe3,0xa2,0x00,0x00,0x1a, -0x02,0x05,0x12,0xe3,0x0b,0x00,0x00,0x0a,0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5, -0x40,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x05,0x00,0x00,0x1a, -0x0c,0x12,0x93,0xe5,0x01,0x08,0x11,0xe3,0x02,0x00,0x00,0x1a,0x14,0x32,0x93,0xe5, -0x01,0x08,0x13,0xe3,0x88,0x30,0x92,0x05,0x08,0x70,0xa0,0xe1,0x38,0x10,0x8d,0xe2, -0x23,0xff,0xff,0xea,0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2, -0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1, -0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5, -0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5,0x0c,0x00,0x9d,0xe5,0x34,0x20,0x9d,0xe5, -0x05,0x30,0x94,0xe7,0x0e,0x20,0xc0,0xe5,0x30,0x20,0x9d,0xe5,0x0f,0x20,0xc0,0xe5, -0x2c,0x20,0x9d,0xe5,0x10,0x20,0xc0,0xe5,0x00,0x30,0x93,0xe5,0x02,0x00,0x53,0xe3, -0xdc,0x00,0x00,0x0a,0x0c,0x10,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe3, -0x20,0x70,0xa0,0xe3,0x16,0x20,0xc1,0xe5,0x17,0x30,0xc1,0xe5,0x1d,0x20,0xc1,0xe5, -0x1e,0x30,0xc1,0xe5,0x02,0xff,0xff,0xea,0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a, -0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1, -0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3, -0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5,0x10,0x10,0x9d,0xe5, -0x0a,0x70,0xa0,0xe3,0x34,0x30,0x9d,0xe5,0x04,0x30,0xc1,0xe5,0x30,0x30,0x9d,0xe5, -0x05,0x30,0xc1,0xe5,0x2c,0x30,0x9d,0xe5,0x06,0x30,0xc1,0xe5,0xec,0xfe,0xff,0xea, -0x0a,0x20,0xd0,0xe5,0x02,0x00,0x52,0xe3,0xd1,0x00,0x00,0x0a,0x03,0x00,0x52,0xe3, -0xc7,0x00,0x00,0x0a,0x01,0x00,0x52,0xe3,0xbf,0x00,0x00,0x0a,0xc4,0x13,0x9f,0xe5, -0x04,0x70,0xa0,0xe3,0x01,0x10,0x84,0xe0,0xe1,0xfe,0xff,0xea,0x00,0x00,0x5a,0xe3, -0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2, -0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a, -0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5, -0x84,0x33,0x9f,0xe5,0x34,0x10,0x9d,0xe5,0x05,0x20,0x94,0xe7,0x03,0x30,0x84,0xe0, -0x0e,0x10,0xc3,0xe5,0x30,0x10,0x9d,0xe5,0x0f,0x10,0xc3,0xe5,0x2c,0x10,0x9d,0xe5, -0x10,0x10,0xc3,0xe5,0x00,0x20,0x92,0xe5,0x02,0x00,0x52,0xe3,0x91,0x00,0x00,0x0a, -0x40,0x00,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x16,0x00,0xc3,0xe5,0x20,0x70,0xa0,0xe3, -0x17,0x20,0xc3,0xe5,0x03,0x10,0xa0,0xe1,0x1d,0x00,0xc3,0xe5,0x1e,0x20,0xc3,0xe5, -0xbf,0xfe,0xff,0xea,0x7f,0x39,0x00,0xeb,0x00,0x30,0x50,0xe2,0x06,0x00,0x00,0x0a, -0x24,0x00,0x8d,0xe2,0x28,0x10,0x8d,0xe2,0x20,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1, -0x13,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3,0x12,0x00,0x00,0x1a,0x07,0x32,0xa0,0xe3, -0x1c,0x00,0x8d,0xe2,0x04,0x78,0x93,0xe5,0x93,0x39,0x00,0xeb,0xfc,0x12,0x9f,0xe5, -0x27,0x34,0xa0,0xe1,0x07,0x0e,0xa0,0xe1,0x24,0x10,0x8d,0xe5,0x07,0x22,0xa0,0xe1, -0x1c,0x10,0x9d,0xe5,0xff,0x30,0x03,0xe2,0x07,0x76,0xa0,0xe1,0x20,0x38,0x83,0xe1, -0x0f,0x10,0x01,0xe2,0x0f,0x2c,0x02,0xe2,0x27,0x2e,0x82,0xe1,0x01,0x34,0x83,0xe1, -0x20,0x20,0x8d,0xe5,0x28,0x30,0x8d,0xe5,0x24,0x10,0x9d,0xe5,0x12,0x70,0xa0,0xe3, -0x28,0x00,0x9d,0xe5,0x20,0x20,0x9d,0xe5,0xb4,0x32,0x9f,0xe5,0x21,0xa4,0xa0,0xe1, -0x20,0xe4,0xa0,0xe1,0x22,0xc4,0xa0,0xe1,0x03,0x30,0x84,0xe0,0x08,0x10,0xc3,0xe5, -0x03,0x10,0xa0,0xe1,0x09,0xa0,0xc3,0xe5,0x0a,0x00,0xc3,0xe5,0x0b,0xe0,0xc3,0xe5, -0x0c,0x20,0xc3,0xe5,0x0d,0xc0,0xc3,0xe5,0x91,0xfe,0xff,0xea,0x40,0x10,0x8d,0xe2, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x61,0xe5,0x08,0x70,0xa0,0xe1,0x8c,0xfe,0xff,0xea, -0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0x16,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2,0xf3,0xfd,0xff,0x1a,0x00,0x30,0x97,0xe5, -0x0d,0x60,0xd3,0xe5,0x0f,0x60,0x06,0xe2,0x04,0x00,0x56,0xe3,0x76,0x00,0x00,0x0a, -0x05,0x30,0x94,0xe7,0x04,0x30,0x93,0xe5,0x74,0x21,0x93,0xe5,0x0f,0x28,0xc2,0xe3, -0x06,0x68,0x82,0xe1,0x74,0x61,0x83,0xe5,0xfe,0xff,0xff,0xea,0x01,0x80,0xa0,0xe3, -0x02,0x30,0xa0,0xe1,0x08,0x10,0xa0,0xe1,0x00,0x80,0x8d,0xe5,0x03,0xfb,0xff,0xeb, -0x00,0x90,0x50,0xe2,0xe0,0xfd,0xff,0x1a,0x00,0x30,0x97,0xe5,0x02,0x10,0xa0,0xe3, -0x0a,0x20,0xd3,0xe5,0x03,0x00,0xa0,0xe1,0x12,0x20,0xc3,0xe5,0x88,0xfa,0xff,0xeb, -0x00,0x00,0x97,0xe5,0x03,0x10,0xa0,0xe3,0x85,0xfa,0xff,0xeb,0x00,0x00,0x97,0xe5, -0x10,0x80,0xc0,0xe5,0x05,0x00,0x94,0xe7,0xd4,0xfd,0xff,0xea,0x04,0x30,0x90,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x00,0x12,0xe3,0xcf,0xff,0xff,0x1a,0x80,0x00,0x12,0xe3, -0x38,0xff,0xff,0x0a,0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2, -0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x32,0xff,0xff,0x1a,0x0c,0x12,0x93,0xe5, -0x02,0x00,0x11,0xe3,0x2f,0xff,0xff,0x1a,0x14,0x32,0x93,0xe5,0x02,0x00,0x13,0xe3, -0x8c,0x30,0x92,0x05,0x2b,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5, -0x01,0x08,0x12,0xe3,0xbc,0xff,0xff,0x1a,0x02,0x05,0x12,0xe3,0x25,0xff,0xff,0x0a, -0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5,0xc0,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5, -0x68,0x00,0x11,0xe3,0x1f,0xff,0xff,0x1a,0x0c,0x12,0x93,0xe5,0x02,0x08,0x11,0xe3, -0x1c,0xff,0xff,0x1a,0x14,0x32,0x93,0xe5,0x02,0x08,0x13,0xe3,0x90,0x30,0x92,0x05, -0x18,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x28,0xc2,0xe3, -0x20,0x22,0x83,0xe5,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x25,0x82,0xe3, -0x20,0x22,0x83,0xe5,0x8c,0xfe,0xff,0xea,0x00,0x10,0xa0,0xe3,0x17,0x20,0xc3,0xe5, -0x16,0x10,0xc3,0xe5,0x20,0x70,0xa0,0xe3,0x1d,0x10,0xc3,0xe5,0x03,0x10,0xa0,0xe1, -0x1e,0x20,0xc3,0xe5,0x2e,0xfe,0xff,0xea,0x40,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3, -0x16,0x20,0xc0,0xe5,0x20,0x70,0xa0,0xe3,0x17,0x30,0xc0,0xe5,0x00,0x10,0xa0,0xe1, -0x1d,0x20,0xc0,0xe5,0x1e,0x30,0xc0,0xe5,0x25,0xfe,0xff,0xea,0xd4,0x10,0x9f,0xe5, -0x01,0x70,0xd4,0xe7,0x01,0x10,0x84,0xe0,0x1a,0x00,0x57,0xe3,0x1a,0x70,0xa0,0x23, -0x1f,0xfe,0xff,0xea,0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1, -0x13,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2,0x0b,0x00,0x00,0x0a,0x00,0x70,0xd1,0xe5, -0x17,0xfe,0xff,0xea,0x00,0x00,0x59,0xe3,0x03,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1, -0x19,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2,0xf7,0xff,0xff,0x1a,0x88,0x10,0x9f,0xe5, -0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5,0x0d,0xfe,0xff,0xea,0x7c,0x10,0x9f,0xe5, -0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5,0x09,0xfe,0xff,0xea,0x70,0x70,0x9f,0xe5, -0x35,0x20,0xa0,0xe3,0x6c,0x10,0x9f,0xe5,0x07,0x70,0x84,0xe0,0x10,0x00,0x97,0xe5, -0x01,0x10,0x84,0xe0,0xd5,0x2e,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x35,0x30,0x83,0xe2,0x05,0x00,0x94,0xe7,0x10,0x20,0x97,0xe5, -0x8a,0xfa,0xff,0xeb,0x79,0xff,0xff,0xea,0x70,0x23,0x01,0x00,0xb0,0x02,0x00,0x00, -0x7c,0x10,0x00,0x00,0x64,0x10,0x00,0x00,0x84,0x02,0x00,0x00,0xa4,0x02,0x00,0x00, -0xa0,0x86,0x01,0x00,0x81,0x00,0x81,0x00,0x04,0x03,0x00,0x00,0xe4,0x02,0x00,0x00, -0x55,0x09,0x00,0x00,0xd0,0x02,0x00,0x00,0x88,0x02,0x00,0x00,0x08,0x03,0x00,0x00, -0x78,0x02,0x00,0x00,0x68,0x10,0x00,0x00,0x5c,0xee,0xff,0xff,0x8c,0x30,0x9f,0xe5, -0x01,0xc0,0xa0,0xe3,0xf0,0x07,0x2d,0xe9,0x7d,0x64,0xa0,0xe3,0x80,0xa0,0x9f,0xe5, -0x00,0x40,0xa0,0xe3,0x03,0x30,0x8f,0xe0,0x78,0x70,0x9f,0xe5,0xb4,0x91,0x96,0xe5, -0x0a,0x20,0x83,0xe0,0x70,0x80,0x9f,0xe5,0x0a,0x70,0x83,0xe7,0x6c,0xa0,0x9f,0xe5, -0x6c,0x50,0x9f,0xe5,0xa9,0x9c,0xa0,0xe1,0x0a,0x80,0x83,0xe7,0x03,0x90,0x09,0xe2, -0x60,0xa0,0x9f,0xe5,0x05,0x10,0x83,0xe0,0x0a,0x10,0x83,0xe7,0x58,0xa0,0x9f,0xe5, -0x10,0xa0,0x82,0xe5,0x54,0xa0,0x9f,0xe5,0x80,0xa0,0x88,0xe5,0x01,0x8a,0xa0,0xe3, -0x04,0x80,0x82,0xe5,0x08,0x70,0x82,0xe5,0x0c,0x40,0x82,0xe5,0x10,0xc0,0xc1,0xe5, -0x11,0xc0,0xc1,0xe5,0x04,0x60,0x81,0xe5,0x05,0x90,0x83,0xe7,0x14,0xc0,0xc1,0xe5, -0x00,0x20,0x80,0xe5,0x04,0x00,0xa0,0xe1,0xf0,0x07,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x1c,0x14,0x01,0x00,0x68,0x10,0x00,0x00,0x00,0x60,0x00,0x40,0x00,0x70,0x00,0x40, -0x64,0x10,0x00,0x00,0x4c,0x10,0x00,0x00,0x7c,0x10,0x00,0x00,0x00,0x40,0x00,0x40, -0x00,0x10,0x00,0x7d,0x70,0x40,0x2d,0xe9,0x00,0xc0,0xa0,0xe3,0x7c,0xe0,0x9f,0xe5, -0x0c,0x10,0xa0,0xe1,0x14,0x20,0xa0,0xe3,0x74,0x30,0x9f,0xe5,0x0e,0xe0,0x8f,0xe0, -0x03,0x30,0x9e,0xe7,0x04,0x40,0x93,0xe5,0x44,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5, -0x08,0x52,0x94,0xe5,0x08,0x52,0x84,0xe5,0x04,0x40,0x93,0xe5,0x18,0x52,0x94,0xe5, -0x18,0x52,0x84,0xe5,0x04,0x40,0x93,0xe5,0x30,0x51,0x94,0xe5,0x01,0x50,0xc5,0xe3, -0x30,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5,0xf8,0x51,0x94,0xe5,0x03,0x50,0xc5,0xe3, -0xf8,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5,0x38,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5, -0xf4,0xc1,0x84,0xe5,0x1c,0x40,0x9f,0xe5,0x14,0xc0,0xc3,0xe5,0x04,0xc0,0x8e,0xe7, -0x70,0x2e,0x00,0xeb,0xc8,0x00,0xa0,0xe3,0x70,0x40,0xbd,0xe8,0xda,0x35,0x00,0xea, -0x64,0x13,0x01,0x00,0x7c,0x10,0x00,0x00,0x64,0x10,0x00,0x00,0x7d,0x34,0xa0,0xe3, -0xf0,0x4f,0x2d,0xe9,0x04,0x34,0x93,0xe5,0x34,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1, -0xcc,0x93,0x9f,0xe5,0x10,0x20,0x8d,0xe5,0x23,0x39,0xa0,0xe1,0x58,0x80,0x9d,0xe5, -0x09,0x90,0x8f,0xe0,0x01,0x30,0x13,0xe2,0x05,0x00,0x00,0x1a,0xb4,0x23,0x9f,0xe5, -0xb4,0x03,0x9f,0xe5,0x02,0x20,0x99,0xe7,0x10,0x30,0xc2,0xe5,0x34,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x10,0x00,0x90,0xe5,0x08,0x10,0x8d,0xe5,0xc1,0xfb,0xff,0xeb, -0x10,0x20,0x9d,0xe5,0x08,0x10,0x9d,0xe5,0x00,0x00,0x52,0xe3,0x10,0x00,0x9d,0x05, -0xf5,0xff,0xff,0x0a,0x7c,0x33,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0x14,0x10,0x8d,0xe5, -0x00,0x10,0xa0,0xe3,0x74,0x53,0x9f,0xe5,0x00,0x60,0xa0,0xe3,0x03,0x40,0x89,0xe0, -0x20,0x30,0x8d,0xe5,0x18,0x10,0x8d,0xe5,0x1c,0x20,0x8d,0xe5,0xfa,0x3f,0xa0,0xe3, -0x98,0x13,0x82,0xe0,0x28,0x10,0x8d,0xe5,0x2c,0x20,0x8d,0xe5,0x14,0x10,0x9d,0xe5, -0x05,0x50,0x89,0xe0,0x24,0x90,0x8d,0xe5,0x08,0x90,0xa0,0xe1,0x10,0x20,0x9d,0xe5, -0x01,0x01,0x97,0xe8,0x08,0x00,0x52,0xe1,0x02,0x80,0xa0,0x31,0x08,0x20,0xa0,0xe1, -0x36,0x2e,0x00,0xeb,0x00,0x00,0x94,0xe5,0x01,0x0a,0x58,0xe3,0x08,0x30,0xa0,0x31, -0x01,0x3a,0xa0,0x23,0x00,0x20,0x97,0xe5,0x03,0x10,0xa0,0xe3,0x00,0x60,0x8d,0xe5, -0xea,0xf9,0xff,0xeb,0x01,0x00,0x79,0xe3,0x06,0x00,0x00,0x0a,0x4b,0x2e,0x00,0xeb, -0x28,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8,0x00,0x20,0x92,0xe0,0x01,0x30,0xa3,0xe0, -0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x7d,0x84,0xa0,0xe3,0x02,0xa8,0xa0,0xe3, -0x04,0x34,0x98,0xe5,0x01,0x07,0x13,0xe3,0x66,0x00,0x00,0x1a,0x00,0x30,0x94,0xe5, -0x11,0x20,0xd3,0xe5,0x00,0x00,0x52,0xe3,0x44,0x00,0x00,0x0a,0x04,0x20,0x93,0xe5, -0xbc,0xb2,0x9f,0xe5,0x10,0xa2,0x82,0xe5,0x04,0x30,0x93,0xe5,0x10,0x32,0x93,0xe5, -0x0c,0x50,0x8d,0xe5,0x04,0x50,0xa0,0xe1,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x10,0x42,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x3d,0x2e,0x00,0xeb,0x02,0x08,0x14,0xe3, -0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x74,0xb2,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0x14,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5, -0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x14,0x42,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x2e,0x2e,0x00,0xeb,0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a, -0x00,0x30,0x95,0xe5,0x38,0xb2,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x0c,0x32,0x93,0xe5, -0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2, -0x04,0x30,0x93,0xe5,0x0c,0x42,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x1f,0x2e,0x00,0xeb,0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1, -0x0c,0x50,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x00,0x00,0x95,0xe5, -0x60,0x00,0x80,0xe2,0xe7,0x2d,0x00,0xeb,0x00,0x30,0x95,0xe5,0x30,0x20,0xa0,0xe3, -0x00,0x10,0xa0,0xe3,0x80,0x00,0x93,0xe5,0xc0,0x00,0x80,0xe2,0xe1,0x2d,0x00,0xeb, -0x00,0x30,0x94,0xe5,0x00,0x20,0x95,0xe5,0x04,0x30,0x93,0xe5,0x90,0x60,0x82,0xe5, -0xa0,0x60,0x82,0xe5,0x18,0x22,0x93,0xe5,0x02,0x28,0x82,0xe3,0x18,0x22,0x83,0xe5, -0x02,0xb0,0xa0,0xe3,0x10,0x00,0x97,0xe5,0x42,0xfb,0xff,0xeb,0x01,0x00,0x79,0xe3, -0x05,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x01,0x2e,0x00,0xeb,0xef,0x2d,0x00,0xeb, -0x1c,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe1,0x53,0x00,0x00,0x9a,0x01,0x00,0x5b,0xe3, -0x04,0x00,0x5b,0x13,0xa5,0xff,0xff,0x0a,0x7d,0x34,0xa0,0xe3,0x24,0x90,0x9d,0xe5, -0x04,0x34,0x93,0xe5,0x20,0x10,0x9d,0xe5,0x23,0x39,0xa0,0xe1,0x01,0x20,0x99,0xe7, -0x01,0x30,0x13,0xe2,0x10,0x30,0xc2,0x05,0x4c,0x01,0x9f,0x05,0x66,0xff,0xff,0x0a, -0x04,0x30,0x92,0xe5,0x4c,0x01,0x9f,0xe5,0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3, -0x20,0x22,0x83,0xe5,0x60,0xff,0xff,0xea,0x00,0x30,0x94,0xe5,0x04,0x30,0x93,0xe5, -0x20,0x22,0x93,0xe5,0x22,0x0e,0x83,0xe2,0x01,0x08,0x12,0xe3,0x15,0x00,0x00,0x1a, -0x02,0x05,0x12,0xe3,0x17,0x00,0x00,0x0a,0x00,0x10,0x95,0xe5,0x80,0x20,0x91,0xe5, -0xc0,0x20,0x82,0xe2,0x0c,0xc0,0x92,0xe5,0x68,0x00,0x1c,0xe3,0xd3,0xff,0xff,0x1a, -0x0c,0xc2,0x93,0xe5,0x83,0xbf,0x83,0xe2,0x02,0x08,0x1c,0xe3,0x0b,0x00,0x00,0x1a, -0x14,0xc2,0x93,0xe5,0x85,0x3f,0x83,0xe2,0x0c,0x30,0x8d,0xe5,0x02,0xc8,0x1c,0xe2, -0x06,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5,0x00,0x00,0x53,0xe3,0x07,0x00,0x00,0x1a, -0x03,0xb0,0xa0,0xe3,0xc6,0xff,0xff,0xea,0x04,0xb0,0xa0,0xe3,0xc4,0xff,0xff,0xea, -0x01,0xb0,0xa0,0xe3,0xc2,0xff,0xff,0xea,0x05,0xb0,0xa0,0xe3,0xc0,0xff,0xff,0xea, -0x00,0x30,0x90,0xe5,0x01,0x08,0x13,0xe3,0x23,0x00,0x00,0x1a,0x02,0x35,0x13,0xe2, -0x0e,0x00,0x00,0x0a,0x0c,0x30,0x92,0xe5,0x68,0x00,0x13,0xe3,0x14,0x00,0x00,0x1a, -0x00,0x30,0x9b,0xe5,0x02,0x38,0x13,0xe2,0x11,0x00,0x00,0x1a,0x0c,0xc0,0x9d,0xe5, -0x00,0x00,0x9c,0xe5,0x02,0x08,0x10,0xe3,0x04,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5, -0x00,0x00,0x53,0xe3,0xa0,0x30,0x91,0x15,0x0c,0x20,0x92,0x15,0x22,0x38,0x43,0x10, -0x10,0x10,0x9d,0xe5,0x03,0x10,0x51,0xe0,0x10,0x10,0x8d,0xe5,0x0c,0x00,0x00,0x0a, -0x14,0x20,0x9d,0xe5,0x03,0x20,0x82,0xe0,0x14,0x20,0x8d,0xe5,0x02,0x10,0xa0,0xe1, -0x3d,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3,0xf4,0xff,0xff,0xea,0x02,0x00,0x00,0x1a, -0x18,0xc0,0x9d,0xe5,0x00,0x00,0x5c,0xe1,0xa7,0xff,0xff,0x8a,0x05,0x00,0xa0,0xe3, -0x19,0xff,0xff,0xea,0x01,0x00,0xa0,0xe1,0x17,0xff,0xff,0xea,0x0c,0x30,0xa0,0xe1, -0xea,0xff,0xff,0xea,0xc0,0x12,0x01,0x00,0x7c,0x10,0x00,0x00,0x05,0x30,0x04,0x00, -0x64,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x04,0x30,0x04,0x00,0x7d,0xc4,0xa0,0xe3, -0xf0,0x4f,0x2d,0xe9,0x04,0xc4,0x9c,0xe5,0x3c,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1, -0x01,0x40,0xa0,0xe1,0xec,0x94,0x9f,0xe5,0x0c,0x20,0x8d,0xe5,0x2c,0xc9,0xa0,0xe1, -0x18,0x30,0x8d,0xe5,0x09,0x90,0x8f,0xe0,0x01,0xc0,0x1c,0xe2,0x05,0x00,0x00,0x1a, -0xd4,0x34,0x9f,0xe5,0xd4,0x04,0x9f,0xe5,0x03,0x30,0x99,0xe7,0x10,0xc0,0xc3,0xe5, -0x3c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x10,0x00,0x90,0xe5,0xc1,0xfa,0xff,0xeb, -0x18,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3,0x00,0x30,0xa0,0x13,0x00,0x30,0x80,0x15, -0x0c,0x50,0x97,0xe5,0x00,0x00,0x55,0xe3,0x28,0x40,0x8d,0x05,0xfb,0x00,0x00,0x1a, -0x94,0x24,0x9f,0xe5,0x02,0x80,0x99,0xe7,0x2c,0x20,0x8d,0xe5,0x00,0x30,0x98,0xe5, -0x02,0x00,0x53,0xe3,0x40,0x30,0xa0,0x13,0x02,0x3c,0xa0,0x03,0x30,0x30,0x8d,0xe5, -0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x18,0x01,0x00,0x0a,0x00,0x00,0xa0,0xe3, -0x00,0x10,0xa0,0xe3,0x10,0x00,0x8d,0xe5,0x14,0x10,0x8d,0xe5,0x02,0x40,0x89,0xe0, -0x64,0x00,0x9d,0xe5,0xfa,0x3f,0xa0,0xe3,0x54,0x54,0x9f,0xe5,0x90,0x13,0x82,0xe0, -0x04,0xa0,0x97,0xe5,0x34,0x90,0x8d,0xe5,0x05,0x50,0x89,0xe0,0x00,0x90,0xa0,0xe1, -0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5,0x0c,0x10,0x9d,0xe5,0x0a,0x00,0x51,0xe1, -0x05,0x00,0x00,0x8a,0x01,0x00,0xa0,0xe1,0x30,0x10,0x9d,0xe5,0x01,0x37,0x00,0xeb, -0x0c,0x20,0x9d,0xe5,0x00,0x00,0x51,0xe3,0x02,0xa0,0xa0,0x01,0x01,0x0a,0x5a,0xe3, -0x01,0xaa,0xa0,0x23,0x00,0x60,0xa0,0xe3,0x1c,0xa0,0x8d,0xe5,0x08,0x00,0xa0,0xe1, -0x07,0xa0,0xa0,0xe1,0x00,0x20,0x9a,0xe5,0x02,0x10,0xa0,0xe3,0x1c,0x30,0x9d,0xe5, -0x00,0x60,0x8d,0xe5,0xd9,0xf8,0xff,0xeb,0x01,0x00,0x79,0xe3,0x08,0x00,0x00,0x0a, -0x3a,0x2d,0x00,0xeb,0x00,0x00,0x59,0xe3,0xec,0x00,0x00,0x0a,0x20,0x30,0x8d,0xe2, -0x0c,0x00,0x93,0xe8,0x00,0x20,0x92,0xe0,0x01,0x30,0xa3,0xe0,0x10,0x20,0x8d,0xe5, -0x14,0x30,0x8d,0xe5,0x7d,0x74,0xa0,0xe3,0x02,0x80,0xa0,0xe3,0x04,0x34,0x97,0xe5, -0x01,0x07,0x13,0xe3,0x5a,0x00,0x00,0x1a,0x00,0x30,0x94,0xe5,0x11,0x20,0xd3,0xe5, -0x00,0x00,0x52,0xe3,0x44,0x00,0x00,0x0a,0x04,0x20,0x93,0xe5,0x94,0xb3,0x9f,0xe5, -0x10,0x82,0x82,0xe5,0x04,0x30,0x93,0xe5,0x10,0x32,0x93,0xe5,0x08,0x50,0x8d,0xe5, -0x04,0x50,0xa0,0xe1,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5, -0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x10,0x42,0x93,0xe5,0x21,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x2a,0x2d,0x00,0xeb,0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a, -0x00,0x30,0x95,0xe5,0x4c,0xb3,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x14,0x32,0x93,0xe5, -0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2, -0x04,0x30,0x93,0xe5,0x14,0x42,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x1b,0x2d,0x00,0xeb,0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5, -0x10,0xb3,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x0c,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5, -0x0c,0x42,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x0c,0x2d,0x00,0xeb, -0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x08,0x50,0x9d,0xe5, -0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x00,0x00,0x95,0xe5,0x40,0x00,0x80,0xe2, -0xd4,0x2c,0x00,0xeb,0x00,0x30,0x95,0xe5,0x30,0x20,0xa0,0xe3,0x00,0x10,0xa0,0xe3, -0x80,0x00,0x93,0xe5,0x80,0x00,0x80,0xe2,0xce,0x2c,0x00,0xeb,0x00,0x30,0x94,0xe5, -0x00,0x20,0x95,0xe5,0x04,0x30,0x93,0xe5,0x8c,0x60,0x82,0xe5,0x9c,0x60,0x82,0xe5, -0x18,0x22,0x93,0xe5,0x02,0x20,0x82,0xe3,0x18,0x22,0x83,0xe5,0x02,0xb0,0xa0,0xe3, -0x10,0x00,0x9a,0xe5,0x2f,0xfa,0xff,0xeb,0x23,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a, -0x01,0x00,0x79,0xe3,0x05,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xec,0x2c,0x00,0xeb, -0xda,0x2c,0x00,0xeb,0x14,0x20,0x9d,0xe5,0x01,0x00,0x52,0xe1,0x85,0x00,0x00,0x9a, -0x01,0x00,0x5b,0xe3,0x04,0x00,0x5b,0x13,0xa3,0xff,0xff,0x0a,0x00,0x00,0x94,0xe5, -0x8f,0xff,0xff,0xea,0x00,0x30,0x94,0xe5,0x04,0xc0,0x93,0xe5,0x20,0x22,0x9c,0xe5, -0x22,0x3e,0x8c,0xe2,0x01,0x00,0x12,0xe3,0x14,0x00,0x00,0x1a,0x80,0x00,0x12,0xe3, -0x16,0x00,0x00,0x0a,0x00,0x20,0x95,0xe5,0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2, -0x0c,0x00,0x91,0xe5,0x68,0x00,0x10,0xe3,0xdf,0xff,0xff,0x1a,0x0c,0xe2,0x9c,0xe5, -0x83,0x0f,0x8c,0xe2,0x02,0x00,0x1e,0xe3,0x0a,0x00,0x00,0x1a,0x14,0xb2,0x9c,0xe5, -0x85,0xef,0x8c,0xe2,0x02,0xb0,0x1b,0xe2,0x06,0x00,0x00,0x1a,0x8c,0xc0,0x92,0xe5, -0x00,0x00,0x5c,0xe3,0x07,0x00,0x00,0x1a,0x03,0xb0,0xa0,0xe3,0xd3,0xff,0xff,0xea, -0x04,0xb0,0xa0,0xe3,0xd1,0xff,0xff,0xea,0x01,0xb0,0xa0,0xe3,0xcf,0xff,0xff,0xea, -0x05,0xb0,0xa0,0xe3,0xcd,0xff,0xff,0xea,0x00,0x30,0x93,0xe5,0x0a,0x70,0xa0,0xe1, -0x01,0x00,0x13,0xe3,0x19,0x00,0x00,0x1a,0x80,0x30,0x13,0xe2,0x39,0x00,0x00,0x0a, -0x0c,0x30,0x91,0xe5,0x68,0x00,0x13,0xe3,0x13,0x00,0x00,0x1a,0x00,0x30,0x90,0xe5, -0x02,0x30,0x13,0xe2,0x10,0x00,0x00,0x1a,0x00,0x00,0x9e,0xe5,0x02,0x00,0x10,0xe3, -0x30,0x00,0x00,0x1a,0x8c,0xb0,0x92,0xe5,0x00,0x00,0x5b,0xe3,0x0b,0x00,0x00,0x0a, -0x9c,0x30,0x92,0xe5,0x0c,0xb0,0x91,0xe5,0x0c,0x00,0x9d,0xe5,0x2b,0xb8,0x43,0xe0, -0x0b,0x00,0x50,0xe1,0x05,0x00,0x00,0x2a,0x0c,0x00,0x9d,0xe5,0x0b,0x30,0x60,0xe0, -0x00,0xb0,0xa0,0xe1,0x0c,0x30,0x87,0xe5,0x02,0x00,0x00,0xea,0x00,0xb0,0xa0,0xe3, -0x00,0x30,0xa0,0xe3,0x0c,0x30,0x87,0xe5,0x00,0x10,0x97,0xe5,0x0b,0x20,0xa0,0xe1, -0x28,0x00,0x9d,0xe5,0x0b,0x30,0x81,0xe0,0x08,0x30,0x87,0xe5,0x6b,0x2c,0x00,0xeb, -0x18,0x10,0x9d,0xe5,0x0c,0x20,0x9d,0xe5,0x00,0x00,0x51,0xe3,0x00,0x30,0x91,0x15, -0x0b,0x30,0x83,0x10,0x00,0x30,0x81,0x15,0x01,0x00,0x72,0xe3,0x39,0x00,0x00,0x0a, -0x04,0xa0,0x97,0xe5,0x0a,0x00,0x5b,0xe1,0x36,0x00,0x00,0x3a,0x0b,0x20,0x52,0xe0, -0x0c,0x20,0x8d,0xe5,0x35,0x00,0x00,0x0a,0x28,0x30,0x9d,0xe5,0x00,0x80,0x94,0xe5, -0x0b,0x30,0x83,0xe0,0x28,0x30,0x8d,0xe5,0x26,0xff,0xff,0xea,0x34,0x90,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x2c,0x40,0x9d,0xe5,0xc0,0x00,0x9f,0xe5,0x04,0x30,0x99,0xe7, -0x10,0x20,0xc3,0xe5,0xf9,0xfe,0xff,0xea,0x03,0xb0,0xa0,0xe1,0xdb,0xff,0xff,0xea, -0x0c,0x10,0x9d,0xe5,0x04,0x00,0xa0,0xe1,0x05,0x00,0x51,0xe1,0x01,0x50,0xa0,0x31, -0x08,0x10,0x97,0xe5,0x05,0x20,0xa0,0xe1,0x48,0x2c,0x00,0xeb,0x18,0x30,0x9d,0xe5, -0x08,0x20,0x97,0xe5,0x00,0x00,0x53,0xe3,0x0c,0x30,0x97,0xe5,0x18,0x00,0x9d,0x15, -0x05,0x20,0x82,0xe0,0x08,0x20,0x87,0xe5,0x03,0x30,0x65,0xe0,0x0c,0x30,0x87,0xe5, -0x00,0x30,0x90,0x15,0x05,0x30,0x83,0x10,0x00,0x30,0x80,0x15,0x0c,0x30,0x97,0x15, -0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x1a,0x0c,0x10,0x9d,0xe5,0x05,0x40,0x84,0xe0, -0x00,0x30,0x97,0xe5,0x28,0x40,0x8d,0xe5,0x01,0x10,0x65,0xe0,0x0c,0x10,0x8d,0xe5, -0x08,0x30,0x87,0xe5,0xe5,0xfe,0xff,0xea,0x02,0x00,0x00,0x1a,0x10,0x30,0x9d,0xe5, -0x00,0x00,0x53,0xe1,0x75,0xff,0xff,0x8a,0x05,0x00,0xa0,0xe3,0xd3,0xfe,0xff,0xea, -0x64,0x00,0x9d,0xe5,0xd1,0xfe,0xff,0xea,0x00,0x00,0xa0,0xe3,0xcf,0xfe,0xff,0xea, -0x0c,0x00,0x9d,0xe5,0xcd,0xfe,0xff,0xea,0xbc,0x0e,0x01,0x00,0x7c,0x10,0x00,0x00, -0x05,0x30,0x04,0x00,0x64,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0xf0,0x41,0x2d,0xe9, -0x01,0x40,0xa0,0xe1,0xb0,0x51,0x9f,0xe5,0x00,0x80,0xa0,0xe1,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0xa4,0x31,0x9f,0xe5,0x05,0x50,0x8f,0xe0,0x03,0x30,0x95,0xe7, -0x80,0x60,0x93,0xe5,0x04,0x73,0x86,0xe0,0x07,0x00,0xa0,0xe1,0x15,0x2c,0x00,0xeb, -0x00,0x00,0x54,0xe3,0x17,0x00,0x00,0x1a,0x02,0x39,0xa0,0xe3,0x04,0x33,0x86,0xe7, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5,0x04,0x33,0x96,0xe7,0x01,0x35,0x83,0xe3, -0x04,0x33,0x86,0xe7,0xa4,0x40,0xb0,0xe1,0x43,0x00,0x00,0x1a,0x60,0x31,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5,0x0c,0x10,0xc1,0xe3, -0x1c,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5,0x01,0x10,0xc1,0xe3, -0x1c,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x1c,0x22,0x93,0xe5,0x80,0x20,0x82,0xe3, -0x1c,0x22,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x02,0x30,0x44,0xe2,0x01,0x00,0x53,0xe3, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x87,0xe5,0x01,0x35,0xa0,0x83,0x04,0x23,0x96,0xe7, -0x19,0x00,0x00,0x9a,0x01,0x00,0x14,0xe3,0x03,0x30,0x82,0xe1,0x04,0x33,0x86,0xe7, -0xe3,0xff,0xff,0x0a,0xa4,0x40,0xb0,0xe1,0x18,0x00,0x00,0x0a,0xf0,0x30,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x03,0x17,0xc1,0xe3, -0x02,0x17,0x81,0xe3,0x20,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5, -0x01,0x18,0xc1,0xe3,0x20,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5, -0x01,0x15,0x81,0xe3,0x20,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x20,0x22,0x93,0xe5, -0x02,0x25,0x82,0xe3,0x20,0x22,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x00,0x30,0x98,0xe5, -0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03,0x01,0x35,0xa0,0x13,0xe0,0xff,0xff,0xea, -0x8c,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5, -0x03,0x17,0xc1,0xe3,0x1c,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x1c,0x12,0x92,0xe5, -0x01,0x18,0xc1,0xe3,0x1c,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x1c,0x22,0x93,0xe5, -0x02,0x25,0x82,0xe3,0x1c,0x22,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0x50,0x30,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5,0x0c,0x10,0xc1,0xe3, -0x08,0x10,0x81,0xe3,0x20,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5, -0x01,0x10,0xc1,0xe3,0x20,0x12,0x82,0xe5,0x04,0x20,0x93,0xe5,0x20,0x12,0x92,0xe5, -0x40,0x10,0x81,0xe3,0x20,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x20,0x22,0x93,0xe5, -0x80,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0xf0,0x81,0xbd,0xe8,0xa8,0x09,0x01,0x00, -0x98,0x10,0x00,0x00,0xb0,0x10,0x00,0x00,0xf0,0x4f,0x2d,0xe9,0x34,0xd0,0x4d,0xe2, -0x2c,0x00,0x8d,0xe5,0x01,0x00,0x71,0xe3,0x01,0x50,0xa0,0xe1,0x98,0x46,0x9f,0xe5, -0x58,0x00,0xdd,0xe5,0x28,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5,0x04,0x40,0x8f,0xe0, -0x24,0x00,0x8d,0xe5,0xff,0x00,0x00,0x0a,0xa1,0x10,0xa0,0xe1,0x01,0xb0,0x15,0xe2, -0x01,0x60,0xa0,0x03,0x01,0x68,0xa0,0x13,0x16,0x61,0xa0,0xe1,0x20,0x10,0x8d,0xe5, -0x08,0x10,0x8d,0xe5,0x64,0xa6,0x9f,0xe5,0x04,0x90,0xa0,0xe1,0x60,0x76,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x20,0x93,0xe5,0x10,0x62,0x82,0xe5,0x04,0x30,0x93,0xe5, -0x10,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xbb,0x2b,0x00,0xeb,0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1, -0x1c,0x76,0x9f,0xe5,0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xac,0x2b,0x00,0xeb, -0x06,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0xe0,0x75,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x9d,0x2b,0x00,0xeb,0x06,0x00,0x18,0xe1, -0xf6,0xff,0xff,0x1a,0xac,0x75,0x9f,0xe5,0x85,0x32,0xa0,0xe1,0x20,0x20,0xa0,0xe3, -0x05,0x63,0xa0,0xe1,0x02,0x90,0x85,0xe0,0x14,0x30,0x8d,0xe5,0x07,0x00,0x94,0xe7, -0x24,0xc0,0x85,0xe2,0x00,0x10,0xa0,0xe3,0x18,0xc0,0x8d,0xe5,0x0c,0x60,0x8d,0xe5, -0x03,0x00,0x80,0xe0,0x10,0x90,0x8d,0xe5,0x5e,0x2b,0x00,0xeb,0x07,0x30,0x94,0xe7, -0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x06,0x00,0x80,0xe0, -0x58,0x2b,0x00,0xeb,0x07,0x20,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x18,0xe0,0x9d,0xe5, -0x01,0x00,0x5b,0xe1,0x0a,0x30,0x94,0xe7,0x09,0xc1,0x82,0xe0,0x0e,0x01,0x82,0xe0, -0x04,0x10,0x8c,0xe5,0x04,0x10,0x80,0xe5,0x04,0x30,0x93,0xe5,0x18,0x02,0x93,0xe5, -0x3f,0x00,0x00,0x1a,0x08,0x10,0x9d,0xe5,0x80,0x80,0x92,0xe5,0x01,0x20,0xa0,0xe3, -0x0c,0x90,0x9d,0xe5,0x12,0x01,0x80,0xe1,0x0b,0x10,0xa0,0xe1,0x09,0x60,0x88,0xe0, -0x18,0x02,0x83,0xe5,0x30,0x20,0xa0,0xe3,0x06,0x00,0xa0,0xe1,0x41,0x2b,0x00,0xeb, -0x00,0x00,0x55,0xe3,0x3c,0x00,0x00,0x1a,0x02,0x29,0xa0,0xe3,0x01,0x35,0xa0,0xe3, -0x05,0x23,0x88,0xe7,0x05,0x23,0x98,0xe7,0x07,0x80,0x94,0xe7,0x03,0x30,0x82,0xe1, -0x14,0xe0,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x10,0x00,0x9d,0xe5,0x01,0xc0,0xa0,0xe3, -0x02,0x32,0x83,0xe3,0x0e,0x90,0x88,0xe0,0x18,0xe0,0x9d,0xe5,0x00,0x30,0x86,0xe5, -0x00,0x21,0x88,0xe0,0x08,0x10,0x86,0xe5,0x09,0x00,0xa0,0xe1,0x04,0xc0,0x82,0xe5, -0x0e,0x31,0x88,0xe0,0x1c,0x20,0x9d,0xe5,0x04,0x20,0x83,0xe5,0x20,0x20,0xa0,0xe3, -0x04,0xc0,0x8d,0xe5,0x27,0x2b,0x00,0xeb,0x1c,0x30,0x9d,0xe5,0x00,0x00,0x5b,0xe3, -0x04,0xc0,0x9d,0xe5,0x01,0x10,0xa0,0x03,0x24,0x00,0x9d,0xe5,0x01,0x18,0xa0,0x13, -0x03,0x28,0xa0,0xe1,0x85,0xc2,0x88,0xe7,0x0a,0x30,0x94,0xe7,0x00,0x00,0x50,0xe3, -0x80,0x20,0x82,0xe3,0x1f,0xc0,0xc9,0xe3,0x04,0x20,0x89,0xe5,0x28,0x20,0x9d,0xe5, -0x08,0x20,0x89,0xe5,0x08,0x00,0x96,0xe5,0x04,0x20,0x93,0xe5,0x00,0x00,0x8c,0xe1, -0x08,0x00,0x86,0xe5,0x08,0x60,0x9d,0xe5,0x0c,0x02,0x92,0xe5,0x11,0x16,0x80,0xe1, -0x24,0x00,0x9d,0x05,0x0c,0x12,0x82,0xe5,0x16,0x00,0x00,0x1a,0x34,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x08,0xc0,0x9d,0xe5,0x80,0x60,0x92,0xe5,0x01,0x28,0xa0,0xe3, -0x0c,0xe0,0x9d,0xe5,0x12,0x0c,0x80,0xe1,0x30,0x20,0xa0,0xe3,0x0e,0x60,0x86,0xe0, -0x18,0x02,0x83,0xe5,0x06,0x00,0xa0,0xe1,0x02,0x2b,0x00,0xeb,0x02,0x30,0x45,0xe2, -0x00,0x20,0x96,0xe5,0x01,0x00,0x53,0xe3,0x01,0x35,0xa0,0x83,0xc1,0xff,0xff,0x8a, -0x2c,0xc0,0x9d,0xe5,0x00,0x30,0x9c,0xe5,0x02,0x00,0x53,0xe3,0x02,0x34,0xa0,0x03, -0x01,0x35,0xa0,0x13,0xbb,0xff,0xff,0xea,0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3, -0x04,0x10,0x93,0x15,0x04,0x10,0x93,0x05,0x20,0x32,0x91,0x15,0x1c,0x32,0x91,0x05, -0x00,0x00,0x5b,0xe3,0x01,0x20,0x03,0x02,0x23,0x28,0xa0,0x11,0x01,0x20,0x02,0x12, -0x00,0x00,0x52,0xe3,0x1a,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3,0xa3,0x3b,0xa0,0x11, -0xa3,0x33,0xa0,0x01,0x01,0x30,0x03,0x12,0x01,0x30,0x03,0x02,0x00,0x00,0x53,0xe3, -0x13,0x00,0x00,0x0a,0x07,0x20,0x94,0xe7,0x0c,0xc0,0x9d,0xe5,0x80,0x30,0x92,0xe5, -0x0c,0x30,0x83,0xe0,0x0c,0x30,0x93,0xe5,0x68,0x00,0x13,0xe2,0x0c,0x00,0x00,0x1a, -0x0c,0xc2,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x60,0x9d,0xe5,0x01,0x30,0xa0,0x03, -0x01,0x38,0xa0,0x13,0x13,0xc6,0x1c,0xe0,0x3c,0x00,0x00,0x1a,0x14,0x02,0x91,0xe5, -0x13,0x66,0x10,0xe0,0xce,0x00,0x00,0x1a,0x10,0x90,0x9d,0xe5,0x09,0x21,0x82,0xe0, -0x04,0x30,0x92,0xe5,0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3,0x20,0x32,0x91,0x15, -0x2e,0x00,0x00,0x0a,0x00,0x00,0x5b,0xe3,0x23,0x28,0xa0,0x11,0x01,0x20,0x03,0x02, -0x01,0x20,0x02,0x12,0x00,0x00,0x52,0xe3,0x2a,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3, -0xa3,0x3b,0xa0,0x11,0xa3,0x33,0xa0,0x01,0x01,0x30,0x03,0x12,0x01,0x30,0x03,0x02, -0x00,0x00,0x53,0xe3,0x23,0x00,0x00,0x0a,0x07,0x30,0x94,0xe7,0x0c,0xc0,0x9d,0xe5, -0x80,0x20,0x93,0xe5,0x0c,0x20,0x82,0xe0,0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3, -0x1c,0x00,0x00,0x1a,0x0c,0x22,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x40,0x9d,0xe5, -0x01,0x00,0xa0,0x03,0x01,0x08,0xa0,0x13,0x10,0x44,0x12,0xe0,0x15,0x00,0x00,0x1a, -0x14,0x22,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x60,0x9d,0xe5,0x01,0xb8,0xa0,0x13, -0x01,0xb0,0xa0,0x03,0x1b,0x66,0x12,0xe0,0x0e,0x00,0x00,0x1a,0x10,0x90,0x9d,0xe5, -0x09,0x31,0x83,0xe0,0x04,0x00,0x93,0xe5,0x00,0x00,0x50,0xe3,0x1a,0x00,0xa0,0x03, -0x00,0x00,0xa0,0x13,0x94,0xff,0xff,0xea,0x02,0x21,0xe0,0xe3,0x01,0x60,0xa0,0xe1, -0x08,0x20,0x8d,0xe5,0x01,0xb0,0xa0,0xe3,0x20,0x20,0x8d,0xe5,0x00,0xff,0xff,0xea, -0x1c,0x32,0x91,0xe5,0xce,0xff,0xff,0xea,0x1a,0x00,0xa0,0xe3,0x8a,0xff,0xff,0xea, -0x1c,0x00,0x8d,0xe5,0x0a,0x60,0x84,0xe0,0x07,0x80,0x84,0xe0,0x01,0x00,0xa0,0xe3, -0xc3,0x2a,0x00,0xeb,0x20,0xc0,0x9d,0xe5,0x00,0x00,0x5c,0xe3,0x00,0x30,0x96,0x15, -0x00,0x30,0x96,0x05,0x04,0x10,0x93,0x15,0x04,0x10,0x93,0x05,0x20,0x22,0x91,0x15, -0x1c,0x22,0x91,0x05,0x00,0x00,0x5b,0xe3,0x01,0x00,0x02,0x02,0x22,0x08,0xa0,0x11, -0x01,0x00,0x00,0x12,0x00,0x00,0x50,0xe3,0x74,0x00,0x00,0x1a,0x00,0x00,0x5b,0xe3, -0xa2,0x2b,0xa0,0x11,0xa2,0x23,0xa0,0x01,0x01,0x20,0x02,0x12,0x01,0x20,0x02,0x02, -0x00,0x00,0x52,0xe3,0x6f,0x00,0x00,0x0a,0x00,0x00,0x98,0xe5,0x0c,0x90,0x9d,0xe5, -0x80,0x20,0x90,0xe5,0x09,0x20,0x82,0xe0,0x0c,0x20,0x92,0xe5,0x68,0x00,0x12,0xe3, -0x6a,0x00,0x00,0x1a,0x0c,0xc2,0x91,0xe5,0x00,0x00,0x5b,0xe3,0x08,0x90,0x9d,0xe5, -0x01,0x20,0xa0,0x03,0x01,0x28,0xa0,0x13,0x12,0xc9,0x1c,0xe0,0x65,0x00,0x00,0x1a, -0x14,0xc2,0x91,0xe5,0x12,0xc9,0x1c,0xe0,0x62,0x00,0x00,0x1a,0x10,0x60,0x9d,0xe5, -0x06,0x31,0x80,0xe0,0x04,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0x03,0x30,0xa0,0x03, -0x00,0x30,0xa0,0x13,0x01,0x00,0x53,0xe3,0x0a,0x30,0x94,0xe7,0x94,0xff,0xff,0x1a, -0x01,0x00,0x75,0xe3,0x04,0x00,0x00,0x0a,0x08,0xc0,0x9d,0xe5,0x00,0x00,0x5b,0xe3, -0x01,0x50,0xa0,0x03,0x01,0x58,0xa0,0x13,0x15,0x5c,0xa0,0xe1,0x10,0x52,0x81,0xe5, -0x0a,0x80,0x84,0xe0,0x04,0x30,0x93,0xe5,0x64,0x61,0x9f,0xe5,0x10,0x92,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x98,0xe5,0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5, -0x10,0x92,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x80,0x2a,0x00,0xeb, -0x05,0x00,0x19,0xe1,0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0x30,0x61,0x9f,0xe5, -0x0a,0x30,0xb9,0xe7,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x99,0xe5,0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5, -0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x71,0x2a,0x00,0xeb,0x05,0x00,0x18,0xe1, -0xf6,0xff,0xff,0x1a,0x04,0x90,0xa0,0xe1,0xf4,0x60,0x9f,0xe5,0x0a,0x30,0xb9,0xe7, -0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5, -0x01,0x60,0x56,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x62,0x2a,0x00,0xeb,0x05,0x00,0x18,0xe1,0xf6,0xff,0xff,0x1a, -0x07,0x00,0x94,0xe7,0x00,0x10,0xa0,0xe3,0x14,0xe0,0x9d,0xe5,0x20,0x20,0xa0,0xe3, -0x0e,0x00,0x80,0xe0,0x2b,0x2a,0x00,0xeb,0x07,0x30,0x94,0xe7,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x0c,0x30,0x9d,0xe5,0x03,0x00,0x80,0xe0, -0x24,0x2a,0x00,0xeb,0x07,0x20,0x94,0xe7,0x00,0x30,0xa0,0xe3,0x0a,0x10,0x94,0xe7, -0x03,0x00,0x5b,0xe1,0x10,0x40,0x9d,0xe5,0x01,0xb8,0xa0,0x13,0x18,0x60,0x9d,0xe5, -0x01,0xb0,0xa0,0x03,0x08,0x90,0x9d,0xe5,0x03,0x00,0xa0,0xe3,0x04,0xc1,0x82,0xe0, -0x06,0x21,0x82,0xe0,0x04,0x30,0x8c,0xe5,0x04,0x30,0x82,0xe5,0x04,0x30,0x91,0xe5, -0x18,0x22,0x93,0xe5,0x1b,0xb9,0x82,0xe1,0x18,0xb2,0x83,0xe5,0x02,0xff,0xff,0xea, -0x04,0x30,0xa0,0xe3,0xa6,0xff,0xff,0xea,0x05,0x30,0xa0,0xe3,0xa4,0xff,0xff,0xea, -0x02,0x30,0xa0,0xe3,0xa2,0xff,0xff,0xea,0x1c,0x00,0x9d,0xe5,0x28,0x20,0x9f,0xe5, -0x01,0x00,0x80,0xe2,0x02,0x00,0x50,0xe1,0x1c,0x00,0x8d,0xe5,0x6e,0xff,0xff,0x1a, -0x9e,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe5,0x69,0xff,0xff,0xea,0xd4,0x07,0x01,0x00, -0xb0,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x98,0x10,0x00,0x00,0x40,0x42,0x0f,0x00, -0xf0,0x4f,0x2d,0xe9,0x44,0xd0,0x4d,0xe2,0x00,0x4f,0x9f,0xe5,0x00,0xb0,0xa0,0xe1, -0x00,0x90,0xa0,0xe3,0xf8,0x3e,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0xf4,0x5e,0x9f,0xe5, -0xf4,0x6e,0x9f,0xe5,0x03,0x30,0x84,0xe0,0xf0,0x1e,0x9f,0xe5,0x0c,0x30,0x8d,0xe5, -0xec,0x3e,0x9f,0xe5,0x06,0x60,0x84,0xe0,0x05,0x00,0x94,0xe7,0x14,0x10,0x8d,0xe5, -0x03,0x30,0x84,0xe0,0x10,0x30,0x8d,0xe5,0x0d,0x00,0x00,0xea,0x04,0x00,0x18,0xe3, -0x04,0x30,0x90,0x15,0x05,0x30,0x94,0x07,0xb4,0x21,0x93,0x15,0x04,0x30,0x93,0x05, -0xa2,0x2c,0xa0,0x11,0x03,0x20,0x02,0x12,0x00,0x20,0x80,0x15,0x08,0x22,0x93,0xe5, -0x01,0x00,0x12,0xe3,0xeb,0x00,0x00,0x1a,0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x0f,0x01,0x00,0x1a,0x04,0x20,0x90,0xe5,0x34,0x31,0x92,0xe5,0x34,0x31,0x82,0xe5, -0x7d,0x24,0xa0,0xe3,0x08,0x24,0x92,0xe5,0x01,0x2b,0x12,0xe2,0xb8,0x01,0x00,0x0a, -0x83,0x8b,0xa0,0xe1,0x40,0x00,0x13,0xe3,0xa8,0x8b,0xa0,0xe1,0xe6,0xff,0xff,0x0a, -0x04,0x30,0x90,0xe5,0x00,0x20,0xa0,0xe3,0x68,0x7e,0x9f,0xe5,0x05,0x90,0x84,0xe0, -0x44,0x21,0x83,0xe5,0x04,0x30,0x90,0xe5,0x08,0x22,0x93,0xe5,0x08,0x22,0x83,0xe5, -0x04,0x30,0x90,0xe5,0x18,0x22,0x93,0xe5,0x18,0x22,0x83,0xe5,0x00,0x20,0xe0,0xe3, -0x04,0x30,0x90,0xe5,0x10,0x22,0x83,0xe5,0x04,0x30,0x90,0xe5,0x10,0xa2,0x93,0xe5, -0x05,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x10,0x93,0xe5, -0x21,0x2e,0x81,0xe2,0x10,0xa2,0x91,0xe5,0x12,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xe7,0x29,0x00,0xeb,0x00,0x00,0x5a,0xe3,0xf5,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x05,0x90,0x84,0xe0,0xfc,0x7d,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x99,0xe5,0x01,0x70,0x57,0xe2,0x04,0x20,0x93,0xe5, -0x14,0xa2,0x92,0xe5,0x00,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xd8,0x29,0x00,0xeb, -0x00,0x00,0x5a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0, -0xc0,0x7d,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x0c,0x92,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x20,0x93,0xe5,0x0c,0x92,0x92,0xe5, -0xf1,0x01,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xc9,0x29,0x00,0xeb,0x00,0x00,0x59,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x04,0x20,0x93,0xe5,0x21,0x2e,0x82,0xe2, -0x02,0x10,0xa0,0xe3,0x7c,0x7d,0x9f,0xe5,0x00,0x10,0x82,0xe5,0x05,0x20,0x84,0xe0, -0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5,0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1, -0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5,0x27,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xb2,0x29,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x2c,0x7d,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0, -0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5, -0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5, -0x14,0xa2,0x93,0xe5,0x15,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xa0,0x29,0x00,0xeb, -0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0xe4,0x7c,0x9f,0xe5, -0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1, -0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x8e,0x29,0x00,0xeb,0x02,0x00,0x1a,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x06,0x50,0xa0,0xe1,0x08,0x60,0x9d,0xe5,0x00,0x10,0xa0,0xe3, -0x20,0x20,0xa0,0xe3,0x05,0xa0,0x84,0xe0,0x88,0x7c,0x9f,0xe5,0x00,0x00,0x96,0xe5, -0x40,0x00,0x80,0xe2,0x53,0x29,0x00,0xeb,0x00,0x30,0x96,0xe5,0x00,0x10,0xa0,0xe3, -0x30,0x20,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x80,0x00,0x80,0xe2,0x4d,0x29,0x00,0xeb, -0x05,0x30,0x94,0xe7,0x00,0x00,0xa0,0xe3,0x00,0x10,0x96,0xe5,0x04,0x20,0x93,0xe5, -0x8c,0x00,0x81,0xe5,0x9c,0x00,0x81,0xe5,0x18,0x12,0x92,0xe5,0x02,0x10,0x81,0xe3, -0x18,0x12,0x82,0xe5,0x02,0x18,0xa0,0xe3,0x04,0x20,0x93,0xe5,0x10,0x12,0x82,0xe5, -0x04,0x30,0x93,0xe5,0x10,0x32,0x93,0xe5,0x08,0x60,0x8d,0xe5,0x05,0x60,0xa0,0xe1, -0x04,0x50,0xa0,0xe1,0x0a,0x40,0xa0,0xe1,0x03,0xa0,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5, -0x27,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x61,0x29,0x00,0xeb,0x02,0x08,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0xe8,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7, -0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5, -0x14,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x14,0xa2,0x93,0xe5,0x15,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x4f,0x29,0x00,0xeb,0x02,0x08,0x1a,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1, -0xa0,0x7b,0x9f,0xe5,0x06,0x30,0x94,0xe7,0x06,0x20,0x84,0xe0,0x04,0x50,0xa0,0xe1, -0x02,0x40,0xa0,0xe1,0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x94,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x0c,0xa2,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x3d,0x29,0x00,0xeb,0x02,0x08,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x06,0x50,0xa0,0xe1,0x08,0x60,0x9d,0xe5, -0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3,0x00,0x00,0x96,0xe5,0x60,0x00,0x80,0xe2, -0x04,0x29,0x00,0xeb,0x00,0x30,0x96,0xe5,0x00,0x10,0xa0,0xe3,0x30,0x20,0xa0,0xe3, -0x80,0x00,0x93,0xe5,0xc0,0x00,0x80,0xe2,0xfe,0x28,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x00,0x30,0xa0,0xe3,0x00,0x10,0x96,0xe5,0x04,0x20,0x90,0xe5,0x90,0x30,0x81,0xe5, -0xa0,0x30,0x81,0xe5,0x18,0x12,0x92,0xe5,0x02,0x18,0x81,0xe3,0x18,0x12,0x82,0xe5, -0x10,0x30,0xc0,0xe5,0x08,0xff,0xff,0xea,0x00,0x10,0x96,0xe5,0x08,0x00,0x80,0xe2, -0x08,0x22,0x83,0xe5,0x08,0x20,0xa0,0xe3,0x00,0x90,0xa0,0xe3,0x05,0x70,0x84,0xe0, -0x80,0x10,0x91,0xe5,0x28,0x10,0x81,0xe2,0xe8,0x28,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x3c,0x90,0xcd,0xe5,0x3d,0x90,0xcd,0xe5,0x38,0x90,0xcd,0xe5,0x39,0x90,0xcd,0xe5, -0x08,0x20,0xd0,0xe5,0x0f,0x80,0xd0,0xe5,0x0e,0x30,0xd0,0xe5,0x02,0x00,0x52,0xe3, -0x08,0x84,0x83,0xe1,0xe0,0x00,0x00,0x0a,0x14,0x00,0x00,0x8a,0x09,0x00,0x52,0xe1, -0x1e,0x00,0x00,0x1a,0x09,0x30,0xd0,0xe5,0x05,0x00,0x53,0xe3,0x43,0x01,0x00,0x0a, -0x09,0x00,0x53,0xe3,0x1e,0x02,0x00,0x0a,0x03,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11, -0x11,0x00,0x00,0x1a,0x0a,0x30,0xd0,0xe5,0x02,0x00,0x53,0xe3,0x02,0x90,0xa0,0x11, -0x04,0x02,0x00,0x0a,0x05,0x00,0x94,0xe7,0x10,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0xef,0xfe,0xff,0x0a,0x09,0x00,0xa0,0xe1,0x44,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x81,0x00,0x52,0xe3,0x83,0x00,0x00,0x0a,0x82,0x00,0x52,0xe3,0xab,0x00,0x00,0x0a, -0x80,0x00,0x52,0xe3,0x9b,0x00,0x00,0x0a,0x00,0x90,0xa0,0xe3,0x04,0x30,0x90,0xe5, -0x34,0x2a,0x9f,0xe5,0x05,0x00,0x94,0xe7,0x1c,0x22,0x83,0xe5,0xed,0xff,0xff,0xea, -0x01,0x00,0x52,0xe3,0xf7,0xff,0xff,0x1a,0x00,0x30,0x96,0xe5,0x04,0x20,0x90,0xe5, -0x10,0x8a,0x9f,0xe5,0x8c,0x90,0x83,0xe5,0x90,0x90,0x83,0xe5,0x02,0x30,0xa0,0xe3, -0x10,0x32,0x82,0xe5,0x04,0x30,0x90,0xe5,0x10,0xa2,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x97,0xe5,0x01,0x80,0x58,0xe2,0x04,0x30,0x93,0xe5,0x10,0xa2,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xd9,0x28,0x00,0xeb,0x02,0x00,0x1a,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0xc4,0x79,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0xca,0x28,0x00,0xeb,0x02,0x00,0x18,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0x88,0x79,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xbb,0x28,0x00,0xeb,0x02,0x00,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x02,0x18,0xa0,0xe3,0x4c,0x79,0x9f,0xe5,0x05,0xa0,0x84,0xe0,0x04,0x20,0x93,0xe5, -0x10,0x12,0x82,0xe5,0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5,0x04,0x00,0x00,0xea, -0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x10,0x82,0x93,0xe5, -0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0xa9,0x28,0x00,0xeb,0x02,0x08,0x18,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0x04,0x79,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5, -0x01,0x70,0x57,0xe2,0x04,0x30,0x93,0xe5,0x14,0x82,0x93,0xe5,0x12,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x9a,0x28,0x00,0xeb,0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x05,0xa0,0x84,0xe0,0xc8,0x78,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0x0c,0x82,0x93,0xe5,0x04,0x00,0x00,0xea,0x00,0x30,0x9a,0xe5,0x01,0x70,0x57,0xe2, -0x04,0x30,0x93,0xe5,0x0c,0x82,0x93,0xe5,0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x8b,0x28,0x00,0xeb,0x02,0x08,0x18,0xe3,0xf6,0xff,0xff,0x1a,0x05,0xc0,0x94,0xe7, -0x01,0x70,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x07,0x10,0xa0,0xe1,0x02,0x30,0xa0,0xe1, -0x04,0x80,0x9c,0xe5,0x0c,0x00,0xa0,0xe1,0x20,0xe2,0x98,0xe5,0x40,0xe0,0x8e,0xe3, -0x20,0xe2,0x88,0xe5,0x04,0xc0,0x9c,0xe5,0x20,0xe2,0x9c,0xe5,0x01,0xe5,0x8e,0xe3, -0x20,0xe2,0x8c,0xe5,0x00,0x70,0x8d,0xe5,0x9a,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2, -0x77,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7,0x0a,0x30,0xd0,0xe5,0x13,0x30,0xc0,0xe5, -0x05,0x00,0x94,0xe7,0x73,0xff,0xff,0xea,0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3, -0x08,0x70,0xa0,0x01,0x3c,0x10,0x8d,0x02,0x5e,0x00,0x00,0x1a,0x0b,0x00,0xa0,0xe1, -0x07,0x20,0xa0,0xe1,0x01,0xa0,0xa0,0xe3,0x38,0x28,0x00,0xeb,0x05,0x00,0x94,0xe7, -0x08,0x00,0x57,0xe1,0x07,0x30,0xa0,0x31,0x08,0x30,0xa0,0x21,0x0a,0x10,0xa0,0xe1, -0x0b,0x20,0xa0,0xe1,0x00,0xa0,0x8d,0xe5,0x82,0xfc,0xff,0xeb,0x00,0x90,0x50,0xe2, -0x5f,0xff,0xff,0x1a,0x05,0x00,0x94,0xe7,0x09,0x10,0xa0,0xe1,0x09,0x20,0xa0,0xe1, -0x09,0x30,0xa0,0xe1,0x00,0xa0,0x8d,0xe5,0x7a,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1, -0x05,0x00,0x94,0xe7,0x57,0xff,0xff,0xea,0x09,0x30,0xd0,0xe5,0x06,0x00,0x53,0xe3, -0x52,0x00,0x00,0x0a,0x08,0x00,0x53,0xe3,0x89,0x00,0x00,0x0a,0x00,0x00,0x53,0xe3, -0x5d,0xff,0xff,0x1a,0x14,0x30,0x9d,0xe5,0x02,0x70,0xa0,0xe3,0x03,0x10,0x84,0xe0, -0xdd,0xff,0xff,0xea,0x10,0x20,0xc0,0xe5,0x23,0x90,0xa0,0xe3,0x4c,0xff,0xff,0xea, -0x09,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x3e,0x00,0x00,0x1a,0x0d,0x20,0xd0,0xe5, -0x0c,0x30,0xd0,0xe5,0x02,0x34,0x83,0xe1,0x01,0x00,0x53,0xe3,0x6c,0x01,0x00,0x0a, -0x6a,0x00,0x00,0x2a,0x04,0x30,0x90,0xe5,0x1c,0x22,0x93,0xe5,0x01,0x00,0x12,0xe3, -0x3b,0x01,0x00,0x1a,0x80,0x00,0x12,0xe3,0xa4,0x00,0x00,0x0a,0x00,0x20,0x96,0xe5, -0x80,0x10,0x92,0xe5,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x9f,0x00,0x00,0x1a, -0x0c,0x12,0x93,0xe5,0x01,0x00,0x11,0xe3,0x9c,0x00,0x00,0x1a,0x14,0x32,0x93,0xe5, -0x01,0x00,0x13,0xe3,0x84,0x30,0x92,0x05,0x98,0x00,0x00,0xea,0x09,0x30,0xd0,0xe5, -0x01,0x00,0x53,0xe3,0x20,0x00,0x00,0x0a,0x03,0x00,0x53,0xe3,0x36,0xff,0xff,0x1a, -0x0a,0x30,0xd0,0xe5,0x00,0x00,0x53,0xe3,0x1e,0x00,0x00,0x1a,0x0d,0x10,0xd0,0xe5, -0x0c,0x20,0xd0,0xe5,0x01,0x24,0x82,0xe1,0x01,0x00,0x52,0xe3,0x74,0x00,0x00,0x0a, -0x73,0x00,0x00,0x3a,0x80,0x00,0x52,0xe3,0x71,0x00,0x00,0x0a,0x81,0x00,0x52,0xe3, -0x3a,0x00,0x00,0x1a,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x28,0x82,0xe3, -0x20,0x22,0x83,0xe5,0x01,0xc0,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x0c,0x10,0xa0,0xe1, -0x02,0x30,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x32,0xfc,0xff,0xeb,0x00,0x90,0xa0,0xe1, -0x05,0x00,0x94,0xe7,0x0f,0xff,0xff,0xea,0x0a,0x00,0x53,0xe3,0x13,0x10,0x80,0x02, -0x08,0x70,0xa0,0x01,0x18,0xff,0xff,0x1a,0x9b,0xff,0xff,0xea,0x0a,0x30,0xd0,0xe5, -0x00,0x00,0x53,0xe3,0x1b,0x00,0x00,0x0a,0x04,0x30,0x90,0xe5,0x05,0x00,0x94,0xe7, -0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0x01,0xff,0xff,0xea, -0x34,0x90,0x8d,0xe5,0x30,0x90,0x8d,0xe5,0x2c,0x90,0x8d,0xe5,0xc0,0x31,0x00,0xeb, -0x00,0xa0,0xa0,0xe1,0xc5,0x31,0x00,0xeb,0x00,0x90,0xa0,0xe1,0xca,0x31,0x00,0xeb, -0x00,0x30,0xa0,0xe1,0x00,0x00,0x97,0xe5,0x0b,0x20,0xd0,0xe5,0x01,0x20,0x42,0xe2, -0x06,0x00,0x52,0xe3,0x02,0xf1,0x8f,0x90,0xfe,0xfe,0xff,0xea,0xc2,0x00,0x00,0xea, -0x9f,0x00,0x00,0xea,0x93,0x00,0x00,0xea,0xfa,0xfe,0xff,0xea,0xf9,0xfe,0xff,0xea, -0x7a,0x00,0x00,0xea,0x58,0x00,0x00,0xea,0x0d,0x10,0xd0,0xe5,0x0c,0x20,0xd0,0xe5, -0x01,0x24,0x82,0xe1,0x01,0x00,0x52,0xe3,0x30,0x00,0x00,0x0a,0x2f,0x00,0x00,0x3a, -0x80,0x00,0x52,0xe3,0x2d,0x00,0x00,0x0a,0x81,0x00,0x52,0xe3,0x32,0x01,0x00,0x0a, -0x04,0x20,0x90,0xe5,0x03,0x90,0xa0,0xe1,0x05,0x00,0x94,0xe7,0x20,0x32,0x92,0xe5, -0x01,0x30,0x83,0xe3,0x20,0x32,0x82,0xe5,0xda,0xfe,0xff,0xea,0x21,0x2e,0x82,0xe2, -0x03,0x90,0xa0,0xe3,0x11,0xfe,0xff,0xea,0x03,0x90,0xa0,0xe3,0x0f,0xfe,0xff,0xea, -0x80,0x00,0x53,0xe3,0x2b,0x00,0x00,0x0a,0x81,0x00,0x53,0xe3,0x0f,0x01,0x00,0x0a, -0x04,0x30,0x90,0xe5,0x00,0x90,0xa0,0xe3,0x05,0x00,0x94,0xe7,0x20,0x22,0x93,0xe5, -0x01,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0x01,0x30,0xa0,0xe3,0x38,0x30,0xcd,0xe5, -0xc8,0xfe,0xff,0xea,0x12,0x10,0x80,0xe2,0x08,0x70,0xa0,0xe1,0x56,0xff,0xff,0xea, -0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5, -0xe0,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2,0xbd,0xfe,0xff,0x1a,0x00,0x00,0x97,0xe5, -0x04,0x30,0x90,0xe5,0x0a,0x10,0xd0,0xe5,0x05,0x00,0x94,0xe7,0x44,0x21,0x93,0xe5, -0xfe,0x24,0xc2,0xe3,0x81,0x2c,0x82,0xe1,0x44,0x21,0x83,0xe5,0xb5,0xfe,0xff,0xea, -0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x20,0xc2,0xe3,0x20,0x22,0x83,0xe5, -0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x40,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5, -0x93,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3, -0x20,0x22,0x83,0xe5,0x8e,0xff,0xff,0xea,0x04,0x30,0x90,0xe5,0x1c,0x22,0x93,0xe5, -0x01,0x08,0x12,0xe3,0xa2,0x00,0x00,0x1a,0x02,0x05,0x12,0xe3,0x0b,0x00,0x00,0x0a, -0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5,0x40,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5, -0x68,0x00,0x11,0xe3,0x05,0x00,0x00,0x1a,0x0c,0x12,0x93,0xe5,0x01,0x08,0x11,0xe3, -0x02,0x00,0x00,0x1a,0x14,0x32,0x93,0xe5,0x01,0x08,0x13,0xe3,0x88,0x30,0x92,0x05, -0x08,0x70,0xa0,0xe1,0x38,0x10,0x8d,0xe2,0x23,0xff,0xff,0xea,0x00,0x00,0x5a,0xe3, -0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2, -0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a, -0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5, -0x0c,0x00,0x9d,0xe5,0x34,0x20,0x9d,0xe5,0x05,0x30,0x94,0xe7,0x0e,0x20,0xc0,0xe5, -0x30,0x20,0x9d,0xe5,0x0f,0x20,0xc0,0xe5,0x2c,0x20,0x9d,0xe5,0x10,0x20,0xc0,0xe5, -0x00,0x30,0x93,0xe5,0x02,0x00,0x53,0xe3,0xdc,0x00,0x00,0x0a,0x0c,0x10,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe3,0x20,0x70,0xa0,0xe3,0x16,0x20,0xc1,0xe5, -0x17,0x30,0xc1,0xe5,0x1d,0x20,0xc1,0xe5,0x1e,0x30,0xc1,0xe5,0x02,0xff,0xff,0xea, -0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2,0x30,0x10,0x8d,0xe2, -0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3, -0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x30,0x30,0x8d,0xe5, -0x2c,0x30,0x8d,0xe5,0x10,0x10,0x9d,0xe5,0x0a,0x70,0xa0,0xe3,0x34,0x30,0x9d,0xe5, -0x04,0x30,0xc1,0xe5,0x30,0x30,0x9d,0xe5,0x05,0x30,0xc1,0xe5,0x2c,0x30,0x9d,0xe5, -0x06,0x30,0xc1,0xe5,0xec,0xfe,0xff,0xea,0x0a,0x20,0xd0,0xe5,0x02,0x00,0x52,0xe3, -0xd1,0x00,0x00,0x0a,0x03,0x00,0x52,0xe3,0xc7,0x00,0x00,0x0a,0x01,0x00,0x52,0xe3, -0xbf,0x00,0x00,0x0a,0xc4,0x13,0x9f,0xe5,0x04,0x70,0xa0,0xe3,0x01,0x10,0x84,0xe0, -0xe1,0xfe,0xff,0xea,0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x34,0x00,0x8d,0xe2, -0x30,0x10,0x8d,0xe2,0x2c,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x1a,0xff,0x2f,0xe1, -0x00,0x00,0x50,0xe3,0x03,0x00,0x00,0x1a,0xff,0x30,0xa0,0xe3,0x34,0x30,0x8d,0xe5, -0x30,0x30,0x8d,0xe5,0x2c,0x30,0x8d,0xe5,0x84,0x33,0x9f,0xe5,0x34,0x10,0x9d,0xe5, -0x05,0x20,0x94,0xe7,0x03,0x30,0x84,0xe0,0x0e,0x10,0xc3,0xe5,0x30,0x10,0x9d,0xe5, -0x0f,0x10,0xc3,0xe5,0x2c,0x10,0x9d,0xe5,0x10,0x10,0xc3,0xe5,0x00,0x20,0x92,0xe5, -0x02,0x00,0x52,0xe3,0x91,0x00,0x00,0x0a,0x40,0x00,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x16,0x00,0xc3,0xe5,0x20,0x70,0xa0,0xe3,0x17,0x20,0xc3,0xe5,0x03,0x10,0xa0,0xe1, -0x1d,0x00,0xc3,0xe5,0x1e,0x20,0xc3,0xe5,0xbf,0xfe,0xff,0xea,0xe9,0x30,0x00,0xeb, -0x00,0x30,0x50,0xe2,0x06,0x00,0x00,0x0a,0x24,0x00,0x8d,0xe2,0x28,0x10,0x8d,0xe2, -0x20,0x20,0x8d,0xe2,0x0f,0xe0,0xa0,0xe1,0x13,0xff,0x2f,0xe1,0x00,0x00,0x50,0xe3, -0x12,0x00,0x00,0x1a,0x07,0x32,0xa0,0xe3,0x1c,0x00,0x8d,0xe2,0x04,0x78,0x93,0xe5, -0x02,0x31,0x00,0xeb,0xfc,0x12,0x9f,0xe5,0x27,0x34,0xa0,0xe1,0x07,0x0e,0xa0,0xe1, -0x24,0x10,0x8d,0xe5,0x07,0x22,0xa0,0xe1,0x1c,0x10,0x9d,0xe5,0xff,0x30,0x03,0xe2, -0x07,0x76,0xa0,0xe1,0x20,0x38,0x83,0xe1,0x0f,0x10,0x01,0xe2,0x0f,0x2c,0x02,0xe2, -0x27,0x2e,0x82,0xe1,0x01,0x34,0x83,0xe1,0x20,0x20,0x8d,0xe5,0x28,0x30,0x8d,0xe5, -0x24,0x10,0x9d,0xe5,0x12,0x70,0xa0,0xe3,0x28,0x00,0x9d,0xe5,0x20,0x20,0x9d,0xe5, -0xb4,0x32,0x9f,0xe5,0x21,0xa4,0xa0,0xe1,0x20,0xe4,0xa0,0xe1,0x22,0xc4,0xa0,0xe1, -0x03,0x30,0x84,0xe0,0x08,0x10,0xc3,0xe5,0x03,0x10,0xa0,0xe1,0x09,0xa0,0xc3,0xe5, -0x0a,0x00,0xc3,0xe5,0x0b,0xe0,0xc3,0xe5,0x0c,0x20,0xc3,0xe5,0x0d,0xc0,0xc3,0xe5, -0x91,0xfe,0xff,0xea,0x40,0x10,0x8d,0xe2,0x01,0x30,0xa0,0xe3,0x08,0x30,0x61,0xe5, -0x08,0x70,0xa0,0xe1,0x8c,0xfe,0xff,0xea,0x01,0xc0,0xa0,0xe3,0x02,0x30,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0x00,0xc0,0x8d,0xe5,0x16,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2, -0xf3,0xfd,0xff,0x1a,0x00,0x30,0x97,0xe5,0x0d,0x60,0xd3,0xe5,0x0f,0x60,0x06,0xe2, -0x04,0x00,0x56,0xe3,0x76,0x00,0x00,0x0a,0x05,0x30,0x94,0xe7,0x04,0x30,0x93,0xe5, -0x74,0x21,0x93,0xe5,0x0f,0x28,0xc2,0xe3,0x06,0x68,0x82,0xe1,0x74,0x61,0x83,0xe5, -0xfe,0xff,0xff,0xea,0x01,0x80,0xa0,0xe3,0x02,0x30,0xa0,0xe1,0x08,0x10,0xa0,0xe1, -0x00,0x80,0x8d,0xe5,0x03,0xfb,0xff,0xeb,0x00,0x90,0x50,0xe2,0xe0,0xfd,0xff,0x1a, -0x00,0x30,0x97,0xe5,0x02,0x10,0xa0,0xe3,0x0a,0x20,0xd3,0xe5,0x03,0x00,0xa0,0xe1, -0x12,0x20,0xc3,0xe5,0x88,0xfa,0xff,0xeb,0x00,0x00,0x97,0xe5,0x03,0x10,0xa0,0xe3, -0x85,0xfa,0xff,0xeb,0x00,0x00,0x97,0xe5,0x10,0x80,0xc0,0xe5,0x05,0x00,0x94,0xe7, -0xd4,0xfd,0xff,0xea,0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x00,0x12,0xe3, -0xcf,0xff,0xff,0x1a,0x80,0x00,0x12,0xe3,0x38,0xff,0xff,0x0a,0x00,0x20,0x96,0xe5, -0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3, -0x32,0xff,0xff,0x1a,0x0c,0x12,0x93,0xe5,0x02,0x00,0x11,0xe3,0x2f,0xff,0xff,0x1a, -0x14,0x32,0x93,0xe5,0x02,0x00,0x13,0xe3,0x8c,0x30,0x92,0x05,0x2b,0xff,0xff,0xea, -0x04,0x30,0x90,0xe5,0x20,0x22,0x93,0xe5,0x01,0x08,0x12,0xe3,0xbc,0xff,0xff,0x1a, -0x02,0x05,0x12,0xe3,0x25,0xff,0xff,0x0a,0x00,0x20,0x96,0xe5,0x80,0x10,0x92,0xe5, -0xc0,0x10,0x81,0xe2,0x0c,0x10,0x91,0xe5,0x68,0x00,0x11,0xe3,0x1f,0xff,0xff,0x1a, -0x0c,0x12,0x93,0xe5,0x02,0x08,0x11,0xe3,0x1c,0xff,0xff,0x1a,0x14,0x32,0x93,0xe5, -0x02,0x08,0x13,0xe3,0x90,0x30,0x92,0x05,0x18,0xff,0xff,0xea,0x04,0x30,0x90,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x28,0xc2,0xe3,0x20,0x22,0x83,0xe5,0x04,0x30,0x90,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x25,0x82,0xe3,0x20,0x22,0x83,0xe5,0x8c,0xfe,0xff,0xea, -0x00,0x10,0xa0,0xe3,0x17,0x20,0xc3,0xe5,0x16,0x10,0xc3,0xe5,0x20,0x70,0xa0,0xe3, -0x1d,0x10,0xc3,0xe5,0x03,0x10,0xa0,0xe1,0x1e,0x20,0xc3,0xe5,0x2e,0xfe,0xff,0xea, -0x40,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x16,0x20,0xc0,0xe5,0x20,0x70,0xa0,0xe3, -0x17,0x30,0xc0,0xe5,0x00,0x10,0xa0,0xe1,0x1d,0x20,0xc0,0xe5,0x1e,0x30,0xc0,0xe5, -0x25,0xfe,0xff,0xea,0xd4,0x10,0x9f,0xe5,0x01,0x70,0xd4,0xe7,0x01,0x10,0x84,0xe0, -0x1a,0x00,0x57,0xe3,0x1a,0x70,0xa0,0x23,0x1f,0xfe,0xff,0xea,0x00,0x00,0x53,0xe3, -0x0f,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1,0x13,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2, -0x0b,0x00,0x00,0x0a,0x00,0x70,0xd1,0xe5,0x17,0xfe,0xff,0xea,0x00,0x00,0x59,0xe3, -0x03,0x00,0x00,0x0a,0x0f,0xe0,0xa0,0xe1,0x19,0xff,0x2f,0xe1,0x00,0x10,0x50,0xe2, -0xf7,0xff,0xff,0x1a,0x88,0x10,0x9f,0xe5,0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5, -0x0d,0xfe,0xff,0xea,0x7c,0x10,0x9f,0xe5,0x01,0x10,0x84,0xe0,0x00,0x70,0xd1,0xe5, -0x09,0xfe,0xff,0xea,0x70,0x70,0x9f,0xe5,0x35,0x20,0xa0,0xe3,0x6c,0x10,0x9f,0xe5, -0x07,0x70,0x84,0xe0,0x10,0x00,0x97,0xe5,0x01,0x10,0x84,0xe0,0x3f,0x26,0x00,0xeb, -0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x35,0x30,0x83,0xe2, -0x05,0x00,0x94,0xe7,0x10,0x20,0x97,0xe5,0x8a,0xfa,0xff,0xeb,0x79,0xff,0xff,0xea, -0x18,0x01,0x01,0x00,0x48,0x03,0x00,0x00,0xb0,0x10,0x00,0x00,0x98,0x10,0x00,0x00, -0x1c,0x03,0x00,0x00,0x3c,0x03,0x00,0x00,0xa0,0x86,0x01,0x00,0x81,0x00,0x81,0x00, -0x9c,0x03,0x00,0x00,0x7c,0x03,0x00,0x00,0x55,0x09,0x00,0x00,0x68,0x03,0x00,0x00, -0x20,0x03,0x00,0x00,0xa0,0x03,0x00,0x00,0x10,0x03,0x00,0x00,0x9c,0x10,0x00,0x00, -0x94,0xee,0xff,0xff,0x8c,0x30,0x9f,0xe5,0x01,0xc0,0xa0,0xe3,0xf0,0x07,0x2d,0xe9, -0x7d,0x64,0xa0,0xe3,0x80,0xa0,0x9f,0xe5,0x00,0x40,0xa0,0xe3,0x03,0x30,0x8f,0xe0, -0x78,0x70,0x9f,0xe5,0xb4,0x91,0x96,0xe5,0x0a,0x20,0x83,0xe0,0x70,0x80,0x9f,0xe5, -0x0a,0x70,0x83,0xe7,0x6c,0xa0,0x9f,0xe5,0x6c,0x50,0x9f,0xe5,0xa9,0x9c,0xa0,0xe1, -0x0a,0x80,0x83,0xe7,0x03,0x90,0x09,0xe2,0x60,0xa0,0x9f,0xe5,0x05,0x10,0x83,0xe0, -0x0a,0x10,0x83,0xe7,0x58,0xa0,0x9f,0xe5,0x10,0xa0,0x82,0xe5,0x54,0xa0,0x9f,0xe5, -0x80,0xa0,0x88,0xe5,0x01,0x8a,0xa0,0xe3,0x04,0x80,0x82,0xe5,0x08,0x70,0x82,0xe5, -0x0c,0x40,0x82,0xe5,0x10,0xc0,0xc1,0xe5,0x11,0xc0,0xc1,0xe5,0x04,0x60,0x81,0xe5, -0x05,0x90,0x83,0xe7,0x14,0xc0,0xc1,0xe5,0x00,0x20,0x80,0xe5,0x04,0x00,0xa0,0xe1, -0xf0,0x07,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0xc4,0xf1,0x00,0x00,0x9c,0x10,0x00,0x00, -0x00,0x70,0x00,0x40,0x00,0x80,0x00,0x40,0x98,0x10,0x00,0x00,0x80,0x10,0x00,0x00, -0xb0,0x10,0x00,0x00,0x00,0x50,0x00,0x40,0x00,0x10,0x00,0x7d,0x70,0x40,0x2d,0xe9, -0x00,0xc0,0xa0,0xe3,0x7c,0xe0,0x9f,0xe5,0x0c,0x10,0xa0,0xe1,0x14,0x20,0xa0,0xe3, -0x74,0x30,0x9f,0xe5,0x0e,0xe0,0x8f,0xe0,0x03,0x30,0x9e,0xe7,0x04,0x40,0x93,0xe5, -0x44,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5,0x08,0x52,0x94,0xe5,0x08,0x52,0x84,0xe5, -0x04,0x40,0x93,0xe5,0x18,0x52,0x94,0xe5,0x18,0x52,0x84,0xe5,0x04,0x40,0x93,0xe5, -0x30,0x51,0x94,0xe5,0x01,0x50,0xc5,0xe3,0x30,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5, -0xf8,0x51,0x94,0xe5,0x03,0x50,0xc5,0xe3,0xf8,0x51,0x84,0xe5,0x04,0x40,0x93,0xe5, -0x38,0xc1,0x84,0xe5,0x04,0x40,0x93,0xe5,0xf4,0xc1,0x84,0xe5,0x1c,0x40,0x9f,0xe5, -0x14,0xc0,0xc3,0xe5,0x04,0xc0,0x8e,0xe7,0xda,0x25,0x00,0xeb,0xc8,0x00,0xa0,0xe3, -0x70,0x40,0xbd,0xe8,0x44,0x2d,0x00,0xea,0x0c,0xf1,0x00,0x00,0xb0,0x10,0x00,0x00, -0x98,0x10,0x00,0x00,0x7d,0x34,0xa0,0xe3,0xf0,0x4f,0x2d,0xe9,0x08,0x34,0x93,0xe5, -0x34,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1,0xcc,0x93,0x9f,0xe5,0x10,0x20,0x8d,0xe5, -0x23,0x35,0xa0,0xe1,0x58,0x80,0x9d,0xe5,0x09,0x90,0x8f,0xe0,0x01,0x30,0x13,0xe2, -0x05,0x00,0x00,0x1a,0xb4,0x23,0x9f,0xe5,0xb4,0x03,0x9f,0xe5,0x02,0x20,0x99,0xe7, -0x10,0x30,0xc2,0xe5,0x34,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x10,0x00,0x90,0xe5, -0x08,0x10,0x8d,0xe5,0xc1,0xfb,0xff,0xeb,0x10,0x20,0x9d,0xe5,0x08,0x10,0x9d,0xe5, -0x00,0x00,0x52,0xe3,0x10,0x00,0x9d,0x05,0xf5,0xff,0xff,0x0a,0x7c,0x33,0x9f,0xe5, -0x00,0x20,0xa0,0xe3,0x14,0x10,0x8d,0xe5,0x00,0x10,0xa0,0xe3,0x74,0x53,0x9f,0xe5, -0x00,0x60,0xa0,0xe3,0x03,0x40,0x89,0xe0,0x20,0x30,0x8d,0xe5,0x18,0x10,0x8d,0xe5, -0x1c,0x20,0x8d,0xe5,0xfa,0x3f,0xa0,0xe3,0x98,0x13,0x82,0xe0,0x28,0x10,0x8d,0xe5, -0x2c,0x20,0x8d,0xe5,0x14,0x10,0x9d,0xe5,0x05,0x50,0x89,0xe0,0x24,0x90,0x8d,0xe5, -0x08,0x90,0xa0,0xe1,0x10,0x20,0x9d,0xe5,0x01,0x01,0x97,0xe8,0x08,0x00,0x52,0xe1, -0x02,0x80,0xa0,0x31,0x08,0x20,0xa0,0xe1,0xa0,0x25,0x00,0xeb,0x00,0x00,0x94,0xe5, -0x01,0x0a,0x58,0xe3,0x08,0x30,0xa0,0x31,0x01,0x3a,0xa0,0x23,0x00,0x20,0x97,0xe5, -0x03,0x10,0xa0,0xe3,0x00,0x60,0x8d,0xe5,0xea,0xf9,0xff,0xeb,0x01,0x00,0x79,0xe3, -0x06,0x00,0x00,0x0a,0xb5,0x25,0x00,0xeb,0x28,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8, -0x00,0x20,0x92,0xe0,0x01,0x30,0xa3,0xe0,0x18,0x20,0x8d,0xe5,0x1c,0x30,0x8d,0xe5, -0x7d,0x84,0xa0,0xe3,0x02,0xa8,0xa0,0xe3,0x08,0x34,0x98,0xe5,0x01,0x0b,0x13,0xe3, -0x66,0x00,0x00,0x1a,0x00,0x30,0x94,0xe5,0x11,0x20,0xd3,0xe5,0x00,0x00,0x52,0xe3, -0x44,0x00,0x00,0x0a,0x04,0x20,0x93,0xe5,0xbc,0xb2,0x9f,0xe5,0x10,0xa2,0x82,0xe5, -0x04,0x30,0x93,0xe5,0x10,0x32,0x93,0xe5,0x0c,0x50,0x8d,0xe5,0x04,0x50,0xa0,0xe1, -0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2, -0x04,0x30,0x93,0xe5,0x10,0x42,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xa7,0x25,0x00,0xeb,0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5, -0x74,0xb2,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x14,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5, -0x14,0x42,0x93,0xe5,0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x98,0x25,0x00,0xeb, -0x02,0x08,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x38,0xb2,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0x0c,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x42,0x93,0xe5, -0x03,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x89,0x25,0x00,0xeb,0x02,0x08,0x14,0xe3, -0xf6,0xff,0xff,0x1a,0x05,0x40,0xa0,0xe1,0x0c,0x50,0x9d,0xe5,0x00,0x10,0xa0,0xe3, -0x20,0x20,0xa0,0xe3,0x00,0x00,0x95,0xe5,0x60,0x00,0x80,0xe2,0x51,0x25,0x00,0xeb, -0x00,0x30,0x95,0xe5,0x30,0x20,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x80,0x00,0x93,0xe5, -0xc0,0x00,0x80,0xe2,0x4b,0x25,0x00,0xeb,0x00,0x30,0x94,0xe5,0x00,0x20,0x95,0xe5, -0x04,0x30,0x93,0xe5,0x90,0x60,0x82,0xe5,0xa0,0x60,0x82,0xe5,0x18,0x22,0x93,0xe5, -0x02,0x28,0x82,0xe3,0x18,0x22,0x83,0xe5,0x02,0xb0,0xa0,0xe3,0x10,0x00,0x97,0xe5, -0x42,0xfb,0xff,0xeb,0x01,0x00,0x79,0xe3,0x05,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x6b,0x25,0x00,0xeb,0x59,0x25,0x00,0xeb,0x1c,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe1, -0x53,0x00,0x00,0x9a,0x01,0x00,0x5b,0xe3,0x04,0x00,0x5b,0x13,0xa5,0xff,0xff,0x0a, -0x7d,0x34,0xa0,0xe3,0x24,0x90,0x9d,0xe5,0x08,0x34,0x93,0xe5,0x20,0x10,0x9d,0xe5, -0x23,0x35,0xa0,0xe1,0x01,0x20,0x99,0xe7,0x01,0x30,0x13,0xe2,0x10,0x30,0xc2,0x05, -0x4c,0x01,0x9f,0x05,0x66,0xff,0xff,0x0a,0x04,0x30,0x92,0xe5,0x4c,0x01,0x9f,0xe5, -0x20,0x22,0x93,0xe5,0x01,0x20,0x82,0xe3,0x20,0x22,0x83,0xe5,0x60,0xff,0xff,0xea, -0x00,0x30,0x94,0xe5,0x04,0x30,0x93,0xe5,0x20,0x22,0x93,0xe5,0x22,0x0e,0x83,0xe2, -0x01,0x08,0x12,0xe3,0x15,0x00,0x00,0x1a,0x02,0x05,0x12,0xe3,0x17,0x00,0x00,0x0a, -0x00,0x10,0x95,0xe5,0x80,0x20,0x91,0xe5,0xc0,0x20,0x82,0xe2,0x0c,0xc0,0x92,0xe5, -0x68,0x00,0x1c,0xe3,0xd3,0xff,0xff,0x1a,0x0c,0xc2,0x93,0xe5,0x83,0xbf,0x83,0xe2, -0x02,0x08,0x1c,0xe3,0x0b,0x00,0x00,0x1a,0x14,0xc2,0x93,0xe5,0x85,0x3f,0x83,0xe2, -0x0c,0x30,0x8d,0xe5,0x02,0xc8,0x1c,0xe2,0x06,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5, -0x00,0x00,0x53,0xe3,0x07,0x00,0x00,0x1a,0x03,0xb0,0xa0,0xe3,0xc6,0xff,0xff,0xea, -0x04,0xb0,0xa0,0xe3,0xc4,0xff,0xff,0xea,0x01,0xb0,0xa0,0xe3,0xc2,0xff,0xff,0xea, -0x05,0xb0,0xa0,0xe3,0xc0,0xff,0xff,0xea,0x00,0x30,0x90,0xe5,0x01,0x08,0x13,0xe3, -0x23,0x00,0x00,0x1a,0x02,0x35,0x13,0xe2,0x0e,0x00,0x00,0x0a,0x0c,0x30,0x92,0xe5, -0x68,0x00,0x13,0xe3,0x14,0x00,0x00,0x1a,0x00,0x30,0x9b,0xe5,0x02,0x38,0x13,0xe2, -0x11,0x00,0x00,0x1a,0x0c,0xc0,0x9d,0xe5,0x00,0x00,0x9c,0xe5,0x02,0x08,0x10,0xe3, -0x04,0x00,0x00,0x1a,0x90,0x30,0x91,0xe5,0x00,0x00,0x53,0xe3,0xa0,0x30,0x91,0x15, -0x0c,0x20,0x92,0x15,0x22,0x38,0x43,0x10,0x10,0x10,0x9d,0xe5,0x03,0x10,0x51,0xe0, -0x10,0x10,0x8d,0xe5,0x0c,0x00,0x00,0x0a,0x14,0x20,0x9d,0xe5,0x03,0x20,0x82,0xe0, -0x14,0x20,0x8d,0xe5,0x02,0x10,0xa0,0xe1,0x3d,0xff,0xff,0xea,0x00,0x30,0xa0,0xe3, -0xf4,0xff,0xff,0xea,0x02,0x00,0x00,0x1a,0x18,0xc0,0x9d,0xe5,0x00,0x00,0x5c,0xe1, -0xa7,0xff,0xff,0x8a,0x05,0x00,0xa0,0xe3,0x19,0xff,0xff,0xea,0x01,0x00,0xa0,0xe1, -0x17,0xff,0xff,0xea,0x0c,0x30,0xa0,0xe1,0xea,0xff,0xff,0xea,0x68,0xf0,0x00,0x00, -0xb0,0x10,0x00,0x00,0x05,0x30,0x04,0x00,0x98,0x10,0x00,0x00,0xa0,0x86,0x01,0x00, -0x04,0x30,0x04,0x00,0x7d,0xc4,0xa0,0xe3,0xf0,0x4f,0x2d,0xe9,0x08,0xc4,0x9c,0xe5, -0x3c,0xd0,0x4d,0xe2,0x00,0x70,0xa0,0xe1,0x01,0x40,0xa0,0xe1,0xec,0x94,0x9f,0xe5, -0x0c,0x20,0x8d,0xe5,0x2c,0xc5,0xa0,0xe1,0x18,0x30,0x8d,0xe5,0x09,0x90,0x8f,0xe0, -0x01,0xc0,0x1c,0xe2,0x05,0x00,0x00,0x1a,0xd4,0x34,0x9f,0xe5,0xd4,0x04,0x9f,0xe5, -0x03,0x30,0x99,0xe7,0x10,0xc0,0xc3,0xe5,0x3c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x10,0x00,0x90,0xe5,0xc1,0xfa,0xff,0xeb,0x18,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3, -0x00,0x30,0xa0,0x13,0x00,0x30,0x80,0x15,0x0c,0x50,0x97,0xe5,0x00,0x00,0x55,0xe3, -0x28,0x40,0x8d,0x05,0xfb,0x00,0x00,0x1a,0x94,0x24,0x9f,0xe5,0x02,0x80,0x99,0xe7, -0x2c,0x20,0x8d,0xe5,0x00,0x30,0x98,0xe5,0x02,0x00,0x53,0xe3,0x40,0x30,0xa0,0x13, -0x02,0x3c,0xa0,0x03,0x30,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x18,0x01,0x00,0x0a,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x10,0x00,0x8d,0xe5, -0x14,0x10,0x8d,0xe5,0x02,0x40,0x89,0xe0,0x64,0x00,0x9d,0xe5,0xfa,0x3f,0xa0,0xe3, -0x54,0x54,0x9f,0xe5,0x90,0x13,0x82,0xe0,0x04,0xa0,0x97,0xe5,0x34,0x90,0x8d,0xe5, -0x05,0x50,0x89,0xe0,0x00,0x90,0xa0,0xe1,0x20,0x10,0x8d,0xe5,0x24,0x20,0x8d,0xe5, -0x0c,0x10,0x9d,0xe5,0x0a,0x00,0x51,0xe1,0x05,0x00,0x00,0x8a,0x01,0x00,0xa0,0xe1, -0x30,0x10,0x9d,0xe5,0x6b,0x2e,0x00,0xeb,0x0c,0x20,0x9d,0xe5,0x00,0x00,0x51,0xe3, -0x02,0xa0,0xa0,0x01,0x01,0x0a,0x5a,0xe3,0x01,0xaa,0xa0,0x23,0x00,0x60,0xa0,0xe3, -0x1c,0xa0,0x8d,0xe5,0x08,0x00,0xa0,0xe1,0x07,0xa0,0xa0,0xe1,0x00,0x20,0x9a,0xe5, -0x02,0x10,0xa0,0xe3,0x1c,0x30,0x9d,0xe5,0x00,0x60,0x8d,0xe5,0xd9,0xf8,0xff,0xeb, -0x01,0x00,0x79,0xe3,0x08,0x00,0x00,0x0a,0xa4,0x24,0x00,0xeb,0x00,0x00,0x59,0xe3, -0xec,0x00,0x00,0x0a,0x20,0x30,0x8d,0xe2,0x0c,0x00,0x93,0xe8,0x00,0x20,0x92,0xe0, -0x01,0x30,0xa3,0xe0,0x10,0x20,0x8d,0xe5,0x14,0x30,0x8d,0xe5,0x7d,0x74,0xa0,0xe3, -0x02,0x80,0xa0,0xe3,0x08,0x34,0x97,0xe5,0x01,0x0b,0x13,0xe3,0x5a,0x00,0x00,0x1a, -0x00,0x30,0x94,0xe5,0x11,0x20,0xd3,0xe5,0x00,0x00,0x52,0xe3,0x44,0x00,0x00,0x0a, -0x04,0x20,0x93,0xe5,0x94,0xb3,0x9f,0xe5,0x10,0x82,0x82,0xe5,0x04,0x30,0x93,0xe5, -0x10,0x32,0x93,0xe5,0x08,0x50,0x8d,0xe5,0x04,0x50,0xa0,0xe1,0x03,0x40,0xa0,0xe1, -0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5, -0x10,0x42,0x93,0xe5,0x21,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x94,0x24,0x00,0xeb, -0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x4c,0xb3,0x9f,0xe5, -0x04,0x30,0x93,0xe5,0x14,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea, -0x00,0x30,0x95,0xe5,0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x14,0x42,0x93,0xe5, -0x12,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x85,0x24,0x00,0xeb,0x02,0x00,0x14,0xe3, -0xf6,0xff,0xff,0x1a,0x00,0x30,0x95,0xe5,0x10,0xb3,0x9f,0xe5,0x04,0x30,0x93,0xe5, -0x0c,0x32,0x93,0xe5,0x03,0x40,0xa0,0xe1,0x04,0x00,0x00,0xea,0x00,0x30,0x95,0xe5, -0x01,0xb0,0x5b,0xe2,0x04,0x30,0x93,0xe5,0x0c,0x42,0x93,0xe5,0x03,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x76,0x24,0x00,0xeb,0x02,0x00,0x14,0xe3,0xf6,0xff,0xff,0x1a, -0x05,0x40,0xa0,0xe1,0x08,0x50,0x9d,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x20,0xa0,0xe3, -0x00,0x00,0x95,0xe5,0x40,0x00,0x80,0xe2,0x3e,0x24,0x00,0xeb,0x00,0x30,0x95,0xe5, -0x30,0x20,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x80,0x00,0x93,0xe5,0x80,0x00,0x80,0xe2, -0x38,0x24,0x00,0xeb,0x00,0x30,0x94,0xe5,0x00,0x20,0x95,0xe5,0x04,0x30,0x93,0xe5, -0x8c,0x60,0x82,0xe5,0x9c,0x60,0x82,0xe5,0x18,0x22,0x93,0xe5,0x02,0x20,0x82,0xe3, -0x18,0x22,0x83,0xe5,0x02,0xb0,0xa0,0xe3,0x10,0x00,0x9a,0xe5,0x2f,0xfa,0xff,0xeb, -0x23,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a,0x01,0x00,0x79,0xe3,0x05,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x56,0x24,0x00,0xeb,0x44,0x24,0x00,0xeb,0x14,0x20,0x9d,0xe5, -0x01,0x00,0x52,0xe1,0x85,0x00,0x00,0x9a,0x01,0x00,0x5b,0xe3,0x04,0x00,0x5b,0x13, -0xa3,0xff,0xff,0x0a,0x00,0x00,0x94,0xe5,0x8f,0xff,0xff,0xea,0x00,0x30,0x94,0xe5, -0x04,0xc0,0x93,0xe5,0x20,0x22,0x9c,0xe5,0x22,0x3e,0x8c,0xe2,0x01,0x00,0x12,0xe3, -0x14,0x00,0x00,0x1a,0x80,0x00,0x12,0xe3,0x16,0x00,0x00,0x0a,0x00,0x20,0x95,0xe5, -0x80,0x10,0x92,0xe5,0x80,0x10,0x81,0xe2,0x0c,0x00,0x91,0xe5,0x68,0x00,0x10,0xe3, -0xdf,0xff,0xff,0x1a,0x0c,0xe2,0x9c,0xe5,0x83,0x0f,0x8c,0xe2,0x02,0x00,0x1e,0xe3, -0x0a,0x00,0x00,0x1a,0x14,0xb2,0x9c,0xe5,0x85,0xef,0x8c,0xe2,0x02,0xb0,0x1b,0xe2, -0x06,0x00,0x00,0x1a,0x8c,0xc0,0x92,0xe5,0x00,0x00,0x5c,0xe3,0x07,0x00,0x00,0x1a, -0x03,0xb0,0xa0,0xe3,0xd3,0xff,0xff,0xea,0x04,0xb0,0xa0,0xe3,0xd1,0xff,0xff,0xea, -0x01,0xb0,0xa0,0xe3,0xcf,0xff,0xff,0xea,0x05,0xb0,0xa0,0xe3,0xcd,0xff,0xff,0xea, -0x00,0x30,0x93,0xe5,0x0a,0x70,0xa0,0xe1,0x01,0x00,0x13,0xe3,0x19,0x00,0x00,0x1a, -0x80,0x30,0x13,0xe2,0x39,0x00,0x00,0x0a,0x0c,0x30,0x91,0xe5,0x68,0x00,0x13,0xe3, -0x13,0x00,0x00,0x1a,0x00,0x30,0x90,0xe5,0x02,0x30,0x13,0xe2,0x10,0x00,0x00,0x1a, -0x00,0x00,0x9e,0xe5,0x02,0x00,0x10,0xe3,0x30,0x00,0x00,0x1a,0x8c,0xb0,0x92,0xe5, -0x00,0x00,0x5b,0xe3,0x0b,0x00,0x00,0x0a,0x9c,0x30,0x92,0xe5,0x0c,0xb0,0x91,0xe5, -0x0c,0x00,0x9d,0xe5,0x2b,0xb8,0x43,0xe0,0x0b,0x00,0x50,0xe1,0x05,0x00,0x00,0x2a, -0x0c,0x00,0x9d,0xe5,0x0b,0x30,0x60,0xe0,0x00,0xb0,0xa0,0xe1,0x0c,0x30,0x87,0xe5, -0x02,0x00,0x00,0xea,0x00,0xb0,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x0c,0x30,0x87,0xe5, -0x00,0x10,0x97,0xe5,0x0b,0x20,0xa0,0xe1,0x28,0x00,0x9d,0xe5,0x0b,0x30,0x81,0xe0, -0x08,0x30,0x87,0xe5,0xd5,0x23,0x00,0xeb,0x18,0x10,0x9d,0xe5,0x0c,0x20,0x9d,0xe5, -0x00,0x00,0x51,0xe3,0x00,0x30,0x91,0x15,0x0b,0x30,0x83,0x10,0x00,0x30,0x81,0x15, -0x01,0x00,0x72,0xe3,0x39,0x00,0x00,0x0a,0x04,0xa0,0x97,0xe5,0x0a,0x00,0x5b,0xe1, -0x36,0x00,0x00,0x3a,0x0b,0x20,0x52,0xe0,0x0c,0x20,0x8d,0xe5,0x35,0x00,0x00,0x0a, -0x28,0x30,0x9d,0xe5,0x00,0x80,0x94,0xe5,0x0b,0x30,0x83,0xe0,0x28,0x30,0x8d,0xe5, -0x26,0xff,0xff,0xea,0x34,0x90,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x2c,0x40,0x9d,0xe5, -0xc0,0x00,0x9f,0xe5,0x04,0x30,0x99,0xe7,0x10,0x20,0xc3,0xe5,0xf9,0xfe,0xff,0xea, -0x03,0xb0,0xa0,0xe1,0xdb,0xff,0xff,0xea,0x0c,0x10,0x9d,0xe5,0x04,0x00,0xa0,0xe1, -0x05,0x00,0x51,0xe1,0x01,0x50,0xa0,0x31,0x08,0x10,0x97,0xe5,0x05,0x20,0xa0,0xe1, -0xb2,0x23,0x00,0xeb,0x18,0x30,0x9d,0xe5,0x08,0x20,0x97,0xe5,0x00,0x00,0x53,0xe3, -0x0c,0x30,0x97,0xe5,0x18,0x00,0x9d,0x15,0x05,0x20,0x82,0xe0,0x08,0x20,0x87,0xe5, -0x03,0x30,0x65,0xe0,0x0c,0x30,0x87,0xe5,0x00,0x30,0x90,0x15,0x05,0x30,0x83,0x10, -0x00,0x30,0x80,0x15,0x0c,0x30,0x97,0x15,0x00,0x00,0x53,0xe3,0x0f,0x00,0x00,0x1a, -0x0c,0x10,0x9d,0xe5,0x05,0x40,0x84,0xe0,0x00,0x30,0x97,0xe5,0x28,0x40,0x8d,0xe5, -0x01,0x10,0x65,0xe0,0x0c,0x10,0x8d,0xe5,0x08,0x30,0x87,0xe5,0xe5,0xfe,0xff,0xea, -0x02,0x00,0x00,0x1a,0x10,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe1,0x75,0xff,0xff,0x8a, -0x05,0x00,0xa0,0xe3,0xd3,0xfe,0xff,0xea,0x64,0x00,0x9d,0xe5,0xd1,0xfe,0xff,0xea, -0x00,0x00,0xa0,0xe3,0xcf,0xfe,0xff,0xea,0x0c,0x00,0x9d,0xe5,0xcd,0xfe,0xff,0xea, -0x64,0xec,0x00,0x00,0xb0,0x10,0x00,0x00,0x05,0x30,0x04,0x00,0x98,0x10,0x00,0x00, -0xa0,0x86,0x01,0x00,0x0c,0x30,0x9f,0xe5,0xc0,0x09,0x93,0xe5,0xa0,0x01,0xa0,0xe1, -0x01,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x24,0x30,0x9f,0xe5, -0x50,0x28,0x93,0xe5,0x54,0x08,0x93,0xe5,0x58,0x18,0x93,0xe5,0x5c,0x38,0x93,0xe5, -0x02,0x20,0x80,0xe1,0x01,0x20,0x82,0xe1,0x03,0x30,0x92,0xe1,0x00,0x00,0xa0,0x03, -0x01,0x00,0xa0,0x13,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x08,0x40,0x2d,0xe9, -0xf1,0xff,0xff,0xeb,0x10,0x30,0x9f,0xe5,0x60,0x38,0x93,0xe5,0x03,0x30,0x90,0xe1, -0x00,0x00,0xa0,0x03,0x01,0x00,0xa0,0x13,0x08,0x80,0xbd,0xe8,0x00,0xf0,0x00,0x70, -0x1c,0x30,0x9f,0xe5,0x08,0xd0,0x4d,0xe2,0x48,0x39,0x93,0xe5,0x04,0x30,0x8d,0xe5, -0x04,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe2,0x01,0x00,0xa0,0x13,0x08,0xd0,0x8d,0xe2, -0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x0c,0x30,0x9f,0xe5,0xa0,0x09,0x93,0xe5, -0x00,0x00,0x50,0xe2,0x01,0x00,0xa0,0x13,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70, -0x0c,0x30,0x9f,0xe5,0x00,0x09,0x93,0xe5,0x00,0x00,0x50,0xe2,0x01,0x00,0xa0,0x13, -0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x00,0x00,0x50,0xe3,0x00,0x00,0x52,0x13, -0x00,0x30,0xa0,0x13,0x01,0x30,0xa0,0x03,0x04,0x00,0xa0,0x03,0x1e,0xff,0x2f,0x01, -0x03,0xc0,0xa0,0xe1,0x03,0x00,0x13,0xe3,0x04,0xc0,0x90,0x04,0x03,0xc0,0xc1,0xe7, -0x01,0x30,0x83,0xe2,0x03,0x00,0x52,0xe1,0x2c,0xc4,0xa0,0xe1,0xf8,0xff,0xff,0x8a, -0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x08,0x30,0x9f,0xe5,0xbc,0x09,0x93,0xe5, -0x3f,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x14,0x30,0x9f,0xe5, -0x01,0x00,0x00,0xe2,0x48,0x20,0x93,0xe5,0x01,0x22,0xc2,0xe3,0x00,0x0e,0x82,0xe1, -0x48,0x00,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x60,0x00,0x60,0x00,0x00,0x51,0xe3, -0x00,0x00,0x52,0x13,0xf0,0x40,0x2d,0xe9,0x09,0x30,0xa0,0x03,0x14,0xd0,0x4d,0xe2, -0x01,0x40,0xa0,0xe1,0x00,0x50,0xa0,0xe1,0x26,0x00,0x00,0x0a,0x00,0x00,0x50,0xe3, -0x0b,0x30,0xa0,0x03,0x23,0x00,0x00,0x0a,0x07,0x32,0xa0,0xe3,0x01,0x60,0x40,0xe2, -0x04,0x78,0x93,0xe5,0x27,0x74,0xa0,0xe1,0xff,0x70,0x07,0xe2,0x10,0x00,0x56,0xe3, -0x06,0xf1,0x8f,0x90,0x37,0x00,0x00,0xea,0x1d,0x00,0x00,0xea,0x32,0x00,0x00,0xea, -0x31,0x00,0x00,0xea,0x30,0x00,0x00,0xea,0x19,0x00,0x00,0xea,0x31,0x00,0x00,0xea, -0x17,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x2a,0x00,0x00,0xea, -0x13,0x00,0x00,0xea,0x2b,0x00,0x00,0xea,0x11,0x00,0x00,0xea,0x29,0x00,0x00,0xea, -0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea,0x0d,0x00,0x00,0xea,0x20,0x00,0x57,0xe3, -0x71,0x00,0x00,0x0a,0x30,0x00,0x57,0xe3,0x75,0x00,0x00,0x0a,0x35,0x00,0x57,0xe3, -0x26,0x00,0x00,0x1a,0x05,0x00,0xa0,0xe1,0x04,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2, -0x62,0x02,0x00,0xeb,0x00,0x30,0xa0,0xe1,0x03,0x00,0xa0,0xe1,0x14,0xd0,0x8d,0xe2, -0xf0,0x80,0xbd,0xe8,0x04,0x10,0xa0,0xe3,0x0c,0x10,0x8d,0xe5,0x00,0x30,0x92,0xe5, -0x00,0x00,0x53,0xe3,0x00,0x10,0x82,0x05,0xf6,0xff,0xff,0x0a,0x01,0x00,0x53,0xe1, -0x06,0x30,0xa0,0x33,0xf3,0xff,0xff,0x3a,0x09,0x00,0x56,0xe3,0x06,0xf1,0x8f,0x90, -0xe5,0xff,0xff,0xea,0x3a,0x00,0x00,0xea,0x32,0x00,0x00,0xea,0x2d,0x00,0x00,0xea, -0x28,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0xdf,0xff,0xff,0xea,0x1b,0x00,0x00,0xea, -0xdd,0xff,0xff,0xea,0x12,0x00,0x00,0xea,0x0a,0x00,0x00,0xea,0x01,0x10,0xa0,0xe3, -0x0c,0x10,0x8d,0xe5,0xe8,0xff,0xff,0xea,0x20,0x00,0x57,0xe3,0x3e,0x00,0x00,0x0a, -0x30,0x00,0x57,0xe3,0x42,0x00,0x00,0x0a,0x35,0x00,0x57,0xe3,0x31,0x00,0x00,0x0a, -0x02,0x30,0xa0,0xe3,0xdb,0xff,0xff,0xea,0x3c,0x21,0x9f,0xe5,0x00,0x30,0xa0,0xe3, -0xc0,0x29,0x92,0xe5,0xa2,0x21,0xa0,0xe1,0x01,0x20,0x02,0xe2,0x00,0x20,0x84,0xe5, -0xd4,0xff,0xff,0xea,0x20,0x21,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0xc0,0x29,0x92,0xe5, -0x22,0x22,0xa0,0xe1,0x0f,0x20,0x02,0xe2,0x00,0x20,0x84,0xe5,0xcd,0xff,0xff,0xea, -0x04,0x21,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0x10,0x29,0x92,0xe5,0xff,0x20,0x02,0xe2, -0x00,0x20,0x84,0xe5,0xc7,0xff,0xff,0xea,0x8a,0xff,0xff,0xeb,0x00,0x30,0xa0,0xe3, -0x00,0x00,0x84,0xe5,0xc3,0xff,0xff,0xea,0x6a,0xff,0xff,0xeb,0x00,0x30,0xa0,0xe3, -0x00,0x00,0xc4,0xe5,0xbf,0xff,0xff,0xea,0x53,0xff,0xff,0xeb,0x00,0x30,0xa0,0xe3, -0x00,0x00,0xc4,0xe5,0xbb,0xff,0xff,0xea,0xbc,0x20,0x9f,0xe5,0x00,0x30,0xa0,0xe3, -0xb8,0x29,0x92,0xe5,0x03,0x20,0x52,0xe0,0x01,0x20,0xa0,0x13,0x00,0x20,0xc4,0xe5, -0xb4,0xff,0xff,0xea,0xa0,0x20,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0xb4,0x19,0x92,0xe5, -0x61,0x28,0x21,0xe0,0x22,0x24,0xa0,0xe1,0xff,0x2c,0xc2,0xe3,0x61,0x24,0x22,0xe0, -0x00,0x20,0x84,0xe5,0xab,0xff,0xff,0xea,0x0c,0x10,0x8d,0xe2,0x04,0x20,0x8d,0xe5, -0x09,0x03,0x00,0xeb,0x04,0x20,0x9d,0xe5,0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3, -0xa4,0xff,0xff,0x1a,0x0c,0x10,0x9d,0xe5,0xa7,0xff,0xff,0xea,0x0c,0x10,0x8d,0xe2, -0x04,0x20,0x8d,0xe5,0xda,0x00,0x00,0xeb,0x04,0x20,0x9d,0xe5,0x00,0x30,0xa0,0xe1, -0xf5,0xff,0xff,0xea,0x0c,0x10,0x8d,0xe2,0x04,0x20,0x8d,0xe5,0xe6,0x01,0x00,0xeb, -0x04,0x20,0x9d,0xe5,0x00,0x30,0xa0,0xe1,0xef,0xff,0xff,0xea,0x05,0x00,0xa0,0xe1, -0x04,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2,0x08,0x00,0x00,0xeb,0x00,0x30,0xa0,0xe1, -0x90,0xff,0xff,0xea,0x05,0x00,0xa0,0xe1,0x04,0x10,0xa0,0xe1,0x0c,0x20,0x8d,0xe2, -0xdc,0x00,0x00,0xeb,0x00,0x30,0xa0,0xe1,0x8a,0xff,0xff,0xea,0x00,0xf0,0x00,0x70, -0xf0,0x40,0x2d,0xe9,0x00,0x00,0x51,0xe3,0x00,0x00,0x52,0x13,0xf0,0x42,0x9f,0xe5, -0x14,0xd0,0x4d,0xe2,0x01,0x50,0xa0,0xe1,0x09,0x00,0xa0,0x03,0x04,0x40,0x8f,0xe0, -0x31,0x00,0x00,0x0a,0x06,0x00,0x40,0xe2,0x0b,0x00,0x50,0xe3,0x00,0xf1,0x8f,0x90, -0x2f,0x00,0x00,0xea,0x84,0x00,0x00,0xea,0x2d,0x00,0x00,0xea,0x2c,0x00,0x00,0xea, -0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x68,0x00,0x00,0xea,0x7a,0x00,0x00,0xea, -0x29,0x00,0x00,0xea,0x2e,0x00,0x00,0xea,0x3b,0x00,0x00,0xea,0x52,0x00,0x00,0xea, -0xff,0xff,0xff,0xea,0x0c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3, -0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0xa8,0x27,0x00,0xeb, -0x00,0x60,0x50,0xe2,0x05,0x00,0x00,0x1a,0x0c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3, -0x08,0x60,0x90,0xe5,0xc8,0x27,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2, -0xe3,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x78,0x00,0x00,0x0a,0x54,0x32,0x9f,0xe5, -0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2,0x05,0x00,0x53,0xe3,0x38,0x00,0x00,0x8a, -0x44,0x22,0x9f,0xe5,0x02,0x40,0x84,0xe0,0x03,0x41,0x94,0xe7,0x00,0x00,0x54,0xe3, -0x33,0x00,0x00,0xba,0x17,0xff,0xff,0xeb,0x04,0x00,0x54,0xe3,0x00,0x00,0xa0,0xe3, -0x03,0x40,0xa0,0x03,0x00,0x40,0xa0,0x13,0x00,0x40,0x85,0xe5,0x14,0xd0,0x8d,0xe2, -0xf0,0x80,0xbd,0xe8,0x01,0x00,0xa0,0xe3,0xfb,0xff,0xff,0xea,0x04,0x32,0x9f,0xe5, -0x00,0x00,0xa0,0xe3,0xfc,0x39,0x93,0xe5,0x03,0x30,0x03,0xe2,0x00,0x30,0x81,0xe5, -0xf5,0xff,0xff,0xea,0x01,0x00,0xa0,0xe3,0x00,0x60,0xa0,0xe3,0x0a,0xff,0xff,0xeb, -0xe0,0x31,0x9f,0xe5,0x06,0x00,0xa0,0xe1,0x08,0x29,0x93,0xe5,0x0c,0x39,0x93,0xe5, -0x03,0x70,0xa0,0xe1,0x02,0x30,0x86,0xe1,0x07,0x40,0xa0,0xe1,0x18,0x00,0x85,0xe8, -0x01,0xff,0xff,0xeb,0x06,0x00,0xa0,0xe1,0xe7,0xff,0xff,0xea,0x0c,0xc0,0x8d,0xe2, -0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0x6e,0x27,0x00,0xeb,0x00,0x60,0x50,0xe2,0x55,0x00,0x00,0x0a, -0xaf,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x3d,0x00,0x00,0x0a,0x84,0x31,0x9f,0xe5, -0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2,0x05,0x00,0x53,0xe3,0x04,0x00,0x00,0x8a, -0x74,0x21,0x9f,0xe5,0x02,0x40,0x84,0xe0,0x03,0x31,0x94,0xe7,0x00,0x00,0x53,0xe3, -0x30,0x00,0x00,0xaa,0x08,0x00,0xa0,0xe3,0xcf,0xff,0xff,0xea,0xbb,0xfe,0xff,0xeb, -0x00,0x40,0x50,0xe2,0x02,0x30,0xa0,0x13,0x00,0x00,0xa0,0x13,0x00,0x30,0x85,0x15, -0xc9,0xff,0xff,0x1a,0xbf,0xfe,0xff,0xeb,0x00,0x60,0x50,0xe2,0x44,0x00,0x00,0x0a, -0x9d,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x05,0x30,0xa0,0x13,0x04,0x30,0xa0,0x03, -0x04,0x00,0xa0,0x11,0x00,0x30,0x85,0x15,0x00,0x30,0x85,0x05,0xbe,0xff,0xff,0xea, -0x0c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x45,0x27,0x00,0xeb,0x00,0x60,0x50,0xe2, -0x25,0x00,0x00,0x0a,0x86,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x0e,0x00,0x00,0x1a, -0x0f,0x00,0x56,0xe3,0x0c,0x00,0x00,0x0a,0xe0,0x30,0x9f,0xe5,0x00,0x60,0xa0,0x81, -0x03,0x40,0x84,0xe0,0x06,0x31,0x94,0xe7,0x0a,0x00,0x00,0xea,0x20,0x20,0xa0,0xe3, -0x72,0x0f,0xa0,0xe3,0xab,0xfe,0xff,0xeb,0xa7,0xff,0xff,0xea,0x10,0x20,0xa0,0xe3, -0x69,0x0f,0xa0,0xe3,0xa7,0xfe,0xff,0xeb,0xa3,0xff,0xff,0xea,0xa4,0x30,0x9f,0xe5, -0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2,0x00,0x30,0x85,0xe5,0x00,0x00,0xa0,0xe3, -0x9d,0xff,0xff,0xea,0x0f,0x00,0x56,0xe3,0xbf,0xff,0xff,0x0a,0x8c,0x30,0x9f,0xe5, -0x00,0x60,0xa0,0x81,0x03,0x30,0x84,0xe0,0x06,0x31,0x93,0xe7,0xbd,0xff,0xff,0xea, -0x0f,0x00,0x56,0xe3,0x84,0xff,0xff,0x0a,0x70,0x30,0x9f,0xe5,0x00,0x60,0xa0,0x81, -0x03,0x30,0x84,0xe0,0x06,0x31,0x93,0xe7,0x82,0xff,0xff,0xea,0x0c,0x00,0x9d,0xe5, -0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5,0x3f,0x27,0x00,0xeb,0x26,0x6d,0xa0,0xe1, -0x0f,0x60,0x06,0xe2,0xd2,0xff,0xff,0xea,0x0c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3, -0x08,0x60,0x90,0xe5,0x38,0x27,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2, -0xa2,0xff,0xff,0xea,0x7d,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3,0x03,0x30,0xa0,0x13, -0x01,0x30,0xa0,0x03,0x06,0x00,0xa0,0x11,0x00,0x30,0x85,0x15,0x00,0x30,0x85,0x05, -0x79,0xff,0xff,0xea,0x84,0xe3,0x00,0x00,0x00,0xf0,0x00,0x70,0xcc,0xee,0xff,0xff, -0xe4,0xee,0xff,0xff,0x00,0x00,0x51,0xe3,0x09,0x00,0xa0,0x03,0x1e,0xff,0x2f,0x01, -0x0c,0x00,0x50,0xe3,0x20,0x30,0xa0,0x03,0x00,0x00,0xa0,0x03,0x00,0x30,0x81,0x05, -0x1e,0xff,0x2f,0x01,0x0e,0x00,0x50,0xe3,0x08,0x30,0xa0,0x03,0x00,0x00,0xa0,0x03, -0x00,0x30,0x81,0x05,0x1e,0xff,0x2f,0x01,0x06,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x10,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3, -0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0xf0,0x4f,0x2d,0xe9,0x00,0x00,0x51,0xe3, -0x00,0x00,0x52,0x13,0xd0,0x53,0x9f,0xe5,0x24,0xd0,0x4d,0xe2,0x01,0x40,0xa0,0xe1, -0x09,0x00,0xa0,0x03,0x05,0x50,0x8f,0xe0,0x30,0x00,0x00,0x0a,0x06,0x00,0x40,0xe2, -0x0b,0x00,0x50,0xe3,0x00,0xf1,0x8f,0x90,0x2e,0x00,0x00,0xea,0xb2,0x00,0x00,0xea, -0x2c,0x00,0x00,0xea,0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x29,0x00,0x00,0xea, -0x96,0x00,0x00,0xea,0xa8,0x00,0x00,0xea,0x28,0x00,0x00,0xea,0x2d,0x00,0x00,0xea, -0x6b,0x00,0x00,0xea,0x80,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe2, -0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3, -0x00,0xc0,0x8d,0xe5,0xce,0x26,0x00,0xeb,0x00,0x60,0x50,0xe2,0x05,0x00,0x00,0x1a, -0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5,0xee,0x26,0x00,0xeb, -0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2,0x09,0xfe,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xa9,0x00,0x00,0x0a,0x34,0x33,0x9f,0xe5,0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2, -0x2c,0x23,0x9f,0xe5,0x02,0x50,0x85,0xe0,0x03,0x51,0x95,0xe7,0x00,0x00,0x55,0xe3, -0x63,0x00,0x00,0xba,0x3f,0xfe,0xff,0xeb,0x04,0x00,0x55,0xe3,0xbe,0x00,0x00,0x0a, -0x03,0x00,0x55,0xe3,0x00,0x50,0xa0,0x13,0x00,0x00,0xa0,0xe3,0x00,0x50,0x84,0xe5, -0x24,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x01,0x00,0xa0,0xe3,0xfb,0xff,0xff,0xea, -0xe8,0x32,0x9f,0xe5,0x00,0x00,0xa0,0xe3,0xfc,0x39,0x93,0xe5,0x0f,0x30,0x03,0xe2, -0x00,0x30,0x81,0xe5,0xf5,0xff,0xff,0xea,0x01,0x00,0xa0,0xe3,0x05,0x50,0xa0,0xe3, -0x31,0xfe,0xff,0xeb,0xc4,0x22,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0x00,0xea,0x92,0xe5, -0x04,0x0a,0x92,0xe5,0x08,0x2a,0x92,0xe5,0x0f,0xe0,0x0e,0xe2,0x3f,0x00,0x00,0xe2, -0x02,0x21,0xa0,0xe1,0x22,0x1d,0xa0,0xe1,0x83,0x31,0x83,0xe0,0x02,0x23,0xa0,0xe1, -0x01,0x50,0x55,0xe2,0x03,0x31,0x81,0xe0,0xf9,0xff,0xff,0x1a,0x8c,0x22,0x9f,0xe5, -0x0e,0x9c,0xa0,0xe1,0x00,0x79,0xa0,0xe1,0x00,0x00,0xa0,0xe3,0x00,0x09,0xa0,0xe1, -0x00,0xc0,0xa0,0xe3,0x10,0xea,0x92,0xe5,0x3f,0xb3,0xe0,0xe3,0x14,0x1a,0x92,0xe5, -0x03,0xb0,0x0b,0xe0,0x18,0xaa,0x92,0xe5,0x0c,0x3c,0xa0,0xe1,0x3f,0xe0,0x0e,0xe2, -0x0c,0x00,0x8d,0xe5,0x0e,0xe9,0xa0,0xe1,0x09,0x70,0x87,0xe1,0x81,0x1b,0xa0,0xe1, -0x05,0x60,0x85,0xe1,0x8a,0xab,0xa0,0xe1,0x08,0xe0,0x8d,0xe5,0xa1,0x1b,0xa0,0xe1, -0x08,0x90,0x8d,0xe2,0x00,0x03,0x99,0xe8,0xaa,0xab,0xa0,0xe1,0x2b,0x34,0x83,0xe1, -0x14,0x10,0x8d,0xe5,0x0b,0x2c,0xa0,0xe1,0x10,0xa0,0x8d,0xe5,0x00,0xa0,0xa0,0xe3, -0x14,0xe0,0x9d,0xe5,0x8a,0x14,0xa0,0xe1,0x10,0xc0,0x9d,0xe5,0x09,0x70,0x87,0xe1, -0x01,0x70,0x87,0xe1,0x0b,0xa0,0xa0,0xe1,0x07,0x30,0x83,0xe1,0x8e,0x04,0xa0,0xe1, -0x0c,0x60,0x86,0xe1,0x08,0x60,0x86,0xe1,0x00,0x60,0x86,0xe1,0x05,0x00,0xa0,0xe1, -0x06,0x20,0x82,0xe1,0x0c,0x00,0x84,0xe8,0xf7,0xfd,0xff,0xeb,0x05,0x00,0xa0,0xe1, -0xb6,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3, -0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x64,0x26,0x00,0xeb, -0x00,0x60,0x50,0xe2,0x59,0x00,0x00,0x0a,0xa5,0xfd,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x3b,0x00,0x00,0x1a,0x0f,0x00,0x56,0xe3,0x39,0x00,0x00,0x0a,0xa4,0x31,0x9f,0xe5, -0x00,0x60,0xa0,0x81,0x03,0x30,0x85,0xe0,0x06,0x31,0x93,0xe7,0x07,0x00,0x53,0xe3, -0x36,0x00,0x00,0x9a,0x08,0x00,0xa0,0xe3,0xa0,0xff,0xff,0xea,0xb3,0xfd,0xff,0xeb, -0x00,0x60,0x50,0xe2,0x02,0x30,0xa0,0x13,0x00,0x00,0xa0,0x13,0x00,0x30,0x84,0x15, -0x9a,0xff,0xff,0x1a,0xb7,0xfd,0xff,0xeb,0x00,0x50,0x50,0xe2,0x4a,0x00,0x00,0x0a, -0x95,0xfd,0xff,0xeb,0x00,0x00,0x50,0xe3,0x05,0x30,0xa0,0x13,0x04,0x30,0xa0,0x03, -0x06,0x00,0xa0,0x11,0x00,0x30,0x84,0x15,0x00,0x30,0x84,0x05,0x8f,0xff,0xff,0xea, -0x1c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x3d,0x26,0x00,0xeb,0x00,0x60,0x50,0xe2, -0x2b,0x00,0x00,0x0a,0x7e,0xfd,0xff,0xeb,0x00,0x00,0x50,0xe3,0x0e,0x00,0x00,0x1a, -0x0f,0x00,0x56,0xe3,0x0c,0x00,0x00,0x0a,0x08,0x31,0x9f,0xe5,0x00,0x60,0xa0,0x81, -0x03,0x50,0x85,0xe0,0x06,0x31,0x95,0xe7,0x0a,0x00,0x00,0xea,0x20,0x20,0xa0,0xe3, -0x72,0x0f,0xa0,0xe3,0xa3,0xfd,0xff,0xeb,0x78,0xff,0xff,0xea,0x10,0x20,0xa0,0xe3, -0x69,0x0f,0xa0,0xe3,0x9f,0xfd,0xff,0xeb,0x74,0xff,0xff,0xea,0xcc,0x30,0x9f,0xe5, -0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2,0x00,0x30,0x84,0xe5,0x00,0x00,0xa0,0xe3, -0x6e,0xff,0xff,0xea,0xb4,0x30,0x9f,0xe5,0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2, -0xac,0x20,0x9f,0xe5,0x02,0x50,0x85,0xe0,0x03,0x31,0x95,0xe7,0x00,0x00,0x53,0xe3, -0xf4,0xff,0xff,0xaa,0x08,0x00,0xa0,0xe3,0x64,0xff,0xff,0xea,0x0f,0x00,0x56,0xe3, -0x53,0xff,0xff,0x0a,0x8c,0x30,0x9f,0xe5,0x00,0x60,0xa0,0x81,0x03,0x30,0x85,0xe0, -0x06,0x31,0x93,0xe7,0x07,0x00,0x53,0xe3,0x50,0xff,0xff,0x9a,0x08,0x00,0xa0,0xe3, -0x5a,0xff,0xff,0xea,0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5, -0x31,0x26,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2,0xcc,0xff,0xff,0xea, -0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5,0x2a,0x26,0x00,0xeb, -0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2,0x9e,0xff,0xff,0xea,0x6f,0xfd,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x03,0x30,0xa0,0x13,0x01,0x30,0xa0,0x03,0x05,0x00,0xa0,0x11, -0x00,0x30,0x84,0x15,0x00,0x30,0x84,0x05,0x44,0xff,0xff,0xea,0x40,0x00,0x10,0xe3, -0x03,0x50,0xa0,0x03,0x02,0x50,0xa0,0x13,0x3e,0xff,0xff,0xea,0x1c,0xe0,0x00,0x00, -0x00,0xf0,0x00,0x70,0x24,0xef,0xff,0xff,0x44,0xef,0xff,0xff,0x00,0x00,0x51,0xe3, -0x09,0x00,0xa0,0x03,0x1e,0xff,0x2f,0x01,0x0c,0x00,0x50,0xe3,0x20,0x30,0xa0,0x03, -0x00,0x00,0xa0,0x03,0x00,0x30,0x81,0x05,0x1e,0xff,0x2f,0x01,0x0e,0x00,0x50,0xe3, -0x08,0x30,0xa0,0x03,0x00,0x00,0xa0,0x03,0x00,0x30,0x81,0x05,0x1e,0xff,0x2f,0x01, -0x06,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x10,0x30,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0xf0,0x45,0x2d,0xe9,0x00,0x00,0x51,0xe3,0x00,0x00,0x52,0x13,0xd4,0x43,0x9f,0xe5, -0x24,0xd0,0x4d,0xe2,0x01,0x50,0xa0,0xe1,0x09,0x00,0xa0,0x03,0x04,0x40,0x8f,0xe0, -0x39,0x00,0x00,0x0a,0x06,0x00,0x40,0xe2,0x0e,0x00,0x50,0xe3,0x00,0xf1,0x8f,0x90, -0x3e,0x00,0x00,0xea,0x3f,0x00,0x00,0xea,0x3c,0x00,0x00,0xea,0x3b,0x00,0x00,0xea, -0x3a,0x00,0x00,0xea,0x39,0x00,0x00,0xea,0x3e,0x00,0x00,0xea,0x50,0x00,0x00,0xea, -0xb4,0x00,0x00,0xea,0x74,0x00,0x00,0xea,0x99,0x00,0x00,0xea,0x50,0x00,0x00,0xea, -0x02,0x00,0x00,0xea,0x65,0x00,0x00,0xea,0x68,0x00,0x00,0xea,0x28,0x00,0x00,0xea, -0x1c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0xb9,0x25,0x00,0xeb,0x00,0x60,0x50,0xe2, -0x05,0x00,0x00,0x1a,0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5, -0xd9,0x25,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2,0xf4,0xfc,0xff,0xeb, -0x00,0x00,0x50,0xe3,0xac,0x00,0x00,0x0a,0x2c,0x33,0x9f,0xe5,0xc0,0x39,0x93,0xe5, -0x07,0x30,0x03,0xe2,0x04,0x00,0x53,0xe3,0xbc,0x00,0x00,0x8a,0x1c,0x23,0x9f,0xe5, -0x02,0x40,0x84,0xe0,0x03,0x41,0x94,0xe7,0x00,0x00,0x54,0xe3,0xb7,0x00,0x00,0xba, -0x28,0xfd,0xff,0xeb,0x04,0x00,0x54,0xe3,0x03,0x40,0xa0,0x03,0x04,0x00,0x00,0x0a, -0x09,0x00,0x54,0xe3,0x03,0x40,0x00,0x02,0x01,0x00,0x00,0x0a,0x03,0x00,0x54,0xe3, -0x00,0x40,0xa0,0x13,0x00,0x00,0xa0,0xe3,0x00,0x40,0x85,0xe5,0x24,0xd0,0x8d,0xe2, -0xf0,0x85,0xbd,0xe8,0xd0,0x32,0x9f,0xe5,0x00,0x00,0xa0,0xe3,0xc0,0x39,0x93,0xe5, -0x23,0x32,0xa0,0xe1,0x01,0x30,0x03,0xe2,0x00,0x30,0xc1,0xe5,0xf6,0xff,0xff,0xea, -0x01,0x00,0xa0,0xe3,0xf4,0xff,0xff,0xea,0x10,0x20,0xa0,0xe3,0x69,0x0f,0xa0,0xe3, -0x00,0xfd,0xff,0xeb,0xf0,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3, -0x01,0x1a,0xa0,0xe3,0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5, -0x83,0x25,0x00,0xeb,0x00,0x60,0x50,0xe2,0x86,0x00,0x00,0x0a,0xc4,0xfc,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x71,0x00,0x00,0x1a,0x10,0x00,0x56,0xe3,0x6f,0x00,0x00,0x0a, -0x6c,0x32,0x9f,0xe5,0x00,0x60,0xa0,0x81,0x03,0x40,0x84,0xe0,0x06,0x31,0x94,0xe7, -0x61,0x00,0x00,0xea,0x20,0x20,0xa0,0xe3,0x72,0x0f,0xa0,0xe3,0xe9,0xfc,0xff,0xeb, -0xd9,0xff,0xff,0xea,0xd1,0xfc,0xff,0xeb,0x00,0x40,0x50,0xe2,0x02,0x30,0xa0,0x13, -0x00,0x00,0xa0,0x13,0x00,0x30,0x85,0x15,0xd3,0xff,0xff,0x1a,0xd5,0xfc,0xff,0xeb, -0x00,0x60,0x50,0xe2,0x7f,0x00,0x00,0x0a,0x1c,0x32,0x9f,0xe5,0x68,0x0a,0x93,0xe5, -0x00,0x00,0x50,0xe3,0x06,0x30,0xa0,0x03,0x00,0x30,0x85,0x05,0xca,0xff,0xff,0x0a, -0xad,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3,0x05,0x30,0xa0,0x13,0x04,0x30,0xa0,0x03, -0x04,0x00,0xa0,0x11,0x00,0x30,0x85,0x15,0x00,0x30,0x85,0x05,0xc2,0xff,0xff,0xea, -0x20,0x20,0xa0,0xe3,0xec,0x01,0x9f,0xe5,0xce,0xfc,0xff,0xeb,0xbe,0xff,0xff,0xea, -0xd4,0x31,0x9f,0xe5,0x00,0x00,0xa0,0xe3,0xc0,0x39,0x93,0xe5,0xa3,0x32,0xa0,0xe1, -0x01,0x30,0x03,0xe2,0x00,0x30,0xc1,0xe5,0xb7,0xff,0xff,0xea,0xb8,0x41,0x9f,0xe5, -0x01,0x00,0xa0,0xe3,0xd8,0xfc,0xff,0xeb,0x05,0x00,0xa0,0xe1,0x0c,0x10,0x8d,0xe2, -0x00,0x8a,0x94,0xe5,0x10,0x20,0xa0,0xe3,0x04,0xea,0x94,0xe5,0x08,0xca,0x94,0xe5, -0x0c,0x3a,0x94,0xe5,0x0f,0x80,0x08,0xe2,0x10,0xaa,0x94,0xe5,0x14,0x5a,0x94,0xe5, -0x0e,0xed,0xa0,0xe1,0x18,0x7a,0x94,0xe5,0x0f,0x32,0xc3,0xe3,0x20,0x6a,0x94,0xe5, -0x3f,0xa0,0x0a,0xe2,0x23,0x41,0xa0,0xe1,0x2c,0xe3,0x8e,0xe1,0x85,0x5b,0xa0,0xe1, -0x18,0x80,0x8d,0xe5,0x87,0x7b,0xa0,0xe1,0x3f,0x60,0x06,0xe2,0x25,0x54,0xa0,0xe1, -0x0c,0xcd,0x84,0xe1,0x14,0xe0,0x8d,0xe5,0xa7,0x78,0x85,0xe1,0x10,0xc0,0x8d,0xe5, -0x06,0x60,0x87,0xe1,0x0a,0xac,0x86,0xe1,0x03,0x3f,0x8a,0xe1,0x0c,0x30,0x8d,0xe5, -0xfe,0x1f,0x00,0xeb,0x00,0x00,0xa0,0xe3,0xb7,0xfc,0xff,0xeb,0x00,0x00,0xa0,0xe3, -0x91,0xff,0xff,0xea,0x1c,0xc0,0x8d,0xe2,0x07,0x02,0xa0,0xe3,0x01,0x1a,0xa0,0xe3, -0x00,0x20,0xa0,0xe3,0x03,0x30,0xa0,0xe3,0x00,0xc0,0x8d,0xe5,0x24,0x25,0x00,0xeb, -0x00,0x60,0x50,0xe2,0x2e,0x00,0x00,0x0a,0x65,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x16,0x00,0x00,0x0a,0xf0,0x30,0x9f,0xe5,0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2, -0x04,0x00,0x53,0xe3,0x2d,0x00,0x00,0x8a,0xe0,0x20,0x9f,0xe5,0x02,0x40,0x84,0xe0, -0x03,0x31,0x94,0xe7,0x00,0x00,0x53,0xe3,0x28,0x00,0x00,0xba,0x00,0x30,0x85,0xe5, -0x00,0x00,0xa0,0xe3,0x78,0xff,0xff,0xea,0xbc,0x30,0x9f,0xe5,0x00,0x00,0xa0,0xe3, -0xfc,0x39,0x93,0xe5,0x0f,0x30,0x03,0xe2,0x00,0x30,0x81,0xe5,0x72,0xff,0xff,0xea, -0xa4,0x30,0x9f,0xe5,0xc0,0x39,0x93,0xe5,0x07,0x30,0x03,0xe2,0xf2,0xff,0xff,0xea, -0x10,0x00,0x56,0xe3,0xe6,0xff,0xff,0x0a,0x94,0x30,0x9f,0xe5,0x00,0x60,0xa0,0x81, -0x03,0x30,0x84,0xe0,0x06,0x31,0x93,0xe7,0xe4,0xff,0xff,0xea,0x10,0x00,0x56,0xe3, -0x50,0xff,0xff,0x0a,0x78,0x30,0x9f,0xe5,0x00,0x60,0xa0,0x81,0x03,0x30,0x84,0xe0, -0x06,0x31,0x93,0xe7,0x4e,0xff,0xff,0xea,0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3, -0x08,0x60,0x90,0xe5,0x1c,0x25,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2, -0x71,0xff,0xff,0xea,0x1c,0x00,0x9d,0xe5,0x01,0x1a,0xa0,0xe3,0x08,0x60,0x90,0xe5, -0x15,0x25,0x00,0xeb,0x26,0x6d,0xa0,0xe1,0x0f,0x60,0x06,0xe2,0xc9,0xff,0xff,0xea, -0x08,0x00,0xa0,0xe3,0x50,0xff,0xff,0xea,0x58,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x03,0x30,0xa0,0x13,0x01,0x30,0xa0,0x03,0x06,0x00,0xa0,0x11,0x00,0x30,0x85,0x15, -0x00,0x30,0x85,0x05,0x48,0xff,0xff,0xea,0xd4,0xdb,0x00,0x00,0x00,0xf0,0x00,0x70, -0x84,0xef,0xff,0xff,0x98,0xef,0xff,0xff,0x64,0xf9,0x00,0x70,0x00,0x00,0x51,0xe3, -0x09,0x00,0xa0,0x03,0x1e,0xff,0x2f,0x01,0x06,0x00,0x40,0xe2,0x0c,0x00,0x50,0xe3, -0x00,0xf1,0x8f,0x90,0x14,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x12,0x00,0x00,0xea, -0x11,0x00,0x00,0xea,0x10,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea, -0x05,0x00,0x00,0xea,0x0c,0x00,0x00,0xea,0x07,0x00,0x00,0xea,0x0a,0x00,0x00,0xea, -0x09,0x00,0x00,0xea,0x08,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0x20,0x30,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x10,0x30,0xa0,0xe3, -0x00,0x00,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x04,0xe0,0x2d,0xe5,0x43,0xdf,0x4d,0xe2,0x20,0x31,0x9f,0xe5, -0x03,0x30,0x8f,0xe0,0x1c,0x21,0x9f,0xe5,0x02,0x30,0x83,0xe0,0x0d,0x10,0xa0,0xe1, -0x03,0x20,0xa0,0xe1,0x01,0x3c,0xa0,0xe3,0x01,0x00,0xa0,0xe1,0x02,0x10,0xa0,0xe1, -0x03,0x20,0xa0,0xe1,0x0b,0x28,0x00,0xeb,0xfc,0x30,0x9f,0xe5,0x04,0x31,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x00,0x31,0x8d,0xe5,0x0d,0x00,0x00,0xea,0xec,0x30,0x9f,0xe5, -0x00,0x21,0x9d,0xe5,0x42,0x1f,0x8d,0xe2,0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0, -0x00,0x20,0xd3,0xe5,0x04,0x31,0x9d,0xe5,0x00,0x20,0xc3,0xe5,0x04,0x31,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x04,0x31,0x8d,0xe5,0x00,0x31,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x00,0x31,0x8d,0xe5,0x00,0x31,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a, -0xac,0x30,0x9f,0xe5,0x04,0x31,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x00,0x31,0x8d,0xe5, -0x0d,0x00,0x00,0xea,0x94,0x30,0x9f,0xe5,0x00,0x21,0x9d,0xe5,0x42,0x1f,0x8d,0xe2, -0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0,0x00,0x20,0xd3,0xe5,0x04,0x31,0x9d,0xe5, -0x00,0x20,0xc3,0xe5,0x04,0x31,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x04,0x31,0x8d,0xe5, -0x00,0x31,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x31,0x8d,0xe5,0x00,0x31,0x9d,0xe5, -0xff,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a,0x58,0x30,0x9f,0xe5,0x04,0x31,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x00,0x31,0x8d,0xe5,0x08,0x00,0x00,0xea,0x04,0x31,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x04,0x31,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x04,0x31,0x8d,0xe5,0x00,0x31,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x31,0x8d,0xe5, -0x00,0x31,0x9d,0xe5,0xff,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x43,0xdf,0x8d,0xe2, -0x00,0x80,0xbd,0xe8,0x70,0xd7,0x00,0x00,0xe0,0xef,0xff,0xff,0x00,0xfc,0x03,0x40, -0xf8,0xfe,0xff,0xff,0x50,0xfc,0x03,0x40,0x50,0xfd,0x03,0x40,0x04,0xe0,0x2d,0xe5, -0x3c,0xd0,0x4d,0xe2,0x28,0x22,0x9f,0xe5,0x02,0x20,0x8f,0xe0,0x10,0x30,0x8d,0xe2, -0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3, -0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5, -0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2, -0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3, -0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5, -0x04,0x30,0x83,0xe2,0x00,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5,0x04,0x30,0x83,0xe2, -0xc0,0x31,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x0d,0xc0,0xa0,0xe1,0x0f,0x00,0x93,0xe8, -0x0f,0x00,0x8c,0xe8,0x8a,0xff,0xff,0xeb,0xac,0x31,0x9f,0xe5,0x34,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x30,0x30,0x8d,0xe5,0x0d,0x00,0x00,0xea,0x27,0x30,0xe0,0xe3, -0x30,0x20,0x9d,0xe5,0x38,0x10,0x8d,0xe2,0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0, -0x00,0x20,0xd3,0xe5,0x34,0x30,0x9d,0xe5,0x00,0x20,0xc3,0xe5,0x34,0x30,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x34,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x30,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5,0x1f,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a, -0x58,0x31,0x9f,0xe5,0x34,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x30,0x30,0x8d,0xe5, -0x0d,0x00,0x00,0xea,0x27,0x30,0xe0,0xe3,0x30,0x20,0x9d,0xe5,0x38,0x10,0x8d,0xe2, -0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0,0x00,0x20,0xd3,0xe5,0x34,0x30,0x9d,0xe5, -0x00,0x20,0xc3,0xe5,0x34,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x34,0x30,0x8d,0xe5, -0x30,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x30,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5, -0x0f,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a,0x04,0x31,0x9f,0xe5,0x34,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x30,0x30,0x8d,0xe5,0x0d,0x00,0x00,0xea,0x27,0x30,0xe0,0xe3, -0x30,0x20,0x9d,0xe5,0x38,0x10,0x8d,0xe2,0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0, -0x00,0x20,0xd3,0xe5,0x34,0x30,0x9d,0xe5,0x00,0x20,0xc3,0xe5,0x34,0x30,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x34,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x30,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a, -0xb0,0x30,0x9f,0xe5,0x34,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x30,0x30,0x8d,0xe5, -0x0d,0x00,0x00,0xea,0x37,0x30,0xe0,0xe3,0x30,0x20,0x9d,0xe5,0x38,0x10,0x8d,0xe2, -0x02,0x20,0x81,0xe0,0x03,0x30,0x82,0xe0,0x00,0x20,0xd3,0xe5,0x34,0x30,0x9d,0xe5, -0x00,0x20,0xc3,0xe5,0x34,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x34,0x30,0x8d,0xe5, -0x30,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x30,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5, -0x0f,0x00,0x53,0xe3,0xee,0xff,0xff,0x9a,0x5c,0x30,0x9f,0xe5,0x34,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x30,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x34,0x30,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x34,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x34,0x30,0x8d,0xe5,0x30,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x30,0x30,0x8d,0xe5, -0x30,0x30,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x3c,0xd0,0x8d,0xe2, -0x00,0x80,0xbd,0xe8,0x28,0xd6,0x00,0x00,0xd0,0xef,0xff,0xff,0x10,0xfc,0x03,0x40, -0x30,0xfc,0x03,0x40,0x40,0xfc,0x03,0x40,0x50,0xfe,0x03,0x40,0x60,0xfe,0x03,0x40, -0x08,0xd0,0x4d,0xe2,0x98,0x31,0x9f,0xe5,0x04,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3, -0x00,0x20,0xc3,0xe5,0x04,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x04,0x30,0x8d,0xe5, -0x00,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5, -0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x58,0x31,0x9f,0xe5,0x04,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x04,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x04,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5, -0x00,0x30,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x18,0x31,0x9f,0xe5, -0x04,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea, -0x04,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x04,0x30,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x04,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x00,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5,0xff,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a, -0xd8,0x30,0x9f,0xe5,0x04,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5, -0x08,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5, -0x04,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x04,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5,0xff,0x00,0x53,0xe3, -0xf3,0xff,0xff,0x9a,0x98,0x30,0x9f,0xe5,0x04,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x00,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3, -0x00,0x20,0xc3,0xe5,0x04,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x04,0x30,0x8d,0xe5, -0x00,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5, -0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x58,0x30,0x9f,0xe5,0x04,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5, -0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x04,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x04,0x30,0x8d,0xe5,0x00,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5, -0x00,0x30,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x08,0xd0,0x8d,0xe2, -0x1e,0xff,0x2f,0xe1,0x00,0xfc,0x03,0x40,0x30,0xfc,0x03,0x40,0x50,0xfc,0x03,0x40, -0x50,0xfd,0x03,0x40,0x50,0xfe,0x03,0x40,0x60,0xfe,0x03,0x40,0x18,0xd0,0x4d,0xe2, -0x0c,0x00,0x8d,0xe5,0x08,0x10,0x8d,0xe5,0x04,0x20,0x8d,0xe5,0x00,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x17,0x30,0xcd,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x30,0x9d,0xe5, -0x03,0x00,0x52,0xe1,0x18,0x00,0x00,0x1a,0x01,0x30,0xa0,0xe3,0x17,0x30,0xcd,0xe5, -0x00,0x30,0xa0,0xe3,0x10,0x30,0x8d,0xe5,0x0f,0x00,0x00,0xea,0x0c,0x20,0x9d,0xe5, -0x10,0x30,0x9d,0xe5,0x03,0x30,0x82,0xe0,0x00,0x20,0xd3,0xe5,0x08,0x10,0x9d,0xe5, -0x10,0x30,0x9d,0xe5,0x03,0x30,0x81,0xe0,0x00,0x30,0xd3,0xe5,0x03,0x00,0x52,0xe1, -0x02,0x00,0x00,0x0a,0x00,0x30,0xa0,0xe3,0x17,0x30,0xcd,0xe5,0x06,0x00,0x00,0xea, -0x10,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x10,0x30,0x8d,0xe5,0x10,0x20,0x9d,0xe5, -0x04,0x30,0x9d,0xe5,0x03,0x00,0x52,0xe1,0xeb,0xff,0xff,0x3a,0x17,0x30,0xdd,0xe5, -0x03,0x00,0xa0,0xe1,0x18,0xd0,0x8d,0xe2,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1, -0x20,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x1f,0x30,0xcd,0xe5, -0x00,0x30,0xa0,0xe3,0x18,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x10,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x0c,0x30,0x8d,0xe5, -0x04,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3, -0x70,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5,0x18,0x30,0x8d,0xe5, -0x18,0x30,0x9d,0xe5,0x01,0x30,0x03,0xe2,0x14,0x30,0x8d,0xe5,0x18,0x30,0x9d,0xe5, -0xa3,0x31,0xa0,0xe1,0x01,0x30,0x03,0xe2,0x10,0x30,0x8d,0xe5,0x18,0x30,0x9d,0xe5, -0xa3,0x34,0xa0,0xe1,0x01,0x30,0x03,0xe2,0x0c,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5, -0x00,0x00,0x53,0xe3,0x05,0x00,0x00,0x1a,0x10,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x02,0x00,0x00,0x0a,0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x01,0x00,0x00,0x0a, -0x01,0x30,0xa0,0xe3,0x1f,0x30,0xcd,0xe5,0x1f,0x30,0xdd,0xe5,0x03,0x00,0xa0,0xe1, -0x20,0xd0,0x8d,0xe2,0x1e,0xff,0x2f,0xe1,0x18,0xb0,0x01,0x60,0x04,0xe0,0x2d,0xe5, -0x14,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5,0x00,0x10,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x0c,0x30,0x8d,0xe5,0x00,0x00,0xa0,0xe1,0x04,0x00,0x9d,0xe5,0xc7,0xff,0xff,0xeb, -0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3,0xfa,0xff,0xff,0x1a,0x04,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3,0x4c,0x30,0x9f,0xe5, -0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5,0x0c,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5, -0x1f,0x26,0xc3,0xe3,0x00,0x30,0x9d,0xe5,0x1f,0x30,0x03,0xe2,0x03,0x3a,0xa0,0xe1, -0x03,0x30,0x82,0xe1,0x0c,0x30,0x8d,0xe5,0x04,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2, -0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3,0x10,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0, -0x0c,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x14,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8, -0x08,0xb1,0x01,0x60,0x04,0xe0,0x2d,0xe5,0x14,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5, -0x00,0x10,0x8d,0xe5,0x01,0x30,0xa0,0xe3,0x0b,0x30,0xcd,0xe5,0x04,0x00,0x9d,0xe5, -0x1f,0x10,0xa0,0xe3,0xd0,0xff,0xff,0xeb,0x00,0x30,0xa0,0xe3,0x0c,0x30,0x8d,0xe5, -0x21,0x00,0x00,0xea,0x04,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x07,0x00,0x00,0x1a, -0x0c,0x20,0x9d,0xe5,0x8c,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x03,0x31,0xa0,0xe1, -0x00,0x20,0x93,0xe5,0x00,0x30,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x09,0x00,0x00,0xea, -0x04,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe3,0x06,0x00,0x00,0x1a,0x0c,0x20,0x9d,0xe5, -0x64,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x03,0x31,0xa0,0xe1,0x00,0x20,0x93,0xe5, -0x00,0x30,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x00,0x30,0x9d,0xe5,0x00,0x30,0x93,0xe5, -0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x0a,0x00,0x30,0xa0,0xe3,0x0b,0x30,0xcd,0xe5, -0x08,0x00,0x00,0xea,0x00,0x30,0x9d,0xe5,0x04,0x30,0x83,0xe2,0x00,0x30,0x8d,0xe5, -0x0c,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x0c,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5, -0x3f,0x00,0x53,0xe3,0xda,0xff,0xff,0x9a,0x0b,0x30,0xdd,0xe5,0x03,0x00,0xa0,0xe1, -0x14,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8,0x80,0x6d,0x00,0x18,0x80,0x45,0x00,0x18, -0x10,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x0c,0x30,0x8d,0xe5, -0x04,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3, -0x3c,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5,0x0c,0x30,0x8d,0xe5, -0x0c,0x30,0x9d,0xe5,0x02,0x30,0xc3,0xe3,0x0c,0x30,0x8d,0xe5,0x04,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3,0x10,0x30,0x9f,0xe5, -0x03,0x30,0x82,0xe0,0x0c,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x10,0xd0,0x8d,0xe2, -0x1e,0xff,0x2f,0xe1,0x10,0xb1,0x01,0x60,0x10,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x0c,0x30,0x8d,0xe5,0x01,0x30,0xa0,0xe3,0x0b,0x30,0xcd,0xe5, -0x04,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x0a,0x01,0x00,0x53,0xe3, -0x04,0x00,0x00,0x0a,0x07,0x00,0x00,0xea,0x4c,0x30,0x9f,0xe5,0x00,0x30,0x93,0xe5, -0x0c,0x30,0x8d,0xe5,0x03,0x00,0x00,0xea,0x40,0x30,0x9f,0xe5,0x00,0x30,0x93,0xe5, -0x0c,0x30,0x8d,0xe5,0x00,0x00,0xa0,0xe1,0x0c,0x30,0x9d,0xe5,0xa3,0x30,0xa0,0xe1, -0x01,0x30,0x03,0xe2,0x0c,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x01,0x00,0x00,0x0a,0x00,0x30,0xa0,0xe3,0x0b,0x30,0xcd,0xe5,0x0b,0x30,0xdd,0xe5, -0x03,0x00,0xa0,0xe1,0x10,0xd0,0x8d,0xe2,0x1e,0xff,0x2f,0xe1,0x10,0xb1,0x01,0x60, -0x10,0x11,0x01,0x60,0x04,0xe0,0x2d,0xe5,0x24,0xd0,0x4d,0xe2,0x0c,0x00,0x8d,0xe5, -0x08,0x10,0x8d,0xe5,0x04,0x20,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x18,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x1c,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x10,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3, -0x02,0x00,0x00,0x1a,0xa0,0x30,0xa0,0xe3,0x1c,0x30,0x8d,0xe5,0x04,0x00,0x00,0xea, -0x0c,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe3,0x01,0x00,0x00,0x1a,0x50,0x30,0xa0,0xe3, -0x1c,0x30,0x8d,0xe5,0x1c,0x30,0x9d,0xe5,0x02,0x30,0x83,0xe2,0x10,0x30,0x8d,0xe5, -0x08,0x30,0x9d,0xe5,0x08,0x30,0x83,0xe3,0x83,0x38,0xa0,0xe1,0x57,0x34,0x83,0xe3, -0x18,0x30,0x8d,0xe5,0x1c,0x30,0x9d,0xe5,0x03,0x28,0xa0,0xe1,0x04,0x30,0x9d,0xe5, -0x03,0x38,0xa0,0xe1,0x23,0x38,0xa0,0xe1,0x03,0x30,0x82,0xe1,0x1f,0x33,0x83,0xe3, -0x14,0x30,0x8d,0xe5,0x00,0x00,0xa0,0xe1,0x0c,0x00,0x9d,0xe5,0x0b,0xff,0xff,0xeb, -0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3,0xfa,0xff,0xff,0x1a,0x0c,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x06,0x32,0x83,0xe2, -0x1b,0x3a,0x83,0xe2,0x14,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x10,0x30,0x9d,0xe5, -0x03,0x28,0xa0,0xe1,0x04,0x10,0x9d,0xe5,0xa0,0x30,0x9f,0xe5,0x03,0x30,0x01,0xe0, -0x23,0x38,0xa0,0xe1,0x03,0x30,0x82,0xe1,0x1f,0x33,0x83,0xe3,0x14,0x30,0x8d,0xe5, -0x00,0x00,0xa0,0xe1,0x0c,0x00,0x9d,0xe5,0xf4,0xfe,0xff,0xeb,0x00,0x30,0xa0,0xe1, -0x00,0x00,0x53,0xe3,0xfa,0xff,0xff,0x1a,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2, -0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2, -0x14,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x00,0x00,0xa0,0xe1,0x0c,0x00,0x9d,0xe5, -0xe6,0xfe,0xff,0xeb,0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3,0xfa,0xff,0xff,0x1a, -0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3, -0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2,0x18,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5, -0x00,0x00,0xa0,0xe1,0x0c,0x00,0x9d,0xe5,0xd8,0xfe,0xff,0xeb,0x00,0x30,0xa0,0xe1, -0x00,0x00,0x53,0xe3,0xfa,0xff,0xff,0x1a,0x24,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8, -0x00,0x00,0xff,0x0f,0x18,0xd0,0x4d,0xe2,0x04,0x00,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x14,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x10,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x0c,0x30,0x8d,0xe5,0x04,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3, -0xff,0x20,0xc2,0xe3,0x44,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x01,0x30,0x03,0xe2,0x10,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0xa3,0x31,0xa0,0xe1,0x01,0x30,0x03,0xe2,0x0c,0x30,0x8d,0xe5, -0x10,0x30,0x9d,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x0a,0x0c,0x30,0x9d,0xe5, -0x01,0x00,0x73,0xe3,0xea,0xff,0xff,0x1a,0x18,0xd0,0x8d,0xe2,0x1e,0xff,0x2f,0xe1, -0x18,0xb0,0x01,0x60,0x04,0xe0,0x2d,0xe5,0x1c,0xd0,0x4d,0xe2,0x0c,0x00,0x8d,0xe5, -0x08,0x10,0x8d,0xe5,0x04,0x20,0x8d,0xe5,0x00,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x14,0x30,0x8d,0xe5,0x33,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x1b,0x3a,0x83,0xe2, -0x86,0x32,0x83,0xe2,0x14,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x01,0x3b,0xa0,0xe3, -0x14,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3, -0xff,0x20,0xc2,0xe3,0x3c,0x32,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x14,0x20,0x9d,0xe5, -0x00,0x20,0x83,0xe5,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3, -0xff,0x20,0xc2,0xe3,0x20,0x32,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0xff,0x34,0xc3,0xe3,0x14,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0xff,0x38,0xc3,0xe3,0x14,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3,0xe8,0x31,0x9f,0xe5, -0x03,0x30,0x82,0xe0,0x14,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x0c,0x30,0x9d,0xe5, -0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3,0xcc,0x31,0x9f,0xe5, -0x03,0x30,0x82,0xe0,0x00,0x30,0x93,0xe5,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5, -0x0f,0x32,0xc3,0xe3,0x01,0x32,0x83,0xe3,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5, -0x02,0x3b,0xc3,0xe3,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x01,0x3b,0x83,0xe3, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x02,0x2c,0xc3,0xe3,0x24,0x30,0xdd,0xe5, -0x00,0x00,0x53,0xe3,0x01,0x00,0x00,0x0a,0x02,0x3c,0xa0,0xe3,0x00,0x00,0x00,0xea, -0x00,0x30,0xa0,0xe3,0x03,0x30,0x82,0xe1,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5, -0x06,0x2d,0xc3,0xe3,0x24,0x30,0xdd,0xe5,0x00,0x00,0x53,0xe3,0x01,0x00,0x00,0x0a, -0x01,0x3c,0xa0,0xe3,0x00,0x00,0x00,0xea,0x06,0x3d,0xa0,0xe3,0x03,0x30,0x82,0xe1, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x60,0x30,0xc3,0xe3,0x14,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0x18,0x20,0xc3,0xe3,0x24,0x30,0xdd,0xe5,0x00,0x00,0x53,0xe3, -0x01,0x00,0x00,0x0a,0x10,0x30,0xa0,0xe3,0x00,0x00,0x00,0xea,0x18,0x30,0xa0,0xe3, -0x03,0x30,0x82,0xe1,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x04,0x30,0xc3,0xe3, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x01,0x30,0xc3,0xe3,0x14,0x30,0x8d,0xe5, -0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3, -0xe8,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x14,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5, -0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x2c,0xc3,0xe3,0xff,0x20,0xc2,0xe3, -0xcc,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x00,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5, -0x0c,0x00,0x9d,0xe5,0x62,0xff,0xff,0xeb,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2, -0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2, -0x01,0x21,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x0c,0x00,0x9d,0xe5,0x58,0xff,0xff,0xeb, -0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2,0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3, -0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2,0x04,0x20,0x9d,0xe5,0x00,0x20,0x83,0xe5, -0x0c,0x00,0x9d,0xe5,0x4e,0xff,0xff,0xeb,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2, -0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2, -0x20,0x20,0x9d,0xe5,0x01,0x20,0x42,0xe2,0x0e,0x23,0x82,0xe3,0x00,0x20,0x83,0xe5, -0x0c,0x00,0x9d,0xe5,0x42,0xff,0xff,0xeb,0x0c,0x30,0x9d,0xe5,0x00,0x30,0x63,0xe2, -0x9f,0x3c,0xc3,0xe3,0xff,0x30,0xc3,0xe3,0x06,0x32,0x83,0xe2,0x1b,0x3a,0x83,0xe2, -0x11,0x23,0xa0,0xe3,0x00,0x20,0x83,0xe5,0x0c,0x00,0x9d,0xe5,0x38,0xff,0xff,0xeb, -0x1c,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8,0x44,0xb0,0x01,0x60,0x0c,0xb1,0x01,0x60, -0x04,0xb1,0x01,0x60,0x00,0xb1,0x01,0x60,0x04,0xe0,0x2d,0xe5,0x24,0xd0,0x4d,0xe2, -0x00,0x30,0xa0,0xe3,0x1f,0x30,0xcd,0xe5,0x40,0x30,0xa0,0xe3,0x0c,0x30,0x8d,0xe5, -0x48,0x31,0x9f,0xe5,0x10,0x30,0x8d,0xe5,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3, -0x29,0xfe,0xff,0xeb,0x38,0x31,0x9f,0xe5,0x18,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3, -0x14,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea,0x18,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3, -0x00,0x20,0xc3,0xe5,0x18,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x18,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5, -0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a,0x10,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5, -0x00,0x30,0xa0,0xe3,0x04,0x30,0x8d,0xe5,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3, -0xdc,0x20,0x9f,0xe5,0xd8,0x30,0x9f,0xe5,0x2d,0xff,0xff,0xeb,0xd0,0x30,0x9f,0xe5, -0x18,0x30,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5,0x08,0x00,0x00,0xea, -0x18,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0x18,0x30,0x9d,0xe5, -0x01,0x30,0x83,0xe2,0x18,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x14,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x0f,0x00,0x53,0xe3,0xf3,0xff,0xff,0x9a, -0x00,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5,0x15,0x00,0x00,0xea,0x14,0x20,0x9d,0xe5, -0x80,0x30,0x9f,0xe5,0x03,0x30,0x82,0xe0,0x03,0x31,0xa0,0xe1,0x00,0x20,0x93,0xe5, -0x10,0x30,0x9d,0xe5,0x00,0x20,0x83,0xe5,0x10,0x30,0x9d,0xe5,0x00,0x30,0x93,0xe5, -0x00,0x00,0x53,0xe3,0x00,0x30,0xa0,0x13,0x01,0x30,0xa0,0x03,0x1f,0x30,0xcd,0xe5, -0x1f,0x30,0xdd,0xe5,0x00,0x00,0x53,0xe3,0x0b,0x00,0x00,0x0a,0x10,0x30,0x9d,0xe5, -0x04,0x30,0x83,0xe2,0x10,0x30,0x8d,0xe5,0x14,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2, -0x14,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x23,0x21,0xa0,0xe1,0x14,0x30,0x9d,0xe5, -0x03,0x00,0x52,0xe1,0xe4,0xff,0xff,0x8a,0x00,0x00,0x00,0xea,0x00,0x00,0xa0,0xe1, -0x1f,0x30,0xdd,0xe5,0x03,0x00,0xa0,0xe1,0x24,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8, -0x50,0xfd,0x03,0x40,0x30,0xfc,0x03,0x40,0x80,0x6d,0x00,0x18,0x08,0xd0,0x4d,0xe2, -0x20,0x30,0x9f,0xe5,0x00,0x30,0x93,0xe5,0x04,0x30,0x8d,0xe5,0x04,0x30,0x9d,0xe5, -0x10,0x30,0x83,0xe3,0x04,0x30,0x8d,0xe5,0x08,0x30,0x9f,0xe5,0x04,0x20,0x9d,0xe5, -0x00,0x20,0x83,0xe5,0xfe,0xff,0xff,0xea,0x00,0xe4,0x00,0x70,0x04,0xe0,0x2d,0xe5, -0x1c,0xd0,0x4d,0xe2,0x01,0x30,0xa0,0xe3,0x13,0x30,0xcd,0xe5,0x00,0x30,0xa0,0xe3, -0x12,0x30,0xcd,0xe5,0x00,0x30,0xa0,0xe3,0x11,0x30,0xcd,0xe5,0x90,0x31,0x9f,0xe5, -0x00,0x30,0x93,0xe5,0x0c,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x23,0x34,0xa0,0xe1, -0xff,0x30,0x03,0xe2,0x0c,0x30,0x8d,0xe5,0x0c,0x30,0x9d,0xe5,0x20,0x00,0x53,0xe3, -0x59,0x00,0x00,0x1a,0x88,0xfd,0xff,0xeb,0x00,0x30,0xa0,0xe3,0x14,0x30,0x8d,0xe5, -0x3a,0x00,0x00,0xea,0x58,0xfc,0xff,0xeb,0x14,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3, -0xb1,0xfd,0xff,0xeb,0x14,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3,0x44,0x21,0x9f,0xe5, -0x47,0xfe,0xff,0xeb,0x10,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5,0x01,0x30,0xa0,0xe3, -0x04,0x30,0x8d,0xe5,0x14,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3,0x28,0x21,0x9f,0xe5, -0x28,0x31,0x9f,0xe5,0xc2,0xfe,0xff,0xeb,0x24,0x01,0x9f,0xe5,0x1c,0x11,0x9f,0xe5, -0x10,0x20,0xa0,0xe3,0x10,0x30,0xa0,0xe3,0x47,0xfd,0xff,0xeb,0x00,0x30,0xa0,0xe1, -0x00,0x00,0x53,0xe3,0x00,0x00,0x00,0x1a,0xc3,0xff,0xff,0xeb,0x14,0x00,0x9d,0xe5, -0x00,0x11,0x9f,0xe5,0xbe,0xfd,0xff,0xeb,0x00,0x30,0xa0,0xe1,0x13,0x30,0xcd,0xe5, -0x14,0x00,0x9d,0xe5,0x0b,0xfe,0xff,0xeb,0x00,0x30,0xa0,0xe1,0x12,0x30,0xcd,0xe5, -0x12,0x30,0xdd,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x00,0x0a,0x13,0x30,0xdd,0xe5, -0x00,0x00,0x53,0xe3,0x0e,0x00,0x00,0x1a,0x14,0x00,0x9d,0xe5,0xe7,0xfd,0xff,0xeb, -0x14,0x00,0x9d,0xe5,0xff,0xfd,0xff,0xeb,0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3, -0x00,0x00,0x00,0x1a,0xac,0xff,0xff,0xeb,0x14,0x00,0x9d,0xe5,0xa4,0x10,0x9f,0xe5, -0xa7,0xfd,0xff,0xeb,0x00,0x30,0xa0,0xe1,0x00,0x00,0x53,0xe3,0x00,0x00,0x00,0x1a, -0xa5,0xff,0xff,0xeb,0x14,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x14,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe3,0xc1,0xff,0xff,0x9a,0x41,0xff,0xff,0xeb, -0x00,0x30,0xa0,0xe1,0x11,0x30,0xcd,0xe5,0x11,0x30,0xdd,0xe5,0x00,0x00,0x53,0xe3, -0x00,0x00,0x00,0x1a,0x98,0xff,0xff,0xeb,0xa8,0xfc,0xff,0xeb,0x00,0x30,0xa0,0xe3, -0x14,0x30,0x8d,0xe5,0x09,0x00,0x00,0xea,0x14,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3, -0x69,0xfd,0xff,0xeb,0x14,0x00,0x9d,0xe5,0x06,0x10,0xa0,0xe3,0x24,0x20,0x9f,0xe5, -0xff,0xfd,0xff,0xeb,0x14,0x30,0x9d,0xe5,0x01,0x30,0x83,0xe2,0x14,0x30,0x8d,0xe5, -0x14,0x30,0x9d,0xe5,0x01,0x00,0x53,0xe3,0xf2,0xff,0xff,0x9a,0x1c,0xd0,0x8d,0xe2, -0x00,0x80,0xbd,0xe8,0x04,0x08,0x00,0x70,0x00,0xfc,0x03,0x40,0x40,0xfc,0x03,0x40, -0x60,0xfe,0x03,0x40,0x50,0xfe,0x03,0x40,0x50,0xfd,0x03,0x40,0x20,0x38,0xb0,0xe1, -0x0f,0x00,0x00,0x1a,0x02,0x00,0x50,0xe3,0x22,0x00,0x00,0x0a,0x14,0x00,0x00,0x8a, -0x00,0x00,0x50,0xe3,0x26,0x00,0x00,0x1a,0x07,0x20,0x02,0xe2,0xd8,0x30,0x9f,0xe5, -0x02,0x22,0xa0,0xe1,0x02,0x22,0x82,0xe3,0x28,0x20,0x83,0xe5,0xa8,0x20,0x93,0xe5, -0xff,0x24,0xc2,0xe3,0x01,0x27,0x82,0xe3,0x01,0x1c,0x82,0xe1,0xa8,0x10,0x83,0xe5, -0x05,0x00,0x00,0xea,0x01,0x18,0xa0,0xe1,0x06,0x32,0x83,0xe2,0x06,0x3a,0x83,0xe2, -0x21,0x18,0xa0,0xe1,0x02,0x2f,0x81,0xe1,0x00,0x20,0x83,0xe5,0x02,0x00,0xa0,0xe3, -0x06,0x1b,0x00,0xea,0x40,0x00,0x50,0xe3,0x1a,0x00,0x00,0x0a,0x79,0x00,0x50,0xe3, -0xf9,0xff,0xff,0x1a,0x80,0x30,0x9f,0xe5,0xff,0x10,0x01,0xe2,0x9c,0x01,0x93,0xe5, -0x03,0x01,0xc0,0xe3,0x02,0x2f,0x80,0xe1,0xff,0x20,0xc2,0xe3,0x01,0x10,0x82,0xe1, -0x9c,0x11,0x83,0xe5,0xf0,0xff,0xff,0xea,0x5c,0x30,0x9f,0xe5,0x03,0x10,0x01,0xe2, -0x30,0x20,0x93,0xe5,0x03,0x20,0xc2,0xe3,0x02,0x10,0x81,0xe1,0x30,0x10,0x83,0xe5, -0xe9,0xff,0xff,0xea,0x01,0x00,0x50,0xe3,0xe7,0xff,0xff,0x1a,0x38,0x30,0x9f,0xe5, -0x03,0x10,0x01,0xe2,0x30,0x20,0x93,0xe5,0x30,0x20,0xc2,0xe3,0x01,0x12,0x82,0xe1, -0x30,0x10,0x83,0xe5,0xe0,0xff,0xff,0xea,0x02,0x22,0xa0,0xe1,0x18,0x30,0x9f,0xe5, -0xff,0x10,0x01,0xe2,0xff,0x20,0x02,0xe2,0x02,0x11,0x81,0xe3,0x02,0x22,0x82,0xe3, -0x20,0x20,0x83,0xe5,0x24,0x10,0x83,0xe5,0xd7,0xff,0xff,0xea,0x00,0x60,0x00,0x60, -0x08,0x30,0x9f,0xe5,0x50,0x00,0x93,0xe5,0x20,0x0f,0xa0,0xe1,0x1e,0xff,0x2f,0xe1, -0x00,0x60,0x00,0x60,0xb0,0xc0,0x9f,0xe5,0x70,0x00,0x2d,0xe9,0x0c,0x40,0x9d,0xe5, -0x0c,0x00,0x50,0xe1,0x10,0xc0,0x9d,0xe5,0x19,0x00,0x00,0x0a,0x00,0x68,0xa0,0xe1, -0x02,0x5b,0xa0,0xe1,0x0c,0xc2,0xa0,0xe1,0x20,0x08,0xa0,0xe1,0x26,0x28,0xa0,0xe1, -0x1f,0x10,0x01,0xe2,0x01,0x11,0x81,0xe3,0xff,0xc0,0x0c,0xe2,0x25,0x17,0x81,0xe1, -0x0f,0x40,0x04,0xe2,0x07,0x30,0x03,0xe2,0x04,0x44,0x8c,0xe1,0x06,0x22,0x82,0xe2, -0x03,0x3a,0x81,0xe1,0x06,0x02,0x80,0xe2,0x06,0x2a,0x82,0xe2,0x06,0x0a,0x80,0xe2, -0x00,0x40,0x82,0xe5,0x00,0x30,0x80,0xe5,0x50,0x30,0x9f,0xe5,0x10,0x20,0x93,0xe5, -0x14,0x30,0x9d,0xe5,0x4b,0x2f,0x82,0xe2,0x00,0x20,0x83,0xe5,0x70,0x00,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0x1f,0x10,0x01,0xe2,0x02,0x2b,0xa0,0xe1,0x0c,0xc2,0xa0,0xe1, -0x01,0x11,0x81,0xe3,0x22,0x27,0x81,0xe1,0x24,0x00,0x9f,0xe5,0xff,0xc0,0x0c,0xe2, -0x0f,0x40,0x04,0xe2,0x01,0x30,0x03,0xe2,0x04,0x44,0x8c,0xe1,0x03,0x3a,0x82,0xe1, -0xcc,0x40,0x80,0xe5,0xc0,0x30,0x80,0xe5,0xea,0xff,0xff,0xea,0xcc,0x00,0xc0,0x00, -0x00,0x50,0x00,0x60,0x00,0x60,0x00,0x60,0x40,0x00,0x10,0xe3,0x30,0x00,0x2d,0xe9, -0x10,0x00,0x00,0x0a,0x20,0x20,0x00,0xe2,0xa4,0x30,0x9f,0xe5,0xa2,0x21,0xa0,0xe1, -0x00,0x00,0x51,0xe3,0x1f,0xc0,0x00,0xe2,0xff,0x20,0x02,0xe2,0x01,0x50,0xa0,0x13, -0x03,0x40,0x92,0xe7,0x01,0x50,0xa0,0x03,0x15,0xcc,0x84,0x11,0x15,0xcc,0xc4,0x01, -0x79,0x00,0x50,0xe3,0x03,0xc0,0x82,0xe7,0x0d,0x00,0x00,0x0a,0x02,0x00,0xa0,0xe3, -0x30,0x00,0xbd,0xe8,0x95,0x1a,0x00,0xea,0x01,0x00,0x50,0xe3,0x10,0x00,0x00,0x0a, -0x02,0x00,0x50,0xe3,0xf8,0xff,0xff,0x1a,0x58,0x30,0x9f,0xe5,0x01,0x10,0x01,0xe2, -0x30,0x20,0x93,0xe5,0x08,0x20,0xc2,0xe3,0x81,0x11,0x82,0xe1,0x30,0x10,0x83,0xe5, -0xf1,0xff,0xff,0xea,0x3c,0x30,0x9f,0xe5,0x00,0x00,0x51,0xe3,0x9c,0x21,0x93,0xe5, -0x30,0x30,0x9f,0xe5,0x03,0x24,0x82,0x13,0x03,0x24,0xc2,0x03,0x9c,0x21,0x83,0xe5, -0xe9,0xff,0xff,0xea,0x1c,0x30,0x9f,0xe5,0x81,0x13,0xa0,0xe1,0xff,0x10,0x01,0xe2, -0x30,0x20,0x93,0xe5,0x80,0x20,0xc2,0xe3,0x02,0x10,0x81,0xe1,0x30,0x10,0x83,0xe5, -0xe1,0xff,0xff,0xea,0x10,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x08,0x30,0x9f,0xe5, -0x10,0x39,0x93,0xe5,0x00,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70, -0xf0,0x4f,0x2d,0xe9,0x00,0x70,0xa0,0xe1,0xe0,0x47,0x9f,0xe5,0x00,0xc0,0xa0,0xe3, -0x1c,0xd0,0x4d,0xe2,0xd8,0x57,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0xd4,0x67,0x9f,0xe5, -0x05,0x30,0x84,0xe0,0x04,0x20,0xd3,0xe5,0x06,0x10,0x84,0xe7,0x05,0x20,0xc1,0xe5, -0x05,0x20,0x94,0xe7,0x08,0x20,0x81,0xe5,0x0c,0x00,0xd0,0xe5,0x02,0x00,0xc1,0xe5, -0x0d,0x00,0xd7,0xe5,0x2c,0xc1,0xc1,0xe5,0x03,0x00,0xc1,0xe5,0x0e,0x30,0xd3,0xe5, -0x0c,0x00,0x53,0xe1,0x03,0x10,0xa0,0x13,0x02,0x00,0x00,0x1a,0x02,0x00,0x52,0xe3, -0x02,0x10,0xa0,0x13,0x01,0x10,0xa0,0x03,0x03,0x00,0xa0,0xe3,0x06,0x04,0x00,0xeb, -0x0d,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x74,0x06,0x00,0xeb,0x00,0x10,0xd7,0xe5, -0x00,0x20,0xa0,0xe3,0x70,0x07,0x9f,0xe5,0x01,0x10,0x41,0xe2,0x81,0x10,0xa0,0xe1, -0x2d,0xff,0xff,0xeb,0x60,0x07,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0xa1,0xff,0xff,0xeb, -0x0d,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x68,0x06,0x00,0xeb,0x4c,0x37,0x9f,0xe5, -0x08,0x10,0xa0,0xe3,0x05,0x20,0x84,0xe0,0x05,0x00,0xd2,0xe5,0x3c,0x10,0x83,0xe5, -0x04,0x10,0x97,0xe5,0x00,0x00,0x50,0xe3,0x14,0x10,0x83,0xe5,0x08,0x10,0x97,0xe5, -0x1c,0x10,0x83,0xe5,0x9c,0x00,0x00,0x0a,0x06,0x20,0x94,0xe7,0xff,0x00,0xa0,0xe3, -0x18,0x37,0x9f,0xe5,0x05,0x10,0x84,0xe0,0x0f,0xc0,0xd1,0xe5,0x10,0x70,0x92,0xe5, -0x08,0xa0,0x93,0xe5,0x03,0x80,0xa0,0xe1,0x0c,0x00,0x82,0xe5,0x01,0xc0,0x0c,0xe2, -0xb8,0x11,0xd2,0xe1,0x08,0xa0,0x83,0xe5,0xb6,0xa1,0xd2,0xe1,0x20,0x00,0x83,0xe5, -0x24,0x70,0x83,0xe5,0x04,0x90,0xd2,0xe5,0xb4,0x01,0xd2,0xe1,0xe0,0x76,0x9f,0xe5, -0x11,0x19,0x8a,0xe0,0x21,0x28,0xa0,0xe1,0x01,0xa0,0xa0,0xe1,0xca,0xbf,0xa0,0xe1, -0x01,0x18,0x80,0xe1,0x0b,0x28,0x82,0xe1,0x28,0x10,0x83,0xe5,0x2c,0x20,0x83,0xe5, -0x10,0x20,0x93,0xe5,0x0c,0x2a,0x82,0xe1,0x10,0x20,0x83,0xe5,0xb4,0x26,0x9f,0xe5, -0x00,0x20,0x83,0xe5,0x02,0x00,0x00,0xea,0x1c,0x1a,0x00,0xeb,0x01,0x70,0x57,0xe2, -0x9f,0x01,0x00,0x0a,0x00,0x30,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3, -0xf8,0xff,0xff,0xba,0x88,0x76,0x9f,0xe5,0x80,0x86,0x9f,0xe5,0x02,0x00,0x00,0xea, -0x12,0x1a,0x00,0xeb,0x01,0x70,0x57,0xe2,0x95,0x01,0x00,0x0a,0x04,0x30,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0x64,0x26,0x9f,0xe5,0x01,0x0c,0x13,0xe3,0xf7,0xff,0xff,0x0a, -0x06,0x10,0x94,0xe7,0x00,0x30,0xa0,0xe3,0x08,0x70,0x92,0xe5,0x90,0x00,0xa0,0xe3, -0x05,0xa0,0x84,0xe0,0x02,0x80,0xa0,0xe1,0x10,0xc0,0x91,0xe5,0xb8,0x31,0xc1,0xe1, -0xb6,0x31,0xc1,0xe1,0xb4,0x31,0xc1,0xe1,0x0c,0x00,0x81,0xe5,0x0f,0x10,0xda,0xe5, -0x08,0x70,0x82,0xe5,0x20,0x00,0x82,0xe5,0x24,0xc0,0x82,0xe5,0x01,0x10,0x01,0xe2, -0x28,0x30,0x82,0xe5,0x2c,0x30,0x82,0xe5,0x10,0x30,0x92,0xe5,0x10,0x76,0x9f,0xe5, -0x01,0x3a,0x83,0xe1,0x10,0x30,0x82,0xe5,0x0c,0x36,0x9f,0xe5,0x00,0x30,0x82,0xe5, -0x02,0x00,0x00,0xea,0xf1,0x19,0x00,0xeb,0x01,0x70,0x57,0xe2,0x74,0x01,0x00,0x0a, -0x00,0x30,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3,0xf8,0xff,0xff,0xba, -0xdc,0x75,0x9f,0xe5,0xd4,0x85,0x9f,0xe5,0x02,0x00,0x00,0xea,0xe7,0x19,0x00,0xeb, -0x01,0x70,0x57,0xe2,0x6a,0x01,0x00,0x0a,0x04,0x30,0x98,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x0c,0x13,0xe3,0xf8,0xff,0xff,0x0a,0xb0,0x35,0x9f,0xe5,0xbc,0x75,0x9f,0xe5, -0x18,0x20,0x93,0xe5,0x07,0x00,0x94,0xe7,0x06,0x30,0x94,0xe7,0xcc,0x20,0x80,0xe5, -0x22,0x14,0xa0,0xe1,0x03,0x00,0xd3,0xe5,0x00,0x20,0xc3,0xe5,0x01,0x10,0xc3,0xe5, -0x00,0x00,0x50,0xe3,0x06,0x00,0x00,0x1a,0x05,0x10,0x84,0xe0,0x02,0x03,0xa0,0xe1, -0x0c,0x10,0xd1,0xe5,0x0a,0x10,0x81,0xe2,0x20,0x0f,0x81,0xe0,0xff,0x00,0x00,0xe2, -0x03,0x00,0xc3,0xe5,0x0b,0x10,0x40,0xe2,0x01,0x00,0x51,0xe3,0x0a,0x00,0xa0,0x83, -0x50,0x01,0x00,0x8a,0x02,0xc0,0xd3,0xe5,0x00,0x00,0x5c,0xe3,0x06,0x00,0x00,0x1a, -0x05,0x10,0x84,0xe0,0x02,0xc1,0xa0,0xe1,0x0d,0x10,0xd1,0xe5,0x10,0x10,0x81,0xe2, -0x2c,0xcf,0x81,0xe0,0xff,0xc0,0x0c,0xe2,0x02,0xc0,0xc3,0xe5,0x05,0x10,0x94,0xe7, -0x0c,0x00,0x60,0xe0,0x04,0x00,0xc3,0xe5,0x00,0x00,0x51,0xe3,0x08,0x10,0x83,0xe5, -0x22,0x2f,0xa0,0x01,0x01,0x20,0x02,0x02,0x01,0x20,0x82,0x02,0x02,0x10,0xa0,0x01, -0x08,0x20,0x83,0x05,0x05,0x50,0x84,0xe0,0x0e,0x30,0xd5,0xe5,0x00,0x00,0x53,0xe3, -0x03,0x10,0xa0,0x13,0x02,0x00,0x00,0x1a,0x02,0x00,0x51,0xe3,0x02,0x10,0xa0,0x13, -0x01,0x10,0xa0,0x03,0x03,0x00,0xa0,0xe3,0x5b,0x03,0x00,0xeb,0x06,0x30,0x94,0xe7, -0x01,0x10,0xa0,0xe3,0x07,0x20,0x94,0xe7,0x00,0x00,0xa0,0xe3,0x08,0xc0,0x93,0xe5, -0x1c,0x10,0x83,0xe5,0x2c,0x11,0xd3,0xe5,0xc0,0xc0,0x82,0xe5,0x05,0x30,0xd3,0xe5, -0xd0,0x10,0x82,0xe5,0xc4,0x30,0x82,0xe5,0x26,0x01,0x00,0xea,0x06,0xa0,0x94,0xe7, -0xff,0xc0,0xa0,0xe3,0x08,0x90,0x93,0xe5,0x03,0x80,0xa0,0xe1,0x0f,0x00,0xd2,0xe5, -0x10,0x70,0x9a,0xe5,0x0c,0xc0,0x8a,0xe5,0xb8,0x11,0xda,0xe1,0x01,0x00,0x00,0xe2, -0x08,0x90,0x83,0xe5,0xb6,0x21,0xda,0xe1,0x20,0xc0,0x83,0xe5,0x24,0x70,0x83,0xe5, -0x04,0x90,0xda,0xe5,0xb4,0xb1,0xda,0xe1,0x74,0x74,0x9f,0xe5,0x11,0x19,0x82,0xe0, -0x10,0xb0,0x8d,0xe5,0x01,0xb0,0xa0,0xe1,0xcb,0xcf,0xa0,0xe1,0x21,0x28,0xa0,0xe1, -0x08,0xb0,0x8d,0xe5,0x0c,0xc0,0x8d,0xe5,0x0c,0x90,0x9d,0xe5,0x10,0xc0,0x9d,0xe5, -0x09,0x28,0x82,0xe1,0x01,0x18,0x8c,0xe1,0x28,0x10,0x83,0xe5,0x2c,0x20,0x83,0xe5, -0x10,0x20,0x93,0xe5,0x00,0x0a,0x82,0xe1,0x38,0x24,0x9f,0xe5,0x10,0x00,0x83,0xe5, -0x00,0x20,0x83,0xe5,0x02,0x00,0x00,0xea,0x7c,0x19,0x00,0xeb,0x01,0x70,0x57,0xe2, -0x3c,0xff,0xff,0x0a,0x00,0x30,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3, -0xf8,0xff,0xff,0xba,0x08,0x74,0x9f,0xe5,0x00,0x84,0x9f,0xe5,0x02,0x00,0x00,0xea, -0x72,0x19,0x00,0xeb,0x01,0x70,0x57,0xe2,0x32,0xff,0xff,0x0a,0x04,0x30,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0xe4,0x23,0x9f,0xe5,0x01,0x0c,0x13,0xe3,0xf7,0xff,0xff,0x0a, -0x08,0x70,0x92,0xe5,0x00,0x30,0xa0,0xe3,0x90,0x00,0xa0,0xe3,0x20,0x10,0xa0,0xe3, -0x05,0xc0,0x84,0xe0,0x0c,0x00,0x8a,0xe5,0x10,0x30,0x8a,0xe5,0x02,0x80,0xa0,0xe1, -0xb6,0x31,0xca,0xe1,0xb8,0x31,0xca,0xe1,0x0f,0xc0,0xdc,0xe5,0xb4,0x11,0xca,0xe1, -0x08,0x70,0x82,0xe5,0x20,0x00,0x82,0xe5,0x01,0x00,0x0c,0xe2,0x24,0x30,0x82,0xe5, -0x28,0x10,0x82,0xe5,0x2c,0x30,0x82,0xe5,0x10,0x30,0x92,0xe5,0x90,0x73,0x9f,0xe5, -0x00,0x3a,0x83,0xe1,0x10,0x30,0x82,0xe5,0x8c,0x33,0x9f,0xe5,0x00,0x30,0x82,0xe5, -0x02,0x00,0x00,0xea,0x51,0x19,0x00,0xeb,0x01,0x70,0x57,0xe2,0x11,0xff,0xff,0x0a, -0x00,0x30,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3,0xf8,0xff,0xff,0xba, -0x5c,0x73,0x9f,0xe5,0x54,0x83,0x9f,0xe5,0x02,0x00,0x00,0xea,0x47,0x19,0x00,0xeb, -0x01,0x70,0x57,0xe2,0x07,0xff,0xff,0x0a,0x04,0x20,0x98,0xe5,0x01,0x00,0xa0,0xe3, -0x38,0x33,0x9f,0xe5,0x01,0x0c,0x12,0xe3,0xf7,0xff,0xff,0x0a,0x3c,0x73,0x9f,0xe5, -0x18,0x20,0x93,0xe5,0x38,0x03,0x9f,0xe5,0x07,0x10,0x94,0xe7,0x00,0x00,0x52,0xe1, -0xcc,0x20,0x81,0xe5,0xfb,0xfe,0xff,0x1a,0x06,0xb0,0x94,0xe7,0x01,0x00,0xa0,0xe3, -0x00,0x20,0xa0,0xe3,0xec,0x10,0xa0,0xe3,0x10,0x20,0x8a,0xe5,0x05,0xc0,0x84,0xe0, -0x08,0xb0,0x8d,0xe5,0x2c,0xb0,0x8b,0xe2,0x08,0x80,0x9d,0xe5,0x03,0x90,0xa0,0xe1, -0xb4,0x21,0xca,0xe1,0xb6,0x21,0xca,0xe1,0x08,0x00,0x88,0xe5,0x04,0x00,0xa0,0xe3, -0x28,0x00,0x88,0xe5,0xff,0x00,0xa0,0xe3,0xb8,0x21,0xca,0xe1,0x0c,0x10,0x8a,0xe5, -0x40,0xb0,0x83,0xe5,0x34,0x00,0x83,0xe5,0x10,0x20,0x83,0xe5,0x10,0x00,0x93,0xe5, -0x10,0x00,0x93,0xe5,0x0f,0xc0,0xdc,0xe5,0xb4,0x82,0x9f,0xe5,0x10,0x00,0x83,0xe5, -0xc0,0x02,0x9f,0xe5,0x01,0xc0,0x0c,0xe2,0xcc,0x20,0x83,0xe5,0x30,0x00,0x83,0xe5, -0x08,0x00,0x93,0xe5,0x08,0x00,0x83,0xe5,0x20,0x10,0x83,0xe5,0x24,0x20,0x83,0xe5, -0x28,0x20,0x83,0xe5,0x2c,0x20,0x83,0xe5,0x10,0x20,0x93,0xe5,0x0c,0xca,0x82,0xe1, -0x94,0x22,0x9f,0xe5,0x10,0xc0,0x83,0xe5,0x00,0x20,0x83,0xe5,0x02,0x00,0x00,0xea, -0x0e,0x19,0x00,0xeb,0x01,0x80,0x58,0xe2,0xce,0xfe,0xff,0x0a,0x00,0x30,0x99,0xe5, -0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3,0xf8,0xff,0xff,0xba,0x50,0x82,0x9f,0xe5, -0x48,0x92,0x9f,0xe5,0x02,0x00,0x00,0xea,0x04,0x19,0x00,0xeb,0x01,0x80,0x58,0xe2, -0xc4,0xfe,0xff,0x0a,0x04,0x30,0x99,0xe5,0x01,0x00,0xa0,0xe3,0x2c,0x22,0x9f,0xe5, -0x01,0x0c,0x13,0xe3,0xf7,0xff,0xff,0x0a,0x08,0x00,0x92,0xe5,0xab,0x30,0xa0,0xe3, -0x10,0x90,0x9a,0xe5,0x05,0x10,0x84,0xe0,0xb8,0xc1,0xda,0xe1,0x02,0x80,0xa0,0xe1, -0x0c,0x30,0x8a,0xe5,0x08,0x00,0x82,0xe5,0xb6,0x01,0xda,0xe1,0x20,0x30,0x82,0xe5, -0x24,0x90,0x82,0xe5,0x06,0x90,0x94,0xe7,0xb4,0xa1,0xda,0xe1,0x0f,0x10,0xd1,0xe5, -0x04,0x30,0xd9,0xe5,0x00,0xa0,0x8d,0xe5,0xe4,0xa1,0x9f,0xe5,0x1c,0x33,0x80,0xe0, -0x01,0x00,0x01,0xe2,0x04,0xa0,0x8d,0xe5,0x03,0x90,0xa0,0xe1,0xc9,0xaf,0xa0,0xe1, -0x23,0x18,0xa0,0xe1,0x10,0x90,0x8d,0xe5,0x14,0xa0,0x8d,0xe5,0x14,0xc0,0x9d,0xe5, -0x00,0xa0,0x9d,0xe5,0x0c,0x18,0x81,0xe1,0x03,0x38,0x8a,0xe1,0xb0,0xa1,0x9f,0xe5, -0x28,0x30,0x82,0xe5,0x2c,0x10,0x82,0xe5,0x10,0x30,0x92,0xe5,0x00,0x0a,0x83,0xe1, -0xb8,0x31,0x9f,0xe5,0x10,0x00,0x82,0xe5,0x00,0x30,0x82,0xe5,0x02,0x00,0x00,0xea, -0xd6,0x18,0x00,0xeb,0x01,0xa0,0x5a,0xe2,0x96,0xfe,0xff,0x0a,0x00,0x30,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3,0xf8,0xff,0xff,0xba,0x70,0x81,0x9f,0xe5, -0x68,0xa1,0x9f,0xe5,0x02,0x00,0x00,0xea,0xcc,0x18,0x00,0xeb,0x01,0x80,0x58,0xe2, -0x8c,0xfe,0xff,0x0a,0x04,0x30,0x9a,0xe5,0x01,0x00,0xa0,0xe3,0x01,0x0c,0x13,0xe3, -0xf8,0xff,0xff,0x0a,0x68,0x81,0x9f,0xe5,0x40,0xa1,0x9f,0xe5,0x02,0x00,0x00,0xea, -0xc2,0x18,0x00,0xeb,0x01,0x80,0x58,0xe2,0x82,0xfe,0xff,0x0a,0x30,0x20,0x9a,0xe5, -0x01,0x00,0xa0,0xe3,0x04,0x30,0x9a,0xe5,0x00,0x00,0x52,0xe3,0x00,0x30,0xa0,0xb3, -0x01,0x30,0x03,0xa2,0x00,0x00,0x53,0xe3,0xf4,0xff,0xff,0x0a,0x02,0x10,0xdb,0xe5, -0x01,0x00,0xdb,0xe5,0x08,0x90,0x9d,0xe5,0x03,0x20,0xdb,0xe5,0x01,0x18,0xa0,0xe1, -0x2c,0x30,0xd9,0xe5,0x00,0x14,0x81,0xe1,0x03,0x30,0x81,0xe1,0x02,0x2c,0x83,0xe1, -0xfc,0x30,0x9f,0xe5,0x03,0x00,0x52,0xe1,0x6e,0xfe,0xff,0x1a,0x52,0x20,0xdb,0xe5, -0x51,0x10,0xdb,0xe5,0x50,0x30,0xdb,0xe5,0x53,0x00,0xdb,0xe5,0x02,0x28,0xa0,0xe1, -0x06,0x80,0x94,0xe7,0x01,0x24,0x82,0xe1,0x03,0x30,0x82,0xe1,0x00,0x0c,0x83,0xe1, -0xad,0x18,0x00,0xeb,0x03,0x00,0xc8,0xe5,0x06,0x80,0x94,0xe7,0x03,0x30,0xd8,0xe5, -0x0b,0x30,0x43,0xe2,0x01,0x00,0x53,0xe3,0x00,0x30,0xa0,0x83,0x03,0x30,0xc8,0x85, -0x5c,0xfe,0xff,0x8a,0x5e,0x20,0xdb,0xe5,0x5d,0x10,0xdb,0xe5,0x5c,0x30,0xdb,0xe5, -0x5f,0x00,0xdb,0xe5,0x02,0x28,0xa0,0xe1,0x01,0x24,0x82,0xe1,0x03,0x30,0x82,0xe1, -0x00,0x0c,0x83,0xe1,0x9c,0x18,0x00,0xeb,0x04,0x00,0xc8,0xe5,0x06,0x30,0x94,0xe7, -0x03,0x10,0xd3,0xe5,0x04,0x20,0xd3,0xe5,0x02,0x20,0x81,0xe0,0x02,0x20,0xc3,0xe5, -0x65,0x20,0xdb,0xe5,0x0f,0x10,0x02,0xe2,0x22,0x22,0x81,0xe0,0x05,0x20,0xc3,0xe5, -0x05,0x20,0x94,0xe7,0x00,0x00,0x52,0xe3,0x08,0x20,0x83,0xe5,0x04,0x00,0x00,0x1a, -0x06,0x20,0xdb,0xe5,0x01,0x00,0x12,0xe3,0x01,0x20,0xa0,0x03,0x02,0x20,0xa0,0x13, -0x08,0x20,0x83,0xe5,0x01,0x20,0xa0,0xe3,0x08,0x10,0x93,0xe5,0x2c,0x21,0xc3,0xe5, -0xc3,0xfe,0xff,0xea,0x03,0x00,0xa0,0xe3,0x1c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x58,0xc3,0x00,0x00,0xb0,0x03,0x00,0x00,0xc4,0x10,0x00,0x00,0x4d,0x00,0x60,0x01, -0x00,0x80,0x00,0x70,0xa0,0x86,0x01,0x00,0x00,0x01,0x00,0xc0,0x00,0x01,0x30,0xf4, -0x40,0x00,0x00,0x00,0x4f,0x4e,0x46,0x49,0x04,0x00,0x00,0xa4,0x00,0x01,0x00,0xe0, -0x00,0x01,0x88,0x84,0x20,0xa1,0x07,0x00,0x03,0x20,0x10,0xe2,0xf0,0x0f,0x2d,0xe9, -0x03,0x20,0x82,0x12,0x18,0xd0,0x4d,0xe2,0xa0,0x86,0xa0,0xe1,0x20,0x51,0xa0,0xe1, -0x0c,0x20,0x8d,0x15,0xa0,0x72,0xa0,0xe1,0x10,0x20,0x8d,0x15,0xa0,0x63,0xa0,0xe1, -0xf4,0x20,0x9f,0xe5,0x20,0x44,0xa0,0xe1,0xf0,0x30,0x9f,0xe5,0x20,0xc5,0xa0,0xe1, -0x14,0x10,0x8d,0xe5,0x07,0x10,0xa0,0x03,0x04,0x20,0x8d,0xe5,0x20,0xb6,0xa0,0xe1, -0x04,0xa0,0x9d,0xe5,0x03,0x30,0x8f,0xe0,0xd4,0x90,0x9f,0xe5,0x01,0x80,0x08,0xe2, -0x0c,0x10,0x8d,0x05,0x07,0x50,0x05,0xe2,0x0a,0x00,0x83,0xe0,0x0c,0xa0,0x9d,0xe5, -0x10,0x10,0x8d,0x05,0x09,0x10,0x83,0xe0,0x08,0x80,0x8d,0xe5,0x01,0x60,0x06,0xe2, -0x04,0xa0,0xc1,0xe5,0x03,0x40,0x04,0xe2,0x08,0xa0,0x9d,0xe5,0x03,0xc0,0x0c,0xe2, -0x01,0xb0,0x0b,0xe2,0x08,0x50,0x81,0xe5,0x05,0x60,0xc1,0xe5,0x03,0x70,0x07,0xe2, -0x0f,0xa0,0xc1,0xe5,0x00,0x80,0xa0,0xe3,0x04,0xa0,0x9d,0xe5,0x0c,0x40,0xc1,0xe5, -0x0d,0xc0,0xc1,0xe5,0x0e,0xb0,0xc1,0xe5,0x12,0x10,0xa0,0xe3,0x0a,0x10,0xc3,0xe7, -0x70,0x10,0x9f,0xe5,0x09,0x70,0x83,0xe7,0x0c,0x80,0xc0,0xe5,0x04,0x10,0x80,0xe5, -0x02,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5,0x14,0x10,0x9d,0xe5,0x0d,0x80,0xc0,0xe5, -0x54,0x20,0x9f,0xe5,0x00,0x00,0x81,0xe5,0x01,0x00,0xa0,0xe3,0x4c,0x10,0x9f,0xe5, -0x02,0x20,0x93,0xe7,0x01,0x00,0xc3,0xe7,0x10,0x30,0x9d,0xe5,0xa0,0x70,0x82,0xe5, -0xa8,0x60,0x82,0xe5,0xa4,0x30,0x82,0xe5,0xac,0x50,0x82,0xe5,0x08,0xa0,0x9d,0xe5, -0xb0,0x40,0x82,0xe5,0xb4,0xc0,0x82,0xe5,0xb8,0xb0,0x82,0xe5,0xbc,0xa0,0x82,0xe5, -0x18,0xd0,0x8d,0xe2,0xf0,0x0f,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0xb4,0x10,0x00,0x00, -0xfc,0xba,0x00,0x00,0xb0,0x03,0x00,0x00,0x01,0x00,0x02,0x14,0x40,0x00,0x00,0x00, -0xac,0x03,0x00,0x00,0x40,0x30,0x9f,0xe5,0x40,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x02,0x10,0x83,0xe0,0x08,0x10,0x91,0xe5,0x04,0x00,0x51,0xe3,0x00,0x00,0xa0,0x83, -0x1e,0xff,0x2f,0x81,0x02,0x30,0x93,0xe7,0x02,0x00,0x53,0xe3,0x04,0x00,0x00,0x8a, -0xd0,0x00,0xd0,0xe1,0x00,0x00,0x50,0xe3,0x00,0x00,0xa0,0xd3,0x01,0x00,0xa0,0xc3, -0x1e,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x04,0xba,0x00,0x00, -0xb0,0x03,0x00,0x00,0x1c,0x30,0x9f,0xe5,0x1c,0x00,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x00,0x30,0x93,0xe7,0x02,0x00,0xd3,0xe5,0x00,0x00,0x81,0xe5,0x03,0x30,0xd3,0xe5, -0x00,0x30,0x82,0xe5,0x1e,0xff,0x2f,0xe1,0xb4,0xb9,0x00,0x00,0xc4,0x10,0x00,0x00, -0xf0,0x45,0x2d,0xe9,0x1c,0xd0,0x4d,0xe2,0x1c,0x41,0x9f,0xe5,0x04,0xc0,0x8d,0xe2, -0x18,0x61,0x9f,0xe5,0x18,0x81,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x06,0x70,0x94,0xe7, -0x06,0xa0,0x84,0xe0,0x08,0x80,0x84,0xe0,0x0f,0x00,0xb8,0xe8,0x1c,0x50,0x97,0xe5, -0x00,0x80,0x98,0xe5,0x02,0x00,0x55,0xe3,0x0f,0x00,0xac,0xe8,0x00,0x80,0x8c,0xe5, -0x02,0x00,0x00,0x0a,0x05,0x00,0xa0,0xe1,0x1c,0xd0,0x8d,0xe2,0xf0,0x85,0xbd,0xe8, -0xe0,0x30,0x9f,0xe5,0x30,0x20,0x93,0xe5,0x00,0x00,0x52,0xe3,0x13,0x00,0x00,0xba, -0x08,0x20,0x93,0xe5,0x01,0x10,0xa0,0xe3,0x1c,0x10,0x87,0xe5,0x01,0x04,0x12,0xe3, -0x09,0x00,0x00,0x0a,0xd4,0x30,0x93,0xe5,0x23,0x1c,0xb0,0xe1,0x16,0x00,0x00,0x0a, -0x04,0x30,0xa0,0xe3,0x1c,0x30,0x87,0xe5,0xac,0x30,0x9f,0xe5,0x03,0x30,0x94,0xe7, -0xd8,0x10,0x93,0xe5,0x01,0x10,0x81,0xe2,0xd8,0x10,0x83,0xe5,0x06,0x30,0x94,0xe7, -0x90,0x10,0x9f,0xe5,0x1c,0x50,0x93,0xe5,0x08,0x20,0x81,0xe5,0xe4,0xff,0xff,0xea, -0x20,0x00,0x97,0xe5,0xc8,0x17,0x00,0xeb,0x80,0x30,0x9f,0xe5,0x03,0x00,0x50,0xe1, -0x00,0x30,0x9a,0x95,0x03,0x30,0xa0,0x83,0x00,0x20,0x9a,0x85,0x03,0x50,0xa0,0x81, -0x1c,0x50,0x93,0x95,0x1c,0x30,0x82,0x85,0xd9,0xff,0xff,0xea,0x28,0x00,0x97,0xe5, -0x23,0x34,0xa0,0xe1,0x18,0xc0,0x8d,0xe2,0x1f,0x10,0x03,0xe2,0x00,0x31,0x8c,0xe0, -0x14,0x30,0x13,0xe5,0x01,0x00,0x53,0xe1,0x05,0x30,0xa0,0x03,0x1c,0x30,0x87,0x05, -0x00,0x00,0x51,0xe3,0xe4,0xff,0xff,0x0a,0x2c,0x30,0x9f,0xe5,0x03,0x30,0x94,0xe7, -0xe0,0xc0,0x93,0xe5,0xdc,0x00,0x93,0xe5,0x0c,0x00,0x51,0xe1,0x01,0x00,0x80,0xe2, -0xe0,0x10,0x83,0x85,0xdc,0x00,0x83,0xe5,0xdb,0xff,0xff,0xea,0x78,0xb9,0x00,0x00, -0xc4,0x10,0x00,0x00,0xfc,0xf0,0xff,0xff,0x00,0x80,0x00,0x70,0x40,0x00,0x00,0x00, -0x20,0xa1,0x07,0x00,0xf0,0x4f,0x2d,0xe9,0x64,0xd0,0x4d,0xe2,0x04,0x55,0x9f,0xe5, -0x04,0x35,0x9f,0xe5,0x04,0x95,0x9f,0xe5,0x05,0x50,0x8f,0xe0,0x1c,0x20,0x8d,0xe5, -0x2c,0x30,0x8d,0xe5,0x03,0x30,0x95,0xe7,0x09,0x20,0x85,0xe0,0x08,0x70,0x92,0xe5, -0x18,0x90,0x8d,0xe5,0xd4,0x20,0x93,0xe5,0x00,0x00,0x57,0xe3,0x01,0x20,0x82,0xe2, -0xd4,0x20,0x83,0xe5,0x0d,0x00,0x00,0x1a,0xd4,0xc4,0x9f,0xe5,0x0c,0x60,0xd5,0xe7, -0x3c,0xc0,0x8d,0xe5,0x01,0x00,0x56,0xe3,0x86,0x00,0x00,0x0a,0x00,0x00,0x56,0xe3, -0x06,0x00,0x00,0x1a,0xbc,0xc4,0x9f,0xe5,0xbc,0x34,0x9f,0xe5,0x38,0xc0,0x8d,0xe5, -0x03,0x40,0x95,0xe7,0x0c,0xc0,0x95,0xe7,0x28,0x40,0x8c,0xe5,0x07,0x00,0x00,0xea, -0xa0,0xe4,0x9f,0xe5,0x2c,0x20,0x9d,0xe5,0x0e,0xc0,0x95,0xe7,0x02,0x30,0x95,0xe7, -0x38,0xe0,0x8d,0xe5,0x28,0x70,0x8c,0xe5,0xc8,0x70,0x83,0xe5,0x28,0x40,0x9c,0xe5, -0x03,0x20,0xdc,0xe5,0x01,0x80,0xa0,0xe3,0x08,0xe0,0x9c,0xe5,0x01,0x18,0xa0,0xe1, -0x00,0x78,0xa0,0xe1,0x74,0x34,0x9f,0xe5,0x21,0x68,0xa0,0xe1,0x60,0x90,0x8d,0xe2, -0x18,0x82,0xa0,0xe1,0x68,0x24,0x9f,0xe5,0x02,0x00,0x5e,0xe3,0x27,0x78,0xa0,0xe1, -0x00,0xe0,0xa0,0xe3,0xa8,0xa5,0xa0,0xe1,0x02,0x20,0x85,0xe0,0x0c,0xe0,0x8c,0xe5, -0x07,0x00,0x92,0xe8,0x0a,0xb1,0x89,0xe0,0x01,0xa0,0x48,0xe2,0xb4,0xe1,0xcc,0xe1, -0x30,0x80,0xa0,0xe3,0x1c,0xe0,0x9d,0xe5,0x54,0x90,0x8d,0xe2,0x10,0x80,0x8c,0xe5, -0xb6,0x61,0xcc,0xe1,0xb8,0x71,0xcc,0xe1,0x07,0x00,0x89,0xe8,0x40,0xe0,0x83,0xe5, -0x34,0xa0,0x83,0xe5,0x44,0xa0,0x8d,0xe2,0x18,0x34,0x9f,0xe5,0x0c,0x80,0x1b,0xe5, -0x08,0xe4,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x0f,0x00,0x93,0xe8,0x02,0x86,0x88,0x03, -0x01,0x00,0x54,0xe3,0x10,0x80,0x8e,0xe5,0x0f,0x00,0x8a,0xe8,0x10,0x10,0x9e,0xe5, -0x00,0xe0,0xa0,0x03,0xc2,0x15,0x81,0xe3,0x03,0x11,0x81,0x03,0x07,0x00,0x00,0x0a, -0x02,0x30,0x44,0xe2,0x01,0x00,0x53,0xe3,0x60,0x00,0x8d,0x92,0x10,0x10,0x9e,0x85, -0x04,0x41,0x80,0x90,0x00,0xe0,0xa0,0x83,0x1c,0xe0,0x14,0x95,0x01,0xe0,0x8e,0x93, -0xb8,0x33,0x9f,0xe5,0x18,0x20,0x9d,0xe5,0xbc,0x43,0x9f,0xe5,0x10,0x10,0x83,0xe5, -0x03,0x80,0xa0,0xe1,0xb4,0x13,0x9f,0xe5,0x02,0x00,0x85,0xe0,0xcc,0xe0,0x83,0xe5, -0xac,0x23,0x9f,0xe5,0x30,0x10,0x83,0xe5,0x08,0x10,0x93,0xe5,0x0f,0xe0,0xd0,0xe5, -0x08,0x10,0x83,0xe5,0x00,0x10,0xa0,0xe3,0x20,0x10,0x83,0xe5,0x30,0x10,0xa0,0xe3, -0x24,0x10,0x83,0xe5,0x01,0xe0,0x0e,0xe2,0x04,0x10,0xdc,0xe5,0x17,0x61,0x86,0xe0, -0x26,0x18,0xa0,0xe1,0x06,0xa0,0xa0,0xe1,0xca,0xbf,0xa0,0xe1,0x06,0x68,0xa0,0xe1, -0x0b,0x18,0x81,0xe1,0x28,0x60,0x83,0xe5,0x2c,0x10,0x83,0xe5,0x05,0x00,0xdc,0xe5, -0x10,0x10,0x93,0xe5,0x01,0x00,0x40,0xe2,0x0f,0x00,0x00,0xe2,0x0e,0x1a,0x81,0xe1, -0x02,0x20,0x80,0xe1,0x10,0x10,0x83,0xe5,0x00,0x20,0x83,0xe5,0x02,0x00,0x00,0xea, -0x2a,0x17,0x00,0xeb,0x01,0x40,0x54,0xe2,0x17,0x00,0x00,0x0a,0x00,0x30,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3,0xf8,0xff,0xff,0xba,0x18,0x43,0x9f,0xe5, -0x08,0x63,0x9f,0xe5,0x02,0x00,0x00,0xea,0x20,0x17,0x00,0xeb,0x01,0x40,0x54,0xe2, -0x0d,0x00,0x00,0x0a,0x04,0x30,0x96,0xe5,0x01,0x00,0xa0,0xe3,0x01,0x0c,0x13,0xe3, -0xf8,0xff,0xff,0x0a,0x38,0x20,0x9d,0xe5,0x02,0x30,0xa0,0xe3,0x00,0xb0,0xa0,0xe3, -0x02,0x40,0x95,0xe7,0x1c,0x30,0x84,0xe5,0x0b,0x17,0x00,0xeb,0x24,0xb0,0x84,0xe5, -0x20,0x00,0x84,0xe5,0x0b,0x00,0xa0,0xe1,0x00,0x00,0x00,0xea,0x03,0x00,0xa0,0xe3, -0x64,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0xb4,0x32,0x9f,0xe5,0x01,0x18,0xa0,0xe1, -0xa0,0xe2,0x9f,0xe5,0x00,0x08,0xa0,0xe1,0xa0,0x42,0x9f,0xe5,0x03,0xb0,0xa0,0xe3, -0x03,0x30,0x85,0xe0,0x30,0x90,0xa0,0xe3,0x14,0x30,0x8d,0xe5,0x21,0x88,0xa0,0xe1, -0x90,0x32,0x9f,0xe5,0x20,0xa8,0xa0,0xe1,0x44,0x10,0x8d,0xe2,0x38,0xe0,0x8d,0xe5, -0x54,0x00,0x8d,0xe2,0x0e,0x20,0x85,0xe0,0x03,0x30,0x85,0xe0,0x10,0x00,0x8d,0xe5, -0x08,0x10,0x8d,0xe5,0x30,0x20,0x8d,0xe5,0x0c,0x30,0x8d,0xe5,0x34,0x50,0x8d,0xe5, -0x30,0x30,0x9d,0xe5,0x14,0x50,0x9d,0xe5,0x00,0xc0,0x93,0xe5,0x07,0x00,0x95,0xe8, -0x01,0x50,0xa0,0xe3,0x03,0x30,0xdc,0xe5,0x08,0xe0,0x9c,0xe5,0x28,0x60,0x8c,0xe5, -0x0c,0x70,0x8c,0xe5,0x15,0x33,0xa0,0xe1,0x02,0x00,0x5e,0xe3,0x60,0x50,0x8d,0xe2, -0x10,0x90,0x8c,0xe5,0xa3,0xe5,0xa0,0xe1,0xb4,0x71,0xcc,0xe1,0xb6,0x81,0xcc,0xe1, -0x01,0x30,0x43,0xe2,0x0e,0xe1,0x85,0xe0,0x10,0x50,0x9d,0xe5,0xb8,0xa1,0xcc,0xe1, -0x07,0x00,0x85,0xe8,0x1c,0x00,0x9d,0xe5,0x0c,0x50,0x9d,0xe5,0x40,0x00,0x84,0xe5, -0x34,0x30,0x84,0xe5,0x0c,0xe0,0x1e,0xe5,0x0f,0x00,0x95,0xe8,0x02,0xe6,0x8e,0x03, -0x01,0x00,0x56,0xe3,0x10,0xe0,0x84,0xe5,0x08,0xe0,0x9d,0xe5,0x0f,0x00,0x8e,0xe8, -0x60,0x00,0x8d,0x12,0x10,0x30,0x94,0xe5,0x06,0x21,0x80,0x10,0x00,0x20,0xa0,0x03, -0x1c,0x20,0x12,0x15,0xc2,0x35,0x83,0xe3,0xd0,0xe1,0x9f,0xe5,0x03,0x31,0x83,0x03, -0x10,0x30,0x84,0xe5,0x01,0x20,0x82,0x13,0x34,0x10,0x9d,0xe5,0x18,0x50,0x9d,0xe5, -0xcc,0x20,0x84,0xe5,0x30,0xe0,0x84,0xe5,0x05,0x30,0x81,0xe0,0x08,0x20,0x94,0xe5, -0x0f,0x00,0xd3,0xe5,0xa8,0x31,0x9f,0xe5,0x08,0x20,0x84,0xe5,0x01,0x00,0x00,0xe2, -0x20,0x70,0x84,0xe5,0x04,0x00,0x8d,0xe5,0x24,0x90,0x84,0xe5,0x04,0x10,0xdc,0xe5, -0x84,0x51,0x9f,0xe5,0x1a,0xe1,0x88,0xe0,0x0e,0x00,0xa0,0xe1,0xc0,0x1f,0xa0,0xe1, -0x2e,0x28,0xa0,0xe1,0x20,0x00,0x8d,0xe5,0x24,0x10,0x8d,0xe5,0x0e,0x18,0xa0,0xe1, -0x24,0xe0,0x9d,0xe5,0x04,0x00,0x9d,0xe5,0x28,0x10,0x84,0xe5,0x0e,0x28,0x82,0xe1, -0x2c,0x20,0x84,0xe5,0x05,0x20,0xdc,0xe5,0x10,0x10,0x94,0xe5,0x01,0x20,0x42,0xe2, -0x0f,0x20,0x02,0xe2,0x00,0x1a,0x81,0xe1,0x03,0x30,0x82,0xe1,0x10,0x10,0x84,0xe5, -0x00,0x30,0x84,0xe5,0x02,0x00,0x00,0xea,0xa8,0x16,0x00,0xeb,0x01,0x50,0x55,0xe2, -0x95,0xff,0xff,0x0a,0x00,0x30,0x94,0xe5,0x01,0x00,0xa0,0xe3,0x00,0x00,0x53,0xe3, -0xf8,0xff,0xff,0xba,0x10,0x51,0x9f,0xe5,0x02,0x00,0x00,0xea,0x9f,0x16,0x00,0xeb, -0x01,0x50,0x55,0xe2,0x8c,0xff,0xff,0x0a,0x04,0x30,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x0c,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x30,0x30,0x9d,0xe5,0x00,0x50,0x93,0xe5, -0x02,0x30,0xa0,0xe3,0x1c,0x30,0x85,0xe5,0x8b,0x16,0x00,0xeb,0x24,0x70,0x85,0xe5, -0x20,0x00,0x85,0xe5,0x95,0xfe,0xff,0xeb,0x02,0x00,0x50,0xe3,0xfc,0xff,0xff,0x0a, -0x04,0x00,0x50,0xe3,0x11,0x00,0x00,0x0a,0x01,0x00,0x50,0xe3,0x05,0x00,0x50,0x13, -0x15,0x00,0x00,0x0a,0x03,0x00,0x50,0xe3,0x20,0x00,0x00,0x0a,0x01,0xb0,0x5b,0xe2, -0x01,0x60,0x86,0xe2,0x8d,0xff,0xff,0x1a,0x04,0x00,0x56,0xe3,0x34,0x50,0x9d,0xe5, -0x0e,0x00,0x00,0x1a,0x2c,0x90,0x9d,0xe5,0x0b,0x00,0xa0,0xe1,0x09,0x30,0x95,0xe7, -0xd8,0x20,0x93,0xe5,0x01,0x20,0x82,0xe2,0xd8,0x20,0x83,0xe5,0x6b,0xff,0xff,0xea, -0x34,0x20,0x9d,0xe5,0x2c,0x10,0x9d,0xe5,0x01,0x30,0x92,0xe7,0xd8,0x20,0x93,0xe5, -0x01,0x20,0x42,0xe2,0xd8,0x20,0x83,0xe5,0xeb,0xff,0xff,0xea,0x34,0x50,0x9d,0xe5, -0x38,0x90,0x9d,0xe5,0x00,0x00,0xa0,0xe3,0x2c,0x10,0x9d,0xe5,0x3c,0xc0,0x9d,0xe5, -0x09,0x30,0x95,0xe7,0x01,0x20,0x95,0xe7,0x0c,0x00,0xc5,0xe7,0x28,0x10,0x9f,0xe5, -0x28,0x30,0x93,0xe5,0x01,0x30,0x85,0xe7,0xc8,0x30,0x82,0xe5,0x57,0xff,0xff,0xea, -0x09,0x00,0xa0,0xe3,0x55,0xff,0xff,0xea,0x38,0xb8,0x00,0x00,0x40,0x00,0x00,0x00, -0xb0,0x03,0x00,0x00,0xac,0x03,0x00,0x00,0xc4,0x10,0x00,0x00,0xa8,0x03,0x00,0x00, -0x00,0x80,0x00,0x70,0xf0,0xf0,0xff,0xff,0xe0,0xf0,0xff,0xff,0xa0,0x86,0x01,0x00, -0x04,0x00,0x00,0xa4,0x00,0x01,0x88,0xe6,0x10,0x40,0x2d,0xe9,0x0d,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x75,0x02,0x00,0xeb,0x08,0x00,0x9f,0xe5,0x00,0x10,0xa0,0xe3, -0x10,0x40,0xbd,0xe8,0xa7,0xfb,0xff,0xea,0x4d,0x00,0x60,0x01,0x34,0x36,0x9f,0xe5, -0x34,0x26,0x9f,0xe5,0xf0,0x41,0x2d,0xe9,0x01,0x50,0xa0,0xe1,0x03,0x30,0x8f,0xe0, -0x08,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1,0x04,0x70,0x8d,0xe2,0x02,0x30,0x93,0xe7, -0x0d,0x60,0xa0,0xe1,0x00,0x81,0x93,0xe7,0x08,0x00,0xa0,0xe1,0xf1,0x01,0x00,0xeb, -0x08,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x00,0x20,0xa0,0xe3,0x7f,0x01,0x00,0xeb, -0x12,0x30,0xa0,0xe3,0x04,0x30,0x8d,0xe5,0x16,0x30,0xa0,0xe3,0x00,0x30,0x8d,0xe5, -0x05,0x00,0x54,0xe3,0x04,0xf1,0x8f,0x90,0x1f,0x00,0x00,0xea,0x91,0x00,0x00,0xea, -0xb3,0x00,0x00,0xea,0x47,0x01,0x00,0xea,0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea, -0x1c,0x00,0x00,0xea,0x01,0x30,0x45,0xe2,0x01,0x00,0x53,0xe3,0x57,0x01,0x00,0x9a, -0x03,0x00,0x55,0xe3,0x14,0x00,0x00,0x1a,0x07,0x32,0xa0,0xe3,0x68,0x08,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x68,0x28,0x83,0xe5,0x6c,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x6c,0x28,0x83,0xe5,0x00,0x00,0xa0,0xe3, -0x08,0xd0,0x8d,0xe2,0xf0,0x81,0xbd,0xe8,0x07,0x32,0xa0,0xe3,0x70,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x70,0x28,0x83,0xe5,0x74,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x74,0x28,0x83,0xe5,0x88,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x88,0x28,0x83,0xe5,0x90,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x90,0x28,0x83,0xe5,0xf8,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0xf8,0x28,0x83,0xe5,0xfc,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xfc,0x28,0x83,0xe5,0x00,0x09,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x00,0x29,0x83,0xe5,0xa8,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xa8,0x28,0x83,0xe5,0x94,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x94,0x28,0x83,0xe5,0xb4,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xb4,0x28,0x83,0xe5,0xb8,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0xb8,0x28,0x83,0xe5,0x8c,0xff,0xff,0xea,0x07,0x32,0xa0,0xe3,0x02,0x50,0x45,0xe2, -0x70,0x08,0x93,0xe5,0x01,0x00,0x55,0xe3,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x70,0x28,0x83,0xe5,0x74,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x74,0x28,0x83,0xe5,0x74,0xff,0xff,0x8a,0xf4,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5, -0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1, -0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xf4,0x28,0x83,0xe5, -0x69,0xff,0xff,0xea,0x07,0x32,0xa0,0xe3,0x04,0x00,0x55,0xe3,0x01,0x00,0x55,0x13, -0x70,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3, -0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3, -0x01,0x2a,0x82,0xe1,0x70,0x28,0x83,0xe5,0x74,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5, -0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1, -0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x74,0x28,0x83,0xe5, -0x88,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3, -0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3, -0x01,0x2a,0x82,0xe1,0x88,0x28,0x83,0xe5,0x90,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5, -0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1, -0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x90,0x28,0x83,0xe5, -0xf8,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3, -0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3, -0x01,0x2a,0x82,0xe1,0xf8,0x28,0x83,0xe5,0x00,0x09,0x93,0xe5,0x04,0x20,0x9d,0xe5, -0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1, -0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x00,0x29,0x83,0xe5, -0xa8,0x08,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3, -0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3, -0x01,0x2a,0x82,0xe1,0xa8,0x28,0x83,0xe5,0x1d,0x00,0x00,0x1a,0x94,0x08,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x94,0x28,0x83,0xe5,0xb4,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xb4,0x28,0x83,0xe5,0xb8,0x08,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0xb8,0x28,0x83,0xe5,0x01,0x50,0x45,0xe2,0x01,0x00,0x55,0xe3,0xfe,0xfe,0xff,0x8a, -0x07,0x32,0xa0,0xe3,0x84,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5,0x00,0x10,0x96,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x84,0x28,0x83,0xe5,0xf4,0x08,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x96,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0xf4,0x28,0x83,0xe5,0xfc,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5,0x00,0x10,0x96,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0xfc,0x28,0x83,0xe5,0x04,0x09,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x96,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x04,0x29,0x83,0xe5,0xd4,0xfe,0xff,0xea,0x07,0x32,0xa0,0xe3,0xfc,0x08,0x93,0xe5, -0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0xfc,0x28,0x83,0xe5,0x00,0x09,0x93,0xe5,0x04,0x20,0x9d,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x00,0x29,0x83,0xe5,0xbe,0xfe,0xff,0xea, -0x07,0x32,0xa0,0xe3,0x70,0x08,0x93,0xe5,0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5, -0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2,0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2, -0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1,0x70,0x28,0x83,0xe5,0x74,0x08,0x93,0xe5, -0x00,0x20,0x97,0xe5,0x00,0x10,0x9d,0xe5,0x1f,0x0a,0xc0,0xe3,0x1f,0x20,0x02,0xe2, -0x02,0x26,0x80,0xe1,0x1f,0x10,0x01,0xe2,0x1f,0x26,0xc2,0xe3,0x01,0x2a,0x82,0xe1, -0x74,0x28,0x83,0xe5,0xa8,0xfe,0xff,0xea,0xd4,0xb2,0x00,0x00,0x10,0x00,0x00,0x00, -0x00,0x00,0x51,0xe3,0xf0,0x00,0x2d,0xe9,0x18,0xd0,0x4d,0xe2,0x67,0x00,0x00,0x0a, -0x00,0x30,0x90,0xe5,0x04,0x00,0x53,0xe3,0x2c,0x00,0x00,0x0a,0x04,0x40,0x80,0xe2, -0x00,0x50,0xa0,0xe3,0x07,0x00,0x00,0xea,0x03,0x00,0x56,0xe3,0x04,0xc0,0xa0,0x11, -0x07,0x00,0x00,0x0a,0x05,0x00,0x51,0xe1,0x09,0x00,0x00,0x9a,0x04,0x30,0x94,0xe4, -0x04,0x00,0x53,0xe3,0x21,0x00,0x00,0x0a,0x03,0x60,0x13,0xe2,0x04,0xc0,0xa0,0xe1, -0xf4,0xff,0xff,0x1a,0x00,0x00,0x53,0xe3,0x01,0x50,0x85,0x02,0x05,0x00,0x51,0xe1, -0xf5,0xff,0xff,0x8a,0x00,0x10,0x9c,0xe5,0x04,0x00,0x51,0xe3,0x17,0x00,0x00,0x0a, -0x00,0x30,0xa0,0xe3,0x03,0x70,0xa0,0xe1,0x04,0x30,0x8d,0xe5,0x03,0x30,0x01,0xe2, -0x02,0x00,0x53,0xe3,0x0e,0x00,0x00,0x0a,0x03,0x00,0x53,0xe3,0x20,0x00,0x00,0x0a, -0x01,0x00,0x53,0xe3,0x10,0x00,0x00,0x0a,0x0c,0x00,0x11,0xe3,0x18,0x10,0x8d,0x02, -0x07,0x31,0x81,0x00,0x01,0x70,0x47,0x02,0x14,0xc0,0x13,0x05,0x00,0x00,0x5c,0xe3, -0x06,0x00,0x00,0x0a,0x00,0x10,0x9c,0xe5,0x03,0x30,0x01,0xe2,0x02,0x00,0x53,0xe3, -0xf0,0xff,0xff,0x1a,0x04,0xc0,0x8c,0xe2,0x00,0x00,0x5c,0xe3,0xf8,0xff,0xff,0x1a, -0x18,0xd0,0x8d,0xe2,0xf0,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x21,0x4d,0xa0,0xe1, -0xa1,0x1a,0xa0,0xe1,0x07,0x43,0x84,0xe2,0x1f,0x10,0x01,0xe2,0x05,0x40,0x84,0xe2, -0x00,0x50,0x52,0xe2,0x01,0x50,0xa0,0x13,0x04,0x41,0xa0,0xe1,0x04,0xc0,0x8c,0xe2, -0x00,0x60,0x94,0xe5,0x13,0x31,0xc6,0xe1,0x15,0x11,0x83,0xe1,0x00,0x10,0x84,0xe5, -0xec,0xff,0xff,0xea,0x01,0x70,0x87,0xe2,0x21,0x61,0xb0,0xe1,0x18,0x10,0x8d,0xe2, -0x07,0x31,0x81,0xe0,0x04,0xc0,0x8c,0xe2,0x14,0xc0,0x03,0xe5,0x1d,0x00,0x00,0x0a, -0x00,0x30,0x90,0xe5,0x08,0x00,0x53,0xe3,0x17,0x00,0x00,0x0a,0x04,0x10,0x80,0xe2, -0x00,0x40,0xa0,0xe3,0x07,0x00,0x00,0xea,0x03,0x00,0x55,0xe3,0x01,0xc0,0xa0,0x11, -0x07,0x00,0x00,0x0a,0x04,0x00,0x56,0xe1,0x09,0x00,0x00,0x9a,0x04,0x30,0x91,0xe4, -0x08,0x00,0x53,0xe3,0x0d,0x00,0x00,0x0a,0x03,0x50,0x13,0xe2,0x01,0xc0,0xa0,0xe1, -0xf4,0xff,0xff,0x1a,0x00,0x00,0x53,0xe3,0x01,0x40,0x84,0x02,0x04,0x00,0x56,0xe1, -0xf5,0xff,0xff,0x8a,0x00,0x30,0x9c,0xe5,0x04,0x00,0x53,0xe3,0x04,0x30,0xbc,0x05, -0x08,0x00,0x53,0xe3,0xc4,0xff,0xff,0x1a,0xcc,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe1, -0x00,0x30,0x9c,0xe5,0xf9,0xff,0xff,0xea,0x00,0xc0,0xa0,0xe1,0xf4,0xff,0xff,0xea, -0x00,0xc0,0xa0,0xe1,0xaa,0xff,0xff,0xea,0x00,0x00,0x51,0xe3,0xf0,0x01,0x2d,0xe9, -0x00,0x30,0xa0,0xe3,0x1c,0xd0,0x4d,0xe2,0x04,0x30,0x8d,0xe5,0x69,0x00,0x00,0x0a, -0x00,0x20,0x90,0xe5,0x04,0x00,0x52,0xe3,0x39,0x00,0x00,0x0a,0x04,0xc0,0x80,0xe2, -0x07,0x00,0x00,0xea,0x03,0x00,0x55,0xe3,0x0c,0x40,0xa0,0x11,0x07,0x00,0x00,0x0a, -0x01,0x00,0x53,0xe1,0x09,0x00,0x00,0x2a,0x04,0x20,0x9c,0xe4,0x04,0x00,0x52,0xe3, -0x2f,0x00,0x00,0x0a,0x03,0x50,0x12,0xe2,0x0c,0x40,0xa0,0xe1,0xf4,0xff,0xff,0x1a, -0x00,0x00,0x52,0xe3,0x01,0x30,0x83,0x02,0x01,0x00,0x53,0xe1,0xf5,0xff,0xff,0x3a, -0x00,0x30,0x94,0xe5,0x04,0x00,0x53,0xe3,0x25,0x00,0x00,0x0a,0x04,0x10,0xa0,0xe1, -0x00,0x60,0xa0,0xe3,0x07,0x00,0x00,0xea,0x0c,0x00,0x13,0xe3,0x18,0x20,0x8d,0x02, -0x06,0x31,0x82,0x00,0x01,0x60,0x46,0x02,0x14,0x10,0x13,0x05,0x00,0x00,0x51,0xe3, -0x1b,0x00,0x00,0x0a,0x00,0x30,0x91,0xe5,0x03,0x20,0x13,0xe2,0xf5,0xff,0xff,0x0a, -0x03,0x00,0x52,0xe3,0x19,0x00,0x00,0x0a,0xa3,0xc8,0xa0,0xe1,0x23,0x46,0xa0,0xe1, -0xa3,0x72,0xa0,0xe1,0x23,0x54,0xa0,0xe1,0x0f,0xc0,0x0c,0xe2,0x01,0x00,0x52,0xe3, -0x07,0xc3,0x8c,0xe2,0x1f,0x40,0x04,0xe2,0x20,0xc0,0x8c,0xe2,0x07,0x70,0x07,0xe2, -0x0c,0xc1,0xa0,0xe1,0x07,0x50,0x05,0xe2,0x00,0x20,0x9c,0xe5,0x30,0x00,0x00,0x0a, -0x23,0x31,0xa0,0xe1,0x32,0x84,0x05,0xe0,0x07,0x30,0x03,0xe2,0x03,0x00,0x58,0xe1, -0x2b,0x00,0x00,0x0a,0x04,0x10,0x81,0xe2,0x00,0x20,0x8c,0xe5,0x00,0x00,0x51,0xe3, -0xe3,0xff,0xff,0x1a,0x1c,0xd0,0x8d,0xe2,0xf0,0x01,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x01,0x60,0x86,0xe2,0x23,0x51,0xb0,0xe1,0x18,0x20,0x8d,0xe2,0x06,0x31,0x82,0xe0, -0x04,0x10,0x81,0xe2,0x14,0x10,0x03,0xe5,0x20,0x00,0x00,0x0a,0x00,0x30,0x90,0xe5, -0x08,0x00,0x53,0xe3,0x17,0x00,0x00,0x0a,0x04,0x20,0x80,0xe2,0x00,0xc0,0xa0,0xe3, -0x07,0x00,0x00,0xea,0x03,0x00,0x54,0xe3,0x02,0x10,0xa0,0x11,0x07,0x00,0x00,0x0a, -0x0c,0x00,0x55,0xe1,0x09,0x00,0x00,0x9a,0x04,0x30,0x92,0xe4,0x08,0x00,0x53,0xe3, -0x0d,0x00,0x00,0x0a,0x03,0x40,0x13,0xe2,0x02,0x10,0xa0,0xe1,0xf4,0xff,0xff,0x1a, -0x00,0x00,0x53,0xe3,0x01,0xc0,0x8c,0x02,0x0c,0x00,0x55,0xe1,0xf5,0xff,0xff,0x8a, -0x00,0x30,0x91,0xe5,0x04,0x00,0x53,0xe3,0x04,0x30,0xb1,0x05,0x08,0x00,0x53,0xe3, -0xbd,0xff,0xff,0x1a,0xda,0xff,0xff,0xea,0x00,0x10,0xa0,0xe1,0x00,0x30,0x91,0xe5, -0xf9,0xff,0xff,0xea,0x15,0x24,0xc2,0xe1,0x17,0x24,0x82,0xe1,0xd0,0xff,0xff,0xea, -0x00,0x10,0xa0,0xe1,0xf1,0xff,0xff,0xea,0x00,0x40,0xa0,0xe1,0xa7,0xff,0xff,0xea, -0x20,0x30,0x00,0xe2,0x00,0x00,0x51,0xe3,0xa3,0x31,0xa0,0xe1,0x1f,0x00,0x00,0xe2, -0x01,0x10,0xa0,0x13,0x06,0x3a,0x83,0xe2,0x01,0x10,0xa0,0x03,0x46,0x32,0x83,0xe2, -0x00,0x20,0x93,0xe5,0x11,0x00,0x82,0x11,0x11,0x00,0xc2,0x01,0x00,0x00,0x83,0xe5, -0x02,0x00,0xa0,0xe3,0xd1,0x13,0x00,0xea,0x32,0x23,0xa0,0xe3,0x04,0x40,0x2d,0xe5, -0x28,0x16,0x92,0xe5,0x01,0x40,0x00,0xe2,0x02,0x00,0x50,0xe3,0x30,0x30,0x9f,0xe5, -0x20,0xc0,0xa0,0x03,0x02,0x10,0xc1,0xe3,0x00,0xc0,0xa0,0x13,0x84,0x10,0x81,0xe1, -0x20,0x40,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x20,0x10,0xc1,0xe3,0x04,0x30,0x93,0xe7, -0x01,0x10,0x8c,0xe1,0xbc,0x00,0x83,0xe5,0x28,0x16,0x82,0xe5,0x10,0x00,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0xbc,0xa8,0x00,0x00,0x40,0x00,0x00,0x00,0xc8,0x30,0x9f,0xe5, -0xc8,0x20,0x9f,0xe5,0x70,0x40,0x2d,0xe9,0x01,0x60,0xa0,0xe3,0x03,0x30,0x8f,0xe0, -0x02,0x40,0x93,0xe7,0x38,0x32,0xd4,0xe5,0x03,0x10,0xd4,0xe5,0x24,0x60,0xc4,0xe5, -0x00,0x00,0x53,0xe3,0x00,0x30,0xa0,0xe3,0x25,0x30,0xc4,0xe5,0x02,0x00,0x00,0x0a, -0x39,0x32,0xd4,0xe5,0x00,0x00,0x53,0xe3,0x0b,0x00,0x00,0x1a,0x37,0x62,0xd4,0xe5, -0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0x8d,0x1d,0x00,0xeb,0x06,0x00,0x50,0xe1, -0x70,0x80,0xbd,0xd8,0x6b,0x0f,0x86,0xe2,0x06,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2, -0x87,0x1d,0x00,0xeb,0x03,0x00,0xc4,0xe5,0x70,0x80,0xbd,0xe8,0x27,0x30,0xd4,0xe5, -0x03,0x00,0x53,0xe3,0xf0,0xff,0xff,0x9a,0x6b,0x0f,0x81,0xe2,0x01,0x50,0xa0,0xe1, -0x03,0x00,0x80,0xe2,0x75,0x1d,0x00,0xeb,0x34,0x00,0x50,0xe3,0x09,0x00,0x00,0x9a, -0x85,0x50,0xa0,0xe1,0x86,0x60,0xa0,0xe1,0x6b,0x0f,0x85,0xe2,0x05,0x10,0xa0,0xe1, -0x03,0x00,0x80,0xe2,0xff,0x60,0x06,0xe2,0x6c,0x1d,0x00,0xeb,0x34,0x00,0x50,0xe3, -0xf6,0xff,0xff,0x8a,0x24,0x60,0xc4,0xe5,0x37,0x32,0xd4,0xe5,0x03,0x00,0x50,0xe1, -0x01,0x30,0xa0,0x83,0x25,0x30,0xc4,0x85,0x70,0x80,0xbd,0xe8,0x84,0xa8,0x00,0x00, -0xcc,0x10,0x00,0x00,0x10,0x31,0x9f,0xe5,0x10,0xc1,0x9f,0xe5,0x70,0x00,0x2d,0xe9, -0x01,0x50,0x71,0xe2,0x00,0x50,0xa0,0x33,0x03,0x30,0x8f,0xe0,0x11,0x00,0x50,0xe3, -0x0c,0x30,0x93,0xe7,0x0c,0x30,0x93,0xe5,0xa3,0x4e,0xa0,0xe1,0xa3,0xcb,0xa0,0xe1, -0x23,0x2a,0xa0,0xe1,0xa3,0x6f,0xa0,0xe1,0x01,0x40,0x04,0xe2,0x01,0xc0,0x0c,0xe2, -0x01,0x20,0x02,0xe2,0x0a,0x00,0x00,0x0a,0x10,0x00,0x50,0xe3,0x11,0x00,0x00,0x0a, -0x06,0x00,0x50,0xe3,0x16,0x00,0x00,0x0a,0x08,0x00,0x50,0xe3,0x2a,0x00,0x00,0x0a, -0x2b,0x00,0x50,0xe3,0x00,0x00,0xa0,0x13,0x20,0x00,0x00,0x0a,0x70,0x00,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0x00,0x00,0x55,0xe3,0x15,0x00,0x00,0x0a,0x83,0x30,0xa0,0xe1, -0xa3,0x4f,0x84,0xe1,0x06,0x60,0x84,0xe1,0x02,0x20,0x96,0xe1,0x02,0x00,0xa0,0x01, -0x0b,0x00,0xa0,0x13,0xf4,0xff,0xff,0xea,0x00,0x00,0x55,0xe3,0x05,0x00,0xa0,0x01, -0xf1,0xff,0xff,0x0a,0x04,0x20,0x92,0xe1,0x02,0x00,0xa0,0x01,0x0b,0x00,0xa0,0x13, -0xed,0xff,0xff,0xea,0x00,0x00,0x51,0xe3,0x01,0x00,0xa0,0x01,0xea,0xff,0xff,0x0a, -0x03,0x3c,0xa0,0xe1,0xa3,0xcf,0x9c,0xe1,0x0c,0x00,0xa0,0x01,0x0b,0x00,0xa0,0x13, -0xe5,0xff,0xff,0xea,0x83,0x04,0xa0,0xe1,0x03,0x35,0xa0,0xe1,0xa0,0xcf,0x8c,0xe1, -0xa3,0xcf,0x9c,0xe1,0x0c,0x00,0xa0,0x01,0x09,0x00,0xa0,0x13,0xde,0xff,0xff,0xea, -0x00,0x00,0x51,0xe3,0x00,0x10,0xa0,0x03,0x01,0x10,0x06,0x12,0x00,0x00,0x51,0xe3, -0x01,0x00,0xa0,0x01,0x0b,0x00,0xa0,0x13,0xd7,0xff,0xff,0xea,0x02,0x20,0x15,0xe0, -0x02,0x00,0xa0,0x01,0x0b,0x00,0xa0,0x13,0xd3,0xff,0xff,0xea,0xa8,0xa7,0x00,0x00, -0xcc,0x10,0x00,0x00,0xf0,0x47,0x2d,0xe9,0x00,0x60,0xa0,0xe1,0xa0,0x42,0x9f,0xe5, -0x60,0xd0,0x4d,0xe2,0x40,0xe0,0x8d,0xe2,0x0d,0xc0,0xa0,0xe1,0x94,0x82,0x9f,0xe5, -0x32,0x73,0xa0,0xe3,0x04,0x40,0x8f,0xe0,0x8c,0x52,0x9f,0xe5,0x8c,0x92,0x9f,0xe5, -0x00,0x00,0x56,0xe3,0x08,0x80,0x84,0xe0,0x0f,0x00,0xb8,0xe8,0x05,0x50,0x84,0xe0, -0x0f,0x00,0xae,0xe8,0x0f,0x00,0x98,0xe8,0x0f,0x00,0x8e,0xe8,0x05,0xe0,0xa0,0xe1, -0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xac,0xe8,0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xac,0xe8, -0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xac,0xe8,0x09,0x50,0x94,0xe7,0x0f,0x00,0x9e,0xe8, -0x30,0x60,0x85,0xe5,0x0f,0x00,0x8c,0xe8,0x2c,0x86,0x97,0xe5,0x04,0x80,0xc8,0xe3, -0x2c,0x86,0x87,0xe5,0x43,0x00,0x00,0x0a,0x01,0x00,0x56,0xe3,0x6e,0x00,0x00,0x0a, -0x34,0x32,0xd5,0xe5,0x32,0x00,0xa0,0xe3,0x00,0x70,0xa0,0xe3,0x2a,0x10,0xa0,0xe3, -0x00,0xa0,0xa0,0xe1,0x16,0x60,0xa0,0xe3,0x00,0x00,0x53,0xe3,0x41,0x00,0x00,0x1a, -0x00,0x20,0xa0,0xe3,0x08,0x02,0x9f,0xe5,0xef,0xf7,0xff,0xeb,0xff,0x2c,0xc8,0xe3, -0x32,0x33,0xa0,0xe3,0x02,0x70,0x87,0xe1,0xf8,0x51,0x9f,0xe5,0x03,0x80,0xa0,0xe1, -0x2c,0x76,0x83,0xe5,0x02,0x00,0x00,0xea,0x08,0x13,0x00,0xeb,0x01,0x50,0x55,0xe2, -0x71,0x00,0x00,0x0a,0x2c,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf8,0xff,0xff,0x0a,0x09,0x40,0x94,0xe7,0x32,0x33,0xa0,0xe3,0x2c,0x56,0x93,0xe5, -0x1b,0x0e,0xa0,0xe3,0x06,0x10,0xa0,0xe1,0x48,0x32,0x94,0xe5,0x04,0x50,0x85,0xe3, -0x93,0x00,0x00,0xe0,0x01,0x00,0x40,0xe2,0x06,0x00,0x80,0xe0,0xd3,0x1c,0x00,0xeb, -0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x0d,0x20,0x83,0xe2,0x11,0x22,0xa0,0xe1, -0x02,0x00,0x50,0xe1,0x3c,0x00,0x00,0x9a,0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3, -0xf8,0xff,0xff,0x1a,0x80,0x31,0x9f,0xe5,0x0e,0x28,0xa0,0xe3,0x9a,0x03,0x03,0xe0, -0x78,0x11,0x9f,0xe5,0xc3,0x3c,0x83,0xe2,0x50,0x30,0x83,0xe2,0x01,0x00,0x53,0xe1, -0x48,0x32,0x84,0xe5,0x68,0x31,0x9f,0x95,0x48,0x32,0x84,0x95,0x02,0x00,0x00,0x9a, -0x60,0x11,0x9f,0xe5,0x01,0x00,0x53,0xe1,0x48,0x12,0x84,0x85,0x0f,0x58,0xc5,0xe3, -0x00,0x00,0xa0,0xe3,0x05,0x50,0x82,0xe1,0x32,0x33,0xa0,0xe3,0x2c,0x56,0x83,0xe5, -0x60,0xd0,0x8d,0xe2,0xf0,0x87,0xbd,0xe8,0x02,0x7a,0xa0,0xe3,0x22,0x10,0xa0,0xe3, -0xfa,0x0f,0xa0,0xe3,0x2a,0xa0,0xa0,0xe3,0x12,0x60,0xa0,0xe3,0x34,0x32,0xd5,0xe5, -0x00,0x00,0x53,0xe3,0xbd,0xff,0xff,0x0a,0xa3,0xe0,0xa0,0xe1,0x60,0x20,0x8d,0xe2, -0x07,0x30,0x03,0xe2,0x03,0x31,0x82,0xe0,0x60,0xc0,0x8d,0xe2,0x3c,0xe0,0x0e,0xe2, -0x35,0x22,0xd5,0xe5,0x0e,0xe0,0x8c,0xe0,0x20,0xc0,0x13,0xe5,0x60,0x30,0x1e,0xe5, -0xfa,0xef,0xa0,0xe3,0x9e,0x02,0x02,0xe0,0x9c,0x03,0x03,0xe0,0xf9,0x3f,0x83,0xe2, -0x03,0x30,0x83,0xe2,0x92,0x30,0x20,0xe0,0xdc,0x30,0x9f,0xe5,0x90,0x23,0x83,0xe0, -0xc8,0x20,0x9f,0xe5,0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x85,0xe5, -0xbc,0x30,0x9f,0x95,0x48,0x32,0x85,0x95,0xa4,0xff,0xff,0x9a,0xb4,0x20,0x9f,0xe5, -0x02,0x00,0x53,0xe1,0x48,0x22,0x85,0x85,0xa0,0xff,0xff,0xea,0xf9,0x2f,0x82,0xe2, -0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x28,0xa0,0xe1,0x98,0x30,0x9f,0xe5, -0x91,0xc3,0x83,0xe0,0x23,0x33,0xa0,0xe1,0xbf,0xff,0xff,0xea,0x03,0x60,0xd5,0xe5, -0x24,0x70,0xd5,0xe5,0x6b,0x0f,0x86,0xe2,0x06,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2, -0x82,0x1c,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2, -0x7e,0x1c,0x00,0xeb,0x96,0x07,0x01,0xe0,0x00,0xa0,0xa0,0xe1,0xa7,0x70,0xa0,0xe1, -0x07,0x74,0xa0,0xe1,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0x77,0x1c,0x00,0xeb, -0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2,0x73,0x1c,0x00,0xeb, -0x06,0x11,0x46,0xe2,0x81,0x10,0xa0,0xe1,0xbf,0xff,0xff,0xea,0x03,0x00,0xa0,0xe3, -0xb6,0xff,0xff,0xea,0x7c,0xa6,0x00,0x00,0x4c,0xf2,0xff,0xff,0xa0,0xf2,0xff,0xff, -0xcc,0x10,0x00,0x00,0x4f,0x00,0x64,0x01,0xa0,0x86,0x01,0x00,0x4a,0x0c,0x02,0x00, -0x3f,0x0d,0x03,0x00,0x40,0x0d,0x03,0x00,0x00,0x35,0x0c,0x00,0xd3,0x4d,0x62,0x10, -0xf0,0x4f,0x2d,0xe9,0x64,0xd0,0x4d,0xe2,0xec,0x43,0x9f,0xe5,0xec,0x33,0x9f,0xe5, -0x04,0x40,0x8f,0xe0,0x03,0x30,0x84,0xe0,0x0c,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3, -0x01,0x10,0xa0,0x13,0x04,0x00,0x00,0x1a,0xd4,0x33,0x9f,0xe5,0x03,0x30,0x94,0xe7, -0x08,0x10,0x93,0xe5,0x02,0x00,0x51,0xe3,0x03,0x10,0xa0,0x13,0x00,0x00,0xa0,0xe3, -0xc0,0x53,0x9f,0xe5,0x24,0xfc,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x92,0xfe,0xff,0xeb,0x00,0x20,0xa0,0xe3,0xac,0x03,0x9f,0xe5,0x22,0x10,0xa0,0xe3, -0x4d,0xf7,0xff,0xeb,0xa0,0x03,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0xc1,0xf7,0xff,0xeb, -0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x88,0xfe,0xff,0xeb,0x32,0x33,0xa0,0xe3, -0x01,0x24,0xa0,0xe3,0x03,0x60,0xa0,0xe1,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea, -0x62,0x12,0x00,0xeb,0x01,0x50,0x55,0xe2,0xaa,0x00,0x00,0x0a,0x2c,0x36,0x96,0xe5, -0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x01,0x04,0x13,0xe3,0xf7,0xff,0xff,0x1a, -0x58,0x33,0x9f,0xe5,0x02,0x60,0xa0,0xe1,0x48,0x53,0x9f,0xe5,0x2c,0x36,0x82,0xe5, -0x02,0x00,0x00,0xea,0x55,0x12,0x00,0xeb,0x01,0x50,0x55,0xe2,0x9d,0x00,0x00,0x0a, -0x2c,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5,0x40,0x36,0x92,0xe5,0x01,0x04,0x13,0xe3, -0x0f,0x2c,0xa0,0x13,0x9c,0x00,0x00,0x0a,0x04,0x83,0x9f,0xe5,0x02,0x06,0x13,0xe3, -0x0c,0xb3,0x9f,0xe5,0x32,0x33,0xa0,0xe3,0x28,0x26,0x83,0xe5,0x00,0x30,0xa0,0xe3, -0x08,0x50,0x94,0xe7,0x32,0x63,0xa0,0xe3,0xf8,0x72,0x9f,0xe5,0x0b,0xb0,0x84,0xe0, -0x40,0xe0,0x8d,0xe2,0x0d,0xc0,0xa0,0xe1,0x38,0x32,0xc5,0xe5,0x01,0x30,0xa0,0x13, -0x38,0x32,0xc5,0x15,0x07,0x90,0x84,0xe0,0x0f,0x00,0xbb,0xe8,0xd8,0x72,0x9f,0xe5, -0x30,0xa0,0x95,0xe5,0x34,0x76,0x86,0xe5,0x09,0x70,0xa0,0xe1,0x0f,0x00,0xae,0xe8, -0x00,0x00,0x5a,0xe3,0x0f,0x00,0x9b,0xe8,0x0f,0x00,0x8e,0xe8,0x0f,0x00,0xb7,0xe8, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0xb7,0xe8,0x0f,0x00,0xac,0xe8,0x0f,0x00,0xb7,0xe8, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0x97,0xe8,0x0f,0x00,0x8c,0xe8,0x2c,0x76,0x96,0xe5, -0x04,0x70,0xc7,0xe3,0x2c,0x76,0x86,0xe5,0x71,0x00,0x00,0x0a,0x01,0x00,0x5a,0xe3, -0x81,0x00,0x00,0x0a,0x32,0x00,0xa0,0xe3,0x00,0xa0,0xa0,0xe3,0x2a,0x10,0xa0,0xe3, -0x00,0x90,0xa0,0xe1,0x16,0x60,0xa0,0xe3,0x34,0x32,0xd5,0xe5,0x00,0x00,0x53,0xe3, -0x1b,0x00,0x00,0x0a,0xa3,0xe0,0xa0,0xe1,0x60,0x20,0x8d,0xe2,0x07,0x30,0x03,0xe2, -0x03,0xc1,0x82,0xe0,0x3c,0x30,0x0e,0xe2,0x60,0xe0,0x8d,0xe2,0x35,0x22,0xd5,0xe5, -0x03,0x30,0x8e,0xe0,0x20,0xc0,0x1c,0xe5,0x60,0x30,0x13,0xe5,0xfa,0xef,0xa0,0xe3, -0x9e,0x02,0x02,0xe0,0x9c,0x03,0x03,0xe0,0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2, -0x92,0x30,0x20,0xe0,0x24,0x32,0x9f,0xe5,0x90,0x23,0x83,0xe0,0x20,0x22,0x9f,0xe5, -0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x85,0xe5,0x14,0x32,0x9f,0x95, -0x48,0x32,0x85,0x95,0x02,0x00,0x00,0x9a,0x0c,0x22,0x9f,0xe5,0x02,0x00,0x53,0xe1, -0x48,0x22,0x85,0x85,0xe0,0x01,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0xff,0x7c,0xc7,0xe3, -0xd0,0x51,0x9f,0xe5,0xd8,0xf6,0xff,0xeb,0x07,0xa0,0x8a,0xe1,0x32,0x33,0xa0,0xe3, -0x03,0xb0,0xa0,0xe1,0x2c,0xa6,0x83,0xe5,0x02,0x00,0x00,0xea,0xf3,0x11,0x00,0xeb, -0x01,0x50,0x55,0xe2,0x29,0x00,0x00,0x0a,0x2c,0x36,0x9b,0xe5,0x01,0x00,0xa0,0xe3, -0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x08,0x50,0x94,0xe7,0x32,0x33,0xa0,0xe3, -0x2c,0x76,0x93,0xe5,0x1b,0x0e,0xa0,0xe3,0x06,0x10,0xa0,0xe1,0x48,0x32,0x95,0xe5, -0x04,0x70,0x87,0xe3,0x93,0x00,0x00,0xe0,0x01,0x00,0x40,0xe2,0x06,0x00,0x80,0xe0, -0xbe,0x1b,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x0d,0x20,0x83,0xe2, -0x11,0x22,0xa0,0xe1,0x02,0x00,0x50,0xe1,0x33,0x00,0x00,0x9a,0x01,0x30,0x83,0xe2, -0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0x70,0x31,0x9f,0xe5,0x0e,0x28,0xa0,0xe3, -0x99,0x03,0x03,0xe0,0x58,0x11,0x9f,0xe5,0xc3,0x3c,0x83,0xe2,0x50,0x30,0x83,0xe2, -0x01,0x00,0x53,0xe1,0x48,0x32,0x85,0xe5,0x48,0x31,0x9f,0x95,0x48,0x32,0x85,0x95, -0x02,0x00,0x00,0x9a,0x40,0x11,0x9f,0xe5,0x01,0x00,0x53,0xe1,0x48,0x12,0x85,0x85, -0x0f,0x78,0xc7,0xe3,0x32,0x33,0xa0,0xe3,0x07,0x20,0x82,0xe1,0x2c,0x26,0x83,0xe5, -0x08,0x30,0x94,0xe7,0x32,0x23,0xa0,0xe3,0x24,0x11,0x9f,0xe5,0x00,0x00,0xa0,0xe3, -0x28,0xc6,0x92,0xe5,0x08,0x30,0x93,0xe5,0x01,0x40,0x94,0xe7,0x02,0xc0,0xcc,0xe3, -0x01,0x50,0x03,0xe2,0x02,0x00,0x53,0xe3,0x85,0xc0,0x8c,0xe1,0xbc,0x30,0x84,0xe5, -0x20,0x10,0xa0,0x03,0x00,0x10,0xa0,0x11,0x20,0x30,0xcc,0xe3,0x03,0x30,0x81,0xe1, -0x28,0x36,0x82,0xe5,0x00,0x00,0x00,0xea,0x03,0x00,0xa0,0xe3,0x64,0xd0,0x8d,0xe2, -0xf0,0x8f,0xbd,0xe8,0x02,0xaa,0xa0,0xe3,0x22,0x10,0xa0,0xe3,0xfa,0x0f,0xa0,0xe3, -0x2a,0x90,0xa0,0xe3,0x12,0x60,0xa0,0xe3,0x8e,0xff,0xff,0xea,0x02,0x04,0x13,0xe3, -0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13,0x5e,0xff,0xff,0xea,0xf9,0x2f,0x82,0xe2, -0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x28,0xa0,0xe1,0x8c,0x30,0x9f,0xe5, -0x91,0x03,0x83,0xe0,0x23,0x33,0xa0,0xe1,0xc8,0xff,0xff,0xea,0x03,0x60,0xd5,0xe5, -0x24,0xa0,0xd5,0xe5,0x6b,0x0f,0x86,0xe2,0x06,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2, -0x76,0x1b,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2, -0x72,0x1b,0x00,0xeb,0x96,0x0a,0x01,0xe0,0x00,0x90,0xa0,0xe1,0xaa,0xa0,0xa0,0xe1, -0x0a,0xa4,0xa0,0xe1,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0x6b,0x1b,0x00,0xeb, -0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2,0x67,0x1b,0x00,0xeb, -0x06,0x11,0x46,0xe2,0x81,0x10,0xa0,0xe1,0x6a,0xff,0xff,0xea,0xb0,0xa3,0x00,0x00, -0xd0,0x10,0x00,0x00,0xcc,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x4f,0x00,0x64,0x01, -0x01,0x20,0x00,0x00,0x4c,0xf2,0xff,0xff,0xa0,0xf2,0xff,0xff,0xcb,0x00,0x7f,0x00, -0xd3,0x4d,0x62,0x10,0x3f,0x0d,0x03,0x00,0x40,0x0d,0x03,0x00,0x00,0x35,0x0c,0x00, -0x4a,0x0c,0x02,0x00,0x40,0x00,0x00,0x00,0xf0,0x4f,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0x78,0x5c,0x9f,0xe5,0xac,0xd0,0x4d,0xe2,0x01,0x90,0xa0,0xe1,0x03,0x80,0xa0,0xe1, -0x6c,0x7c,0x9f,0xe5,0x32,0xa3,0xa0,0xe3,0x05,0x50,0x8f,0xe0,0x64,0x6c,0x9f,0xe5, -0x28,0x20,0x8d,0xe5,0x07,0x00,0x95,0xe7,0x30,0x00,0x8d,0xe5,0x02,0x00,0x00,0xea, -0x6a,0x11,0x00,0xeb,0x01,0x60,0x56,0xe2,0x34,0x02,0x00,0x0a,0x24,0x36,0x9a,0xe5, -0x01,0x00,0xa0,0xe3,0x01,0x00,0x13,0xe3,0xf8,0xff,0xff,0x1a,0x00,0x00,0x58,0xe3, -0x3f,0x40,0x04,0xe2,0x04,0x4c,0xa0,0xe1,0x4a,0x00,0x00,0x1a,0x28,0x3c,0x9f,0xe5, -0x08,0x20,0xa0,0xe1,0x28,0xc0,0x9d,0xe5,0x03,0x30,0x85,0xe0,0x0c,0x31,0x93,0xe7, -0x03,0x30,0x84,0xe1,0x02,0x30,0x83,0xe1,0x03,0x60,0xa0,0xe3,0x14,0x30,0x8d,0xe5, -0x08,0xa0,0xa0,0xe1,0x04,0x3c,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x2c,0x30,0x8d,0xe5, -0xfc,0x3b,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x20,0x30,0x8d,0xe5,0xf4,0x3b,0x9f,0xe5, -0x03,0x30,0x85,0xe0,0x24,0x30,0x8d,0xe5,0x32,0x33,0xa0,0xe3,0x14,0xc0,0x9d,0xe5, -0x30,0x26,0x93,0xe5,0x03,0x80,0xa0,0xe1,0xc8,0x4b,0x9f,0xe5,0x30,0x26,0x83,0xe5, -0x30,0x26,0x93,0xe5,0x08,0x96,0x83,0xe5,0x0c,0xc6,0x83,0xe5,0x04,0x00,0x00,0xea, -0x01,0x00,0x13,0xe3,0x11,0x02,0x00,0x1a,0x40,0x11,0x00,0xeb,0x01,0x40,0x54,0xe2, -0x01,0x02,0x00,0x0a,0x30,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x0f,0x08,0x13,0xe3, -0xf6,0xff,0xff,0x0a,0x32,0x23,0xa0,0xe3,0x08,0x00,0xa0,0xe3,0x30,0xb6,0x92,0xe5, -0x1c,0x00,0x8d,0xe5,0x2c,0x36,0x92,0xe5,0x0f,0x08,0x1b,0xe3,0xfd,0x01,0x00,0x0a, -0x02,0x34,0x83,0xe3,0x6c,0x4b,0x9f,0xe5,0x02,0x80,0xa0,0xe1,0x2c,0x36,0x82,0xe5, -0x02,0x00,0x00,0xea,0x2d,0x11,0x00,0xeb,0x01,0x40,0x54,0xe2,0x10,0x00,0x00,0x0a, -0x2c,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x04,0x13,0xe3,0xf8,0xff,0xff,0x1a, -0x07,0x06,0x1b,0xe3,0x18,0x00,0x00,0x0a,0x32,0x23,0xa0,0xe3,0x01,0x33,0x83,0xe3, -0x02,0x80,0xa0,0xe1,0x2c,0x36,0x82,0xe5,0x2c,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x03,0x13,0xe3,0x10,0x00,0x00,0x0a,0x1c,0x11,0x00,0xeb,0x01,0x40,0x54,0xe2, -0xf8,0xff,0xff,0x1a,0x01,0x60,0x56,0xe2,0xca,0xff,0xff,0x1a,0x1c,0x00,0x9d,0xe5, -0xac,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0xfc,0x3a,0x9f,0xe5,0x02,0x16,0x84,0xe3, -0x28,0xb0,0x9d,0xe5,0x02,0x10,0x81,0xe3,0x01,0x20,0xa0,0xe3,0x03,0x30,0x85,0xe0, -0x0b,0x31,0x93,0xe7,0x03,0x30,0x81,0xe1,0xb1,0xff,0xff,0xea,0x00,0x00,0x5a,0xe3, -0x32,0x43,0xa0,0xe3,0x30,0xb6,0x84,0xe5,0xf0,0x00,0x00,0x0a,0x07,0x10,0x95,0xe7, -0x02,0xb0,0xa0,0xe3,0xd0,0x2a,0x9f,0xe5,0x06,0x80,0xa0,0xe1,0x3c,0x10,0x8d,0xe5, -0x34,0x20,0x8d,0xe5,0x30,0x36,0x94,0xe5,0xa8,0x6a,0x9f,0xe5,0x30,0x36,0x84,0xe5, -0x30,0x36,0x94,0xe5,0x00,0x30,0xa0,0xe3,0x08,0x36,0x84,0xe5,0xac,0x3a,0x9f,0xe5, -0x0c,0x36,0x84,0xe5,0x04,0x00,0x00,0xea,0x01,0x00,0x13,0xe3,0xe2,0x01,0x00,0x1a, -0xf6,0x10,0x00,0xeb,0x01,0x60,0x56,0xe2,0x03,0x00,0x00,0x0a,0x30,0x36,0x94,0xe5, -0x01,0x00,0xa0,0xe3,0x0f,0x08,0x13,0xe3,0xf6,0xff,0xff,0x0a,0x2c,0xc0,0x9d,0xe5, -0x0c,0x30,0xdc,0xe5,0x00,0x00,0x53,0xe3,0x01,0x10,0xa0,0x13,0xa9,0x01,0x00,0x0a, -0x00,0x00,0xa0,0xe3,0x4c,0x6a,0x9f,0xe5,0x97,0xfa,0xff,0xeb,0x0f,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x05,0xfd,0xff,0xeb,0x00,0x20,0xa0,0xe3,0x50,0x0a,0x9f,0xe5, -0x22,0x10,0xa0,0xe3,0xc0,0xf5,0xff,0xeb,0x44,0x0a,0x9f,0xe5,0x01,0x10,0xa0,0xe3, -0x34,0xf6,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xfb,0xfc,0xff,0xeb, -0x01,0x34,0xa0,0xe3,0x2c,0x36,0x84,0xe5,0x02,0x00,0x00,0xea,0xd7,0x10,0x00,0xeb, -0x01,0x60,0x56,0xe2,0xba,0x00,0x00,0x0a,0x2c,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x04,0x13,0xe3,0xf8,0xff,0xff,0x1a,0x08,0x2a,0x9f,0xe5,0x32,0x33,0xa0,0xe3, -0xe0,0x69,0x9f,0xe5,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0xcb,0x10,0x00,0xeb, -0x01,0x60,0x56,0xe2,0xae,0x00,0x00,0x0a,0x2c,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x32,0x23,0xa0,0xe3,0x02,0x00,0x13,0xe3,0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5, -0x40,0x36,0x92,0xe5,0x01,0x04,0x13,0xe3,0x0f,0x2c,0xa0,0x13,0x02,0x00,0x00,0x1a, -0x02,0x04,0x13,0xe3,0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13,0x07,0x60,0x95,0xe7, -0x02,0x06,0x13,0xe3,0x00,0x30,0xa0,0xe3,0x28,0x26,0x84,0xe5,0x88,0xc0,0x8d,0xe2, -0x38,0x32,0xc6,0xe5,0x01,0x30,0xa0,0x13,0x38,0x32,0xc6,0x15,0x20,0xe0,0x9d,0xe5, -0x40,0xc0,0x8d,0xe5,0x30,0xc0,0x96,0xe5,0x0f,0x00,0xbe,0xe8,0x38,0xc0,0x8d,0xe5, -0x84,0xc9,0x9f,0xe5,0x18,0xe0,0x8d,0xe5,0x48,0xe0,0x8d,0xe2,0x34,0xc6,0x84,0xe5, -0x40,0xc0,0x9d,0xe5,0x0f,0x00,0xac,0xe8,0x40,0xc0,0x8d,0xe5,0x18,0xc0,0x9d,0xe5, -0x38,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3,0x0f,0x00,0x9c,0xe8,0x40,0xc0,0x9d,0xe5, -0x0f,0x00,0x8c,0xe8,0x24,0xc0,0x9d,0xe5,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0x9c,0xe8,0x0f,0x00,0x8e,0xe8,0x2c,0x36,0x94,0xe5,0x04,0x30,0xc3,0xe3, -0x2c,0x36,0x84,0xe5,0x9d,0x01,0x00,0x0a,0x38,0xe0,0x9d,0xe5,0x01,0x00,0x5e,0xe3, -0xf9,0x01,0x00,0x0a,0x00,0xc0,0xa0,0xe3,0x2a,0x10,0xa0,0xe3,0x32,0x00,0xa0,0xe3, -0x16,0xe0,0xa0,0xe3,0x38,0x00,0x8d,0xe5,0x18,0xe0,0x8d,0xe5,0x34,0x22,0xd6,0xe5, -0x00,0x00,0x52,0xe3,0x24,0x00,0x00,0x0a,0xa2,0xe0,0xa0,0xe1,0x07,0x20,0x02,0xe2, -0x04,0xe0,0x8d,0xe5,0xa8,0xe0,0x8d,0xe2,0x02,0xe1,0x8e,0xe0,0x35,0x22,0xd6,0xe5, -0x40,0xe0,0x8d,0xe5,0x04,0xe0,0x9d,0xe5,0x44,0x20,0x8d,0xe5,0x3c,0x20,0x0e,0xe2, -0xa8,0xe0,0x8d,0xe2,0x02,0x20,0x8e,0xe0,0x40,0xe0,0x9d,0xe5,0x60,0x20,0x12,0xe5, -0x20,0xe0,0x1e,0xe5,0x40,0x20,0x8d,0xe5,0xfa,0x2f,0xa0,0xe3,0x04,0xe0,0x8d,0xe5, -0x44,0xe0,0x9d,0xe5,0x92,0x0e,0x0e,0xe0,0x40,0x20,0x9d,0xe5,0x44,0xe0,0x8d,0xe5, -0x04,0xe0,0x9d,0xe5,0x9e,0x02,0x02,0xe0,0x44,0xe0,0x9d,0xe5,0xf9,0x2f,0x82,0xe2, -0x03,0x20,0x82,0xe2,0x90,0x2e,0x22,0xe0,0x80,0xe8,0x9f,0xe5,0x9e,0x02,0x82,0xe0, -0x7c,0x08,0x9f,0xe5,0x22,0x23,0xa0,0xe1,0x00,0x00,0x52,0xe1,0x48,0x22,0x86,0xe5, -0x70,0x28,0x9f,0x95,0x48,0x22,0x86,0x95,0x7c,0x01,0x00,0x8a,0x50,0x08,0x9f,0xe5, -0x00,0x20,0xa0,0xe3,0x0c,0x30,0x8d,0xe5,0x10,0xc0,0x8d,0xe5,0x3e,0xf5,0xff,0xeb, -0x0c,0x30,0x9d,0xe5,0x10,0xc0,0x9d,0xe5,0x18,0x68,0x9f,0xe5,0xff,0x3c,0xc3,0xe3, -0x03,0x30,0x8c,0xe1,0x2c,0x36,0x84,0xe5,0x02,0x00,0x00,0xea,0x57,0x10,0x00,0xeb, -0x01,0x60,0x56,0xe2,0x2b,0x00,0x00,0x0a,0x2c,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x07,0x60,0x95,0xe7,0x1b,0x2e,0xa0,0xe3, -0x32,0x33,0xa0,0xe3,0x18,0x10,0x9d,0xe5,0x2c,0x36,0x93,0xe5,0x48,0x02,0x96,0xe5, -0x04,0x30,0x83,0xe3,0x0c,0x30,0x8d,0xe5,0x92,0x00,0x00,0xe0,0x01,0x00,0x40,0xe2, -0x01,0x00,0x80,0xe0,0x21,0x1a,0x00,0xeb,0x0c,0x30,0x9d,0xe5,0x00,0x20,0xa0,0xe3, -0x01,0xc0,0xa0,0xe3,0x0d,0x10,0x82,0xe2,0x1c,0x11,0xa0,0xe1,0x01,0x00,0x50,0xe1, -0x7d,0x01,0x00,0x9a,0x01,0x20,0x82,0xe2,0x0e,0x00,0x52,0xe3,0xf8,0xff,0xff,0x1a, -0xc4,0x17,0x9f,0xe5,0x0e,0x28,0xa0,0xe3,0x38,0xe0,0x9d,0xe5,0xb0,0x07,0x9f,0xe5, -0x9e,0x01,0x01,0xe0,0xc3,0x1c,0x81,0xe2,0x50,0x10,0x81,0xe2,0x00,0x00,0x51,0xe1, -0x48,0x12,0x86,0xe5,0x9c,0x17,0x9f,0x95,0x48,0x12,0x86,0x95,0x02,0x00,0x00,0x9a, -0x98,0x07,0x9f,0xe5,0x00,0x00,0x51,0xe1,0x48,0x02,0x86,0x85,0x0f,0x38,0xc3,0xe3, -0x03,0x30,0x82,0xe1,0x2c,0x36,0x84,0xe5,0x07,0x30,0x95,0xe7,0x28,0x06,0x94,0xe5, -0x34,0x20,0x9d,0xe5,0x08,0x30,0x93,0xe5,0x02,0x00,0xc0,0xe3,0x02,0x10,0x95,0xe7, -0x01,0xc0,0x03,0xe2,0x02,0x00,0x53,0xe3,0x8c,0x00,0x80,0xe1,0x20,0x20,0xa0,0x03, -0x00,0x20,0xa0,0x13,0xbc,0x30,0x81,0xe5,0x20,0x00,0xc0,0xe3,0x00,0x20,0x82,0xe1, -0x28,0x26,0x84,0xe5,0x01,0xb0,0x5b,0xe2,0x15,0xff,0xff,0x1a,0x08,0x60,0xa0,0xe1, -0x28,0x00,0xa0,0xe3,0x15,0x10,0x00,0xeb,0x32,0x33,0xa0,0xe3,0x24,0x36,0x93,0xe5, -0x0f,0x36,0x03,0xe2,0x0f,0x06,0x53,0xe3,0xf5,0xfe,0xff,0x0a,0x2c,0xc0,0x9d,0xe5, -0x0c,0x30,0xdc,0xe5,0x00,0x00,0x53,0xe3,0x01,0x10,0xa0,0x13,0x03,0x00,0x00,0x1a, -0x07,0x30,0x95,0xe7,0x08,0x10,0x93,0xe5,0x02,0x00,0x51,0xe3,0x03,0x10,0xa0,0x13, -0x00,0x00,0xa0,0xe3,0xbc,0x46,0x9f,0xe5,0xb3,0xf9,0xff,0xeb,0x0f,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x21,0xfc,0xff,0xeb,0x00,0x20,0xa0,0xe3,0xc0,0x06,0x9f,0xe5, -0x22,0x10,0xa0,0xe3,0xdc,0xf4,0xff,0xeb,0xb4,0x06,0x9f,0xe5,0x01,0x10,0xa0,0xe3, -0x50,0xf5,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x17,0xfc,0xff,0xeb, -0x32,0x33,0xa0,0xe3,0x01,0x24,0xa0,0xe3,0x03,0x80,0xa0,0xe1,0x2c,0x26,0x83,0xe5, -0x02,0x00,0x00,0xea,0xf1,0x0f,0x00,0xeb,0x01,0x40,0x54,0xe2,0xa8,0x00,0x00,0x0a, -0x2c,0x26,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x33,0xa0,0xe3,0x01,0x04,0x12,0xe3, -0xf7,0xff,0xff,0x1a,0x6c,0x26,0x9f,0xe5,0x03,0x80,0xa0,0xe1,0x44,0x46,0x9f,0xe5, -0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0xe4,0x0f,0x00,0xeb,0x01,0x40,0x54,0xe2, -0x9b,0x00,0x00,0x0a,0x2c,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3, -0x02,0x00,0x13,0xe3,0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5,0x40,0x36,0x92,0xe5, -0x01,0x04,0x13,0xe3,0x0f,0x2c,0xa0,0x13,0x02,0x00,0x00,0x1a,0x02,0x04,0x13,0xe3, -0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13,0x07,0x40,0x95,0xe7,0x02,0x06,0x13,0xe3, -0x32,0x33,0xa0,0xe3,0x32,0x83,0xa0,0xe3,0x28,0x26,0x83,0xe5,0x00,0x30,0xa0,0xe3, -0x38,0x32,0xc4,0xe5,0x01,0x30,0xa0,0x13,0x38,0x32,0xc4,0x15,0x88,0xc0,0x8d,0xe2, -0x20,0xe0,0x9d,0xe5,0x30,0xb0,0x94,0xe5,0x0f,0x00,0xbe,0xe8,0x34,0xb0,0x8d,0xe5, -0xe4,0xb5,0x9f,0xe5,0x18,0xe0,0x8d,0xe5,0x48,0xe0,0x8d,0xe2,0x34,0xb6,0x88,0xe5, -0x18,0xb0,0x9d,0xe5,0x0f,0x00,0xac,0xe8,0x34,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3, -0x0f,0x00,0x9b,0xe8,0x0f,0x00,0x8c,0xe8,0x24,0xc0,0x9d,0xe5,0x0f,0x00,0xbc,0xe8, -0x0f,0x00,0xae,0xe8,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0xbc,0xe8, -0x0f,0x00,0xae,0xe8,0x0f,0x00,0x9c,0xe8,0x0f,0x00,0x8e,0xe8,0x2c,0xb6,0x98,0xe5, -0x04,0xb0,0xcb,0xe3,0x2c,0xb6,0x88,0xe5,0xc0,0x00,0x00,0x0a,0x34,0xc0,0x9d,0xe5, -0x01,0x00,0x5c,0xe3,0x34,0x01,0x00,0x0a,0x2a,0x10,0xa0,0xe3,0x16,0x80,0xa0,0xe3, -0x32,0x00,0xa0,0xe3,0x00,0xc0,0xa0,0xe3,0x18,0xc0,0x8d,0xe5,0x34,0x00,0x8d,0xe5, -0x34,0x22,0xd4,0xe5,0x00,0x00,0x52,0xe3,0x17,0x00,0x00,0x0a,0xa2,0x30,0xa0,0xe1, -0xa8,0xe0,0x8d,0xe2,0x07,0x20,0x02,0xe2,0x35,0xc2,0xd4,0xe5,0x02,0x21,0x8e,0xe0, -0x3c,0x30,0x03,0xe2,0x03,0x30,0x8e,0xe0,0x60,0xe0,0x13,0xe5,0xfa,0x3f,0xa0,0xe3, -0x20,0x20,0x12,0xe5,0x9c,0x03,0x03,0xe0,0x30,0xc5,0x9f,0xe5,0x9e,0x02,0x02,0xe0, -0xf9,0x2f,0x82,0xe2,0x03,0x20,0x82,0xe2,0x90,0x23,0x23,0xe0,0x20,0x25,0x9f,0xe5, -0x9c,0x03,0x83,0xe0,0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x84,0xe5, -0x10,0x35,0x9f,0x95,0x48,0x32,0x84,0x95,0xac,0x00,0x00,0x8a,0x00,0x20,0xa0,0xe3, -0xec,0x04,0x9f,0xe5,0x68,0xf4,0xff,0xeb,0x18,0x10,0x9d,0xe5,0xff,0x2c,0xcb,0xe3, -0x32,0x33,0xa0,0xe3,0xbc,0x44,0x9f,0xe5,0x03,0xb0,0xa0,0xe1,0x02,0x20,0x81,0xe1, -0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0x80,0x0f,0x00,0xeb,0x01,0x40,0x54,0xe2, -0x27,0x00,0x00,0x0a,0x2c,0x36,0x9b,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf8,0xff,0xff,0x0a,0x07,0x40,0x95,0xe7,0x32,0x33,0xa0,0xe3,0x2c,0xb6,0x93,0xe5, -0x1b,0x2e,0xa0,0xe3,0x08,0x10,0xa0,0xe1,0x48,0x32,0x94,0xe5,0x04,0xb0,0x8b,0xe3, -0x92,0x03,0x03,0xe0,0x01,0x00,0x43,0xe2,0x08,0x00,0x80,0xe0,0x4b,0x19,0x00,0xeb, -0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x0d,0x20,0x83,0xe2,0x11,0x22,0xa0,0xe1, -0x02,0x00,0x50,0xe1,0xb4,0x00,0x00,0x9a,0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3, -0xf8,0xff,0xff,0x1a,0x70,0x24,0x9f,0xe5,0x0e,0x38,0xa0,0xe3,0x34,0x00,0x9d,0xe5, -0x5c,0x14,0x9f,0xe5,0x90,0x02,0x02,0xe0,0xc3,0x2c,0x82,0xe2,0x50,0x20,0x82,0xe2, -0x01,0x00,0x52,0xe1,0x48,0x22,0x84,0xe5,0x48,0x24,0x9f,0x95,0x48,0x22,0x84,0x95, -0x76,0x00,0x00,0x8a,0x0f,0xb8,0xcb,0xe3,0x32,0x23,0xa0,0xe3,0x0b,0x30,0x83,0xe1, -0x2c,0x36,0x82,0xe5,0x07,0x30,0x95,0xe7,0x32,0x23,0xa0,0xe3,0x28,0xc6,0x92,0xe5, -0x04,0x14,0x9f,0xe5,0x08,0x30,0x93,0xe5,0x02,0xc0,0xcc,0xe3,0x01,0x00,0x95,0xe7, -0x01,0x40,0x03,0xe2,0x02,0x00,0x53,0xe3,0x84,0xc0,0x8c,0xe1,0x20,0x10,0xa0,0x03, -0x00,0x10,0xa0,0x13,0xbc,0x30,0x80,0xe5,0x20,0xc0,0xcc,0xe3,0x0c,0x10,0x81,0xe1, -0x28,0x16,0x82,0xe5,0x01,0x60,0x56,0xe2,0x32,0x33,0xa0,0xe3,0x24,0x36,0x93,0xe5, -0xf4,0xfd,0xff,0x1a,0x28,0xfe,0xff,0xea,0x07,0x30,0x95,0xe7,0x08,0x10,0x93,0xe5, -0x02,0x00,0x51,0xe3,0x03,0x10,0xa0,0x13,0x50,0xfe,0xff,0xea,0x32,0x23,0xa0,0xe3, -0x03,0xe0,0xa0,0xe3,0x30,0xb6,0x92,0xe5,0x1c,0xe0,0x8d,0xe5,0x2c,0x36,0x92,0xe5, -0x0f,0x08,0x1b,0xe3,0x01,0xfe,0xff,0x1a,0x78,0x43,0x9f,0xe5,0x0b,0xfe,0xff,0xea, -0x03,0x20,0xa0,0xe3,0x1c,0x20,0x8d,0xe5,0x02,0x00,0xa0,0xe1,0x17,0xfe,0xff,0xea, -0x60,0x43,0x9f,0xe5,0x32,0x63,0xa0,0xe3,0x02,0x00,0x00,0xea,0x2b,0x0f,0x00,0xeb, -0x01,0x40,0x54,0xe2,0x70,0x00,0x00,0x0a,0x24,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3, -0x32,0x23,0xa0,0xe3,0x01,0x00,0x13,0xe3,0xf7,0xff,0xff,0x1a,0x28,0x10,0x9d,0xe5, -0x08,0x00,0x51,0xe3,0x74,0x00,0x00,0x0a,0x28,0x20,0x9d,0xe5,0x01,0x30,0x42,0xe2, -0x07,0x00,0x53,0xe3,0x03,0xf1,0x8f,0x90,0x40,0x00,0x00,0xea,0x53,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x51,0x00,0x00,0xea,0x50,0x00,0x00,0xea,0x4f,0x00,0x00,0xea, -0x4e,0x00,0x00,0xea,0x4d,0x00,0x00,0xea,0x4c,0x00,0x00,0xea,0x08,0x60,0xa0,0xe1, -0xf0,0x42,0x9f,0xe5,0x32,0x83,0xa0,0xe3,0x02,0x00,0x00,0xea,0x0f,0x0f,0x00,0xeb, -0x01,0x40,0x54,0xe2,0xf5,0xfe,0xff,0x0a,0x24,0x26,0x98,0xe5,0x01,0x00,0xa0,0xe3, -0x32,0x33,0xa0,0xe3,0x01,0x00,0x12,0xe3,0xf7,0xff,0xff,0x1a,0x07,0x20,0x95,0xe7, -0x48,0x42,0x92,0xe5,0x00,0x00,0x54,0xe3,0xa7,0x00,0x00,0x0a,0x24,0x26,0x93,0xe5, -0x02,0x00,0x12,0xe3,0xa4,0x00,0x00,0x0a,0x03,0x80,0xa0,0xe1,0x02,0x00,0x00,0xea, -0x24,0x36,0x98,0xe5,0x02,0x00,0x13,0xe3,0x9f,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0xfa,0x0e,0x00,0xeb,0x01,0x40,0x54,0xe2,0xf8,0xff,0xff,0x1a,0xdf,0xfe,0xff,0xea, -0x2a,0xe0,0xa0,0xe3,0x12,0x20,0xa0,0xe3,0x02,0xca,0xa0,0xe3,0x22,0x10,0xa0,0xe3, -0xfa,0x0f,0xa0,0xe3,0x38,0xe0,0x8d,0xe5,0x18,0x20,0x8d,0xe5,0x62,0xfe,0xff,0xea, -0x02,0x2a,0xa0,0xe3,0x2a,0x30,0xa0,0xe3,0x18,0x20,0x8d,0xe5,0x22,0x10,0xa0,0xe3, -0xfa,0x0f,0xa0,0xe3,0x34,0x30,0x8d,0xe5,0x12,0x80,0xa0,0xe3,0x3f,0xff,0xff,0xea, -0x78,0x02,0x9f,0xe5,0x00,0x00,0x52,0xe1,0x48,0x02,0x86,0x85,0x7e,0xfe,0xff,0xea, -0x68,0x12,0x9f,0xe5,0x01,0x00,0x52,0xe1,0x48,0x12,0x84,0x85,0x84,0xff,0xff,0xea, -0x58,0x22,0x9f,0xe5,0x02,0x00,0x53,0xe1,0x48,0x22,0x84,0x85,0x4e,0xff,0xff,0xea, -0x30,0x10,0x9d,0xe5,0x00,0x30,0xa0,0xe3,0x1c,0x30,0x8d,0xe5,0x03,0x00,0xa0,0xe1, -0x0c,0x30,0x81,0xe5,0xbd,0xfd,0xff,0xea,0x32,0x33,0xa0,0xe3,0x30,0x00,0x9d,0xe5, -0x10,0x26,0x93,0xe5,0x00,0xc0,0xa0,0xe3,0x1c,0xc0,0x8d,0xe5,0x0c,0x20,0x80,0xe5, -0x14,0x26,0x93,0xe5,0x10,0x20,0x80,0xe5,0x18,0x26,0x93,0xe5,0x14,0x20,0x80,0xe5, -0x1c,0x36,0x93,0xe5,0x18,0x30,0x80,0xe5,0x0c,0x00,0xa0,0xe1,0xaf,0xfd,0xff,0xea, -0x00,0x30,0xa0,0xe3,0x30,0xb0,0x9d,0xe5,0x1c,0x30,0x8d,0xe5,0x32,0x33,0xa0,0xe3, -0x10,0x36,0x93,0xe5,0x0c,0x30,0x8b,0xe5,0xa7,0xfd,0xff,0xea,0xf9,0x1f,0x81,0xe2, -0x0f,0x20,0x02,0xe2,0x03,0x00,0x81,0xe2,0x02,0x28,0xa0,0xe1,0xbc,0x11,0x9f,0xe5, -0x90,0xc1,0x81,0xe0,0x21,0x13,0xa0,0xe1,0x7e,0xfe,0xff,0xea,0x03,0x30,0xa0,0xe3, -0x1c,0x30,0x8d,0xe5,0x03,0x00,0xa0,0xe1,0x9c,0xfd,0xff,0xea,0xf9,0x2f,0x82,0xe2, -0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x38,0xa0,0xe1,0x8c,0x21,0x9f,0xe5, -0x91,0xc2,0x82,0xe0,0x22,0x23,0xa0,0xe1,0x47,0xff,0xff,0xea,0x07,0x30,0x95,0xe7, -0x48,0x42,0x93,0xe5,0x00,0x00,0x54,0xe3,0x86,0xff,0xff,0x0a,0x24,0x36,0x92,0xe5, -0x02,0x00,0x13,0xe3,0x83,0xff,0xff,0x0a,0x02,0x50,0xa0,0xe1,0x02,0x00,0x00,0xea, -0x24,0x36,0x95,0xe5,0x02,0x00,0x13,0xe3,0xd8,0xff,0xff,0x0a,0x01,0x00,0xa0,0xe3, -0x9e,0x0e,0x00,0xeb,0x01,0x40,0x54,0xe2,0xf8,0xff,0xff,0x1a,0x03,0xb0,0xa0,0xe3, -0x1c,0xb0,0x8d,0xe5,0x0b,0x00,0xa0,0xe1,0x80,0xfd,0xff,0xea,0x03,0x00,0xd6,0xe5, -0x24,0x10,0xd6,0xe5,0x0c,0x30,0x8d,0xe5,0x18,0x00,0x8d,0xe5,0x6b,0x0f,0x80,0xe2, -0x40,0x10,0x8d,0xe5,0x03,0x00,0x80,0xe2,0x18,0x10,0x9d,0xe5,0x6b,0x18,0x00,0xeb, -0xf9,0x2f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x82,0xe2,0x67,0x18,0x00,0xeb, -0x18,0x20,0x9d,0xe5,0x40,0x10,0x9d,0xe5,0x38,0x00,0x8d,0xe5,0x92,0x01,0x01,0xe0, -0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0x60,0x18,0x00,0xeb,0xf9,0x2f,0x80,0xe2, -0x00,0x10,0xa0,0xe1,0x03,0x00,0x82,0xe2,0x5c,0x18,0x00,0xeb,0x40,0xe0,0x9d,0xe5, -0x18,0x20,0x9d,0xe5,0x0c,0x30,0x9d,0xe5,0xae,0xc0,0xa0,0xe1,0x06,0x11,0x42,0xe2, -0x81,0x10,0xa0,0xe1,0x0c,0xc4,0xa0,0xe1,0xeb,0xfd,0xff,0xea,0x03,0x80,0xd4,0xe5, -0x24,0xe0,0xd4,0xe5,0x6b,0x0f,0x88,0xe2,0x08,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2, -0x18,0xe0,0x8d,0xe5,0x4d,0x18,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1, -0x03,0x00,0x83,0xe2,0x49,0x18,0x00,0xeb,0x18,0x10,0x9d,0xe5,0x34,0x00,0x8d,0xe5, -0x98,0x01,0x01,0xe0,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0x43,0x18,0x00,0xeb, -0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2,0x3f,0x18,0x00,0xeb, -0x18,0x10,0x9d,0xe5,0xa1,0x30,0xa0,0xe1,0x06,0x11,0x48,0xe2,0x81,0x10,0xa0,0xe1, -0x03,0x34,0xa0,0xe1,0x18,0x30,0x8d,0xe5,0xb4,0xfe,0xff,0xea,0x32,0x33,0xa0,0xe3, -0x3c,0xb0,0x9d,0xe5,0x10,0x36,0x93,0xe5,0x0c,0x30,0x8b,0xe5,0x3f,0xfe,0xff,0xea, -0x68,0x9f,0x00,0x00,0xcc,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x7c,0xf2,0xff,0xff, -0xd0,0x10,0x00,0x00,0x4c,0xf2,0xff,0xff,0xa0,0xf2,0xff,0xff,0x40,0x00,0x00,0x00, -0x00,0x00,0xdb,0x0c,0x4f,0x00,0x64,0x01,0x01,0x20,0x00,0x00,0xcb,0x00,0x7f,0x00, -0xd3,0x4d,0x62,0x10,0x3f,0x0d,0x03,0x00,0x40,0x0d,0x03,0x00,0x4a,0x0c,0x02,0x00, -0x00,0x35,0x0c,0x00,0x38,0x40,0x2d,0xe9,0x00,0x10,0xa0,0xe1,0x68,0x40,0x9f,0xe5, -0x06,0x00,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x60,0x20,0x9f,0xe5,0x04,0x40,0x8f,0xe0, -0x02,0x20,0x84,0xe0,0x08,0x20,0x92,0xe5,0x01,0x00,0x52,0xe3,0x08,0x20,0xa0,0x13, -0xc0,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3,0x38,0x80,0xbd,0x18,0x40,0x50,0x9f,0xe5, -0x00,0x30,0xa0,0xe1,0x01,0x20,0xa0,0xe3,0x0d,0x00,0xa0,0xe3,0x05,0x10,0x94,0xe7, -0x04,0x10,0x91,0xe5,0xb7,0xfc,0xff,0xeb,0x00,0x00,0x50,0xe3,0x38,0x80,0xbd,0x18, -0x05,0x30,0x94,0xe7,0x0c,0x30,0x93,0xe5,0xa3,0x2b,0xa0,0xe1,0xa3,0x33,0x82,0xe1, -0x01,0x00,0x13,0xe3,0x0b,0x00,0xa0,0x13,0x38,0x80,0xbd,0xe8,0xa4,0x92,0x00,0x00, -0xd0,0x10,0x00,0x00,0xcc,0x10,0x00,0x00,0x32,0x23,0xa0,0xe3,0xf0,0x4f,0x2d,0xe9, -0x30,0x76,0x92,0xe5,0x84,0xd0,0x4d,0xe2,0x00,0x80,0xa0,0xe1,0xbc,0x59,0x9f,0xe5, -0x0f,0x08,0x17,0xe3,0x2c,0x36,0x92,0xe5,0x05,0x50,0x8f,0xe0,0x7e,0x01,0x00,0x0a, -0x02,0x34,0x83,0xe3,0xa8,0x49,0x9f,0xe5,0x02,0x60,0xa0,0xe1,0x2c,0x36,0x82,0xe5, -0x02,0x00,0x00,0xea,0x15,0x0e,0x00,0xeb,0x01,0x40,0x54,0xe2,0x10,0x00,0x00,0x0a, -0x2c,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x04,0x13,0xe3,0xf8,0xff,0xff,0x1a, -0x07,0x06,0x17,0xe3,0x0d,0x00,0x00,0x0a,0x32,0x23,0xa0,0xe3,0x01,0x33,0x83,0xe3, -0x02,0x60,0xa0,0xe1,0x2c,0x36,0x82,0xe5,0x2c,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x03,0x13,0xe3,0x05,0x00,0x00,0x0a,0x04,0x0e,0x00,0xeb,0x01,0x40,0x54,0xe2, -0xf8,0xff,0xff,0x1a,0x03,0x00,0xa0,0xe3,0x84,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x00,0x00,0x58,0xe3,0x32,0x43,0xa0,0xe3,0x30,0x76,0x84,0xe5,0x88,0x00,0x00,0x0a, -0x30,0x39,0x9f,0xe5,0x02,0x60,0xa0,0xe3,0x2c,0x79,0x9f,0xe5,0x2c,0x99,0x9f,0xe5, -0x03,0x30,0x85,0xe0,0x28,0x89,0x9f,0xe5,0x04,0x30,0x8d,0xe5,0x24,0x39,0x9f,0xe5, -0x09,0x90,0x85,0xe0,0x07,0x00,0x95,0xe7,0x1c,0x19,0x9f,0xe5,0x03,0x30,0x85,0xe0, -0x18,0x00,0x8d,0xe5,0x14,0x10,0x8d,0xe5,0x08,0x30,0x8d,0xe5,0x30,0x36,0x94,0xe5, -0xec,0xa8,0x9f,0xe5,0x30,0x36,0x84,0xe5,0x30,0x36,0x94,0xe5,0x00,0x30,0xa0,0xe3, -0x08,0x36,0x84,0xe5,0x0c,0x86,0x84,0xe5,0x04,0x00,0x00,0xea,0x01,0x00,0x13,0xe3, -0xc5,0x01,0x00,0x1a,0xe1,0x0d,0x00,0xeb,0x01,0xa0,0x5a,0xe2,0x03,0x00,0x00,0x0a, -0x30,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3,0x0f,0x08,0x13,0xe3,0xf6,0xff,0xff,0x0a, -0x0c,0x30,0xd9,0xe5,0x00,0x00,0x53,0xe3,0x01,0x10,0xa0,0x13,0x03,0x00,0x00,0x1a, -0x07,0x30,0x95,0xe7,0x08,0x10,0x93,0xe5,0x02,0x00,0x51,0xe3,0x03,0x10,0xa0,0x13, -0x00,0x00,0xa0,0xe3,0x88,0xa8,0x9f,0xe5,0x7f,0xf7,0xff,0xeb,0x0f,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0xed,0xf9,0xff,0xeb,0x00,0x20,0xa0,0xe3,0x8c,0x08,0x9f,0xe5, -0x22,0x10,0xa0,0xe3,0xa8,0xf2,0xff,0xeb,0x80,0x08,0x9f,0xe5,0x01,0x10,0xa0,0xe3, -0x1c,0xf3,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xe3,0xf9,0xff,0xeb, -0x01,0x34,0xa0,0xe3,0x2c,0x36,0x84,0xe5,0x02,0x00,0x00,0xea,0xbf,0x0d,0x00,0xeb, -0x01,0xa0,0x5a,0xe2,0x95,0x01,0x00,0x0a,0x2c,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x01,0x04,0x13,0xe3,0xf8,0xff,0xff,0x1a,0x44,0x28,0x9f,0xe5,0x32,0x33,0xa0,0xe3, -0x1c,0xa8,0x9f,0xe5,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0xb3,0x0d,0x00,0xeb, -0x01,0xa0,0x5a,0xe2,0x89,0x01,0x00,0x0a,0x2c,0x36,0x94,0xe5,0x01,0x00,0xa0,0xe3, -0x32,0x23,0xa0,0xe3,0x02,0x00,0x13,0xe3,0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5, -0x40,0x36,0x92,0xe5,0x01,0x04,0x13,0xe3,0x0f,0x2c,0xa0,0x13,0x02,0x00,0x00,0x1a, -0x02,0x04,0x13,0xe3,0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13,0x07,0xa0,0x95,0xe7, -0x02,0x06,0x13,0xe3,0x00,0x30,0xa0,0xe3,0x28,0x26,0x84,0xe5,0x60,0xc0,0x8d,0xe2, -0x20,0xe0,0x8d,0xe2,0x38,0x32,0xca,0xe5,0x01,0x30,0xa0,0x13,0x38,0x32,0xca,0x15, -0x04,0xb0,0x9d,0xe5,0x0f,0x00,0xbb,0xe8,0x0c,0xb0,0x8d,0xe5,0x30,0xb0,0x9a,0xe5, -0x10,0xb0,0x8d,0xe5,0xbc,0xb7,0x9f,0xe5,0x34,0xb6,0x84,0xe5,0x0c,0xb0,0x9d,0xe5, -0x0f,0x00,0xac,0xe8,0x10,0x00,0x9d,0xe5,0x00,0x00,0x50,0xe3,0x0f,0x00,0x9b,0xe8, -0x0f,0x00,0x8c,0xe8,0x08,0xc0,0x9d,0xe5,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0x9c,0xe8,0x0f,0x00,0x8e,0xe8,0x2c,0xb6,0x94,0xe5,0x04,0xb0,0xcb,0xe3, -0x2c,0xb6,0x84,0xe5,0xee,0x00,0x00,0x0a,0x10,0xc0,0x9d,0xe5,0x01,0x00,0x5c,0xe3, -0x87,0x01,0x00,0x0a,0x32,0x00,0xa0,0xe3,0x00,0xc0,0xa0,0xe3,0x16,0xe0,0xa0,0xe3, -0x10,0xc0,0x8d,0xe5,0x2a,0x10,0xa0,0xe3,0x1c,0x00,0x8d,0xe5,0x0c,0xe0,0x8d,0xe5, -0xeb,0x00,0x00,0xea,0x32,0x33,0xa0,0xe3,0x18,0xb0,0x9d,0xe5,0x10,0x36,0x93,0xe5, -0x0c,0x30,0x8b,0xe5,0x28,0x00,0xa0,0xe3,0x70,0x0d,0x00,0xeb,0x32,0x33,0xa0,0xe3, -0x24,0x36,0x93,0xe5,0x0f,0x36,0x03,0xe2,0x0f,0x06,0x53,0xe3,0x00,0x00,0xa0,0x03, -0x68,0xff,0xff,0x0a,0xf4,0x36,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x0c,0x30,0xd3,0xe5, -0x00,0x00,0x53,0xe3,0x01,0x10,0xa0,0x13,0xcb,0x00,0x00,0x0a,0x00,0x00,0xa0,0xe3, -0xcc,0x46,0x9f,0xe5,0x10,0xf7,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x7e,0xf9,0xff,0xeb,0x00,0x20,0xa0,0xe3,0xd0,0x06,0x9f,0xe5,0x22,0x10,0xa0,0xe3, -0x39,0xf2,0xff,0xeb,0xc4,0x06,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0xad,0xf2,0xff,0xeb, -0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0x74,0xf9,0xff,0xeb,0x32,0x33,0xa0,0xe3, -0x01,0x24,0xa0,0xe3,0x03,0x60,0xa0,0xe1,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea, -0x4e,0x0d,0x00,0xeb,0x01,0x40,0x54,0xe2,0xa8,0x00,0x00,0x0a,0x2c,0x36,0x96,0xe5, -0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x01,0x04,0x13,0xe3,0xf7,0xff,0xff,0x1a, -0x7c,0x36,0x9f,0xe5,0x02,0x60,0xa0,0xe1,0x54,0x46,0x9f,0xe5,0x2c,0x36,0x82,0xe5, -0x02,0x00,0x00,0xea,0x41,0x0d,0x00,0xeb,0x01,0x40,0x54,0xe2,0x9b,0x00,0x00,0x0a, -0x2c,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5,0x40,0x36,0x92,0xe5,0x01,0x04,0x13,0xe3, -0x0f,0x2c,0xa0,0x13,0x34,0x01,0x00,0x0a,0x1c,0x76,0x9f,0xe5,0x02,0x06,0x13,0xe3, -0x10,0xb6,0x9f,0xe5,0x32,0x33,0xa0,0xe3,0x28,0x26,0x83,0xe5,0x00,0x30,0xa0,0xe3, -0x07,0x40,0x95,0xe7,0x32,0x83,0xa0,0xe3,0x08,0x66,0x9f,0xe5,0x0b,0xb0,0x85,0xe0, -0x60,0xe0,0x8d,0xe2,0x20,0xc0,0x8d,0xe2,0x38,0x32,0xc4,0xe5,0x01,0x30,0xa0,0x13, -0x38,0x32,0xc4,0x15,0x06,0x90,0x85,0xe0,0x0f,0x00,0xbb,0xe8,0xf4,0x65,0x9f,0xe5, -0x30,0xa0,0x94,0xe5,0x34,0x66,0x88,0xe5,0x09,0x60,0xa0,0xe1,0x0f,0x00,0xae,0xe8, -0x00,0x00,0x5a,0xe3,0x0f,0x00,0x9b,0xe8,0x0f,0x00,0x8e,0xe8,0x0f,0x00,0xb6,0xe8, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0xb6,0xe8,0x0f,0x00,0xac,0xe8,0x0f,0x00,0xb6,0xe8, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0x96,0xe8,0x0f,0x00,0x8c,0xe8,0x2c,0x66,0x98,0xe5, -0x04,0x60,0xc6,0xe3,0x2c,0x66,0x88,0xe5,0x13,0x01,0x00,0x0a,0x01,0x00,0x5a,0xe3, -0x46,0x01,0x00,0x0a,0x32,0x00,0xa0,0xe3,0x00,0xa0,0xa0,0xe3,0x2a,0x10,0xa0,0xe3, -0x00,0x90,0xa0,0xe1,0x16,0x80,0xa0,0xe3,0x34,0x32,0xd4,0xe5,0x00,0x00,0x53,0xe3, -0x1b,0x00,0x00,0x0a,0xa3,0xe0,0xa0,0xe1,0x80,0x20,0x8d,0xe2,0x07,0x30,0x03,0xe2, -0x03,0xc1,0x82,0xe0,0x80,0xb0,0x8d,0xe2,0x3c,0x30,0x0e,0xe2,0x35,0x22,0xd4,0xe5, -0x03,0x30,0x8b,0xe0,0x20,0xc0,0x1c,0xe5,0x60,0x30,0x13,0xe5,0xfa,0xef,0xa0,0xe3, -0x9e,0x02,0x02,0xe0,0x9c,0x03,0x03,0xe0,0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2, -0x92,0x30,0x20,0xe0,0x40,0x25,0x9f,0xe5,0x40,0x35,0x9f,0xe5,0x90,0xc3,0x83,0xe0, -0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x84,0xe5,0x30,0x35,0x9f,0x95, -0x48,0x32,0x84,0x95,0x02,0x00,0x00,0x9a,0x28,0x25,0x9f,0xe5,0x02,0x00,0x53,0xe1, -0x48,0x22,0x84,0x85,0x04,0x05,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0xff,0x6c,0xc6,0xe3, -0xdc,0x44,0x9f,0xe5,0xc4,0xf1,0xff,0xeb,0x06,0xa0,0x8a,0xe1,0x32,0x33,0xa0,0xe3, -0x03,0xb0,0xa0,0xe1,0x2c,0xa6,0x83,0xe5,0x02,0x00,0x00,0xea,0xdf,0x0c,0x00,0xeb, -0x01,0x40,0x54,0xe2,0x29,0x00,0x00,0x0a,0x2c,0x36,0x9b,0xe5,0x01,0x00,0xa0,0xe3, -0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x07,0x40,0x95,0xe7,0x32,0x33,0xa0,0xe3, -0x2c,0x66,0x93,0xe5,0x1b,0x0e,0xa0,0xe3,0x08,0x10,0xa0,0xe1,0x48,0x32,0x94,0xe5, -0x04,0x60,0x86,0xe3,0x93,0x00,0x00,0xe0,0x01,0x00,0x40,0xe2,0x08,0x00,0x80,0xe0, -0xaa,0x16,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x0d,0x20,0x83,0xe2, -0x11,0x22,0xa0,0xe1,0x02,0x00,0x50,0xe1,0xf8,0x00,0x00,0x9a,0x01,0x30,0x83,0xe2, -0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0x8c,0x34,0x9f,0xe5,0x0e,0x28,0xa0,0xe3, -0x99,0x03,0x03,0xe0,0x70,0x14,0x9f,0xe5,0xc3,0x3c,0x83,0xe2,0x50,0x30,0x83,0xe2, -0x01,0x00,0x53,0xe1,0x48,0x32,0x84,0xe5,0x64,0x34,0x9f,0x95,0x48,0x32,0x84,0x95, -0x02,0x00,0x00,0x9a,0x5c,0x14,0x9f,0xe5,0x01,0x00,0x53,0xe1,0x48,0x12,0x84,0x85, -0x0f,0x68,0xc6,0xe3,0x32,0x33,0xa0,0xe3,0x06,0x20,0x82,0xe1,0x2c,0x26,0x83,0xe5, -0x07,0x30,0x95,0xe7,0x32,0x23,0xa0,0xe3,0x1c,0x14,0x9f,0xe5,0x28,0x06,0x92,0xe5, -0x08,0x30,0x93,0xe5,0x01,0xc0,0x95,0xe7,0x02,0x00,0xc0,0xe3,0x01,0x40,0x03,0xe2, -0x02,0x00,0x53,0xe3,0x84,0x00,0x80,0xe1,0xbc,0x30,0x8c,0xe5,0x20,0x10,0xa0,0x03, -0x00,0x10,0xa0,0x13,0x20,0x30,0xc0,0xe3,0x03,0x30,0x81,0xe1,0x28,0x36,0x82,0xe5, -0x32,0x33,0xa0,0xe3,0x24,0x06,0x93,0xe5,0x0f,0x06,0x00,0xe2,0x0f,0x06,0x50,0xe3, -0x08,0x00,0xa0,0x13,0x00,0x00,0xa0,0x03,0x9a,0xfe,0xff,0xea,0x07,0x06,0x17,0xe3, -0xac,0x43,0x9f,0xe5,0x8b,0xfe,0xff,0x1a,0x98,0xfe,0xff,0xea,0xa8,0x33,0x9f,0xe5, -0x03,0x30,0x95,0xe7,0x08,0x10,0x93,0xe5,0x02,0x00,0x51,0xe3,0x03,0x10,0xa0,0x13, -0x2d,0xff,0xff,0xea,0x02,0x0a,0xa0,0xe3,0x22,0x10,0xa0,0xe3,0x10,0x00,0x8d,0xe5, -0xfa,0x0f,0xa0,0xe3,0x2a,0x20,0xa0,0xe3,0x12,0x30,0xa0,0xe3,0x1c,0x20,0x8d,0xe5, -0x0c,0x30,0x8d,0xe5,0x34,0x32,0xda,0xe5,0x00,0x00,0x53,0xe3,0x1a,0x00,0x00,0x0a, -0xa3,0x20,0xa0,0xe1,0x80,0xc0,0x8d,0xe2,0x07,0x30,0x03,0xe2,0x35,0xe2,0xda,0xe5, -0x03,0x31,0x8c,0xe0,0x3c,0x20,0x02,0xe2,0x02,0x20,0x8c,0xe0,0x60,0xc0,0x12,0xe5, -0xfa,0x2f,0xa0,0xe3,0x20,0x30,0x13,0xe5,0x9e,0x02,0x02,0xe0,0x9c,0x03,0x03,0xe0, -0x58,0xc3,0x9f,0xe5,0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2,0x90,0x32,0x23,0xe0, -0x44,0x23,0x9f,0xe5,0x9c,0xe3,0x83,0xe0,0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1, -0x48,0x32,0x8a,0xe5,0x38,0x33,0x9f,0x95,0x48,0x32,0x8a,0x95,0x02,0x00,0x00,0x9a, -0x30,0x23,0x9f,0xe5,0x02,0x00,0x53,0xe1,0x48,0x22,0x8a,0x85,0x0c,0x03,0x9f,0xe5, -0x00,0x20,0xa0,0xe3,0x48,0xf1,0xff,0xeb,0x10,0x00,0x9d,0xe5,0xff,0xbc,0xcb,0xe3, -0xdc,0xa2,0x9f,0xe5,0x0b,0xb0,0x80,0xe1,0x2c,0xb6,0x84,0xe5,0x02,0x00,0x00,0xea, -0x62,0x0c,0x00,0xeb,0x01,0xa0,0x5a,0xe2,0x29,0x00,0x00,0x0a,0x2c,0x36,0x94,0xe5, -0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x07,0xa0,0x95,0xe7, -0x32,0x33,0xa0,0xe3,0x2c,0xb6,0x93,0xe5,0x1b,0x2e,0xa0,0xe3,0x0c,0x10,0x9d,0xe5, -0x48,0x32,0x9a,0xe5,0x04,0xb0,0x8b,0xe3,0x92,0x03,0x03,0xe0,0x01,0x00,0x43,0xe2, -0x01,0x00,0x80,0xe0,0x2d,0x16,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x0d,0x20,0x83,0xe2,0x11,0x22,0xa0,0xe1,0x02,0x00,0x50,0xe1,0x73,0x00,0x00,0x9a, -0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0x98,0x22,0x9f,0xe5, -0x0e,0x38,0xa0,0xe3,0x1c,0xe0,0x9d,0xe5,0x7c,0x12,0x9f,0xe5,0x9e,0x02,0x02,0xe0, -0xc3,0x2c,0x82,0xe2,0x50,0x20,0x82,0xe2,0x01,0x00,0x52,0xe1,0x48,0x22,0x8a,0xe5, -0x6c,0x22,0x9f,0x95,0x48,0x22,0x8a,0x95,0x02,0x00,0x00,0x9a,0x64,0x12,0x9f,0xe5, -0x01,0x00,0x52,0xe1,0x48,0x12,0x8a,0x85,0x0f,0xb8,0xcb,0xe3,0x0b,0x30,0x83,0xe1, -0x2c,0x36,0x84,0xe5,0x07,0x30,0x95,0xe7,0x14,0x20,0x9d,0xe5,0x28,0x06,0x94,0xe5, -0x08,0x30,0x93,0xe5,0x02,0x10,0x95,0xe7,0x02,0x00,0xc0,0xe3,0x01,0xc0,0x03,0xe2, -0x02,0x00,0x53,0xe3,0x8c,0x00,0x80,0xe1,0xbc,0x30,0x81,0xe5,0x20,0x20,0xa0,0x03, -0x00,0x20,0xa0,0x13,0x20,0x30,0xc0,0xe3,0x03,0x20,0x82,0xe1,0x28,0x26,0x84,0xe5, -0x01,0x60,0x56,0xe2,0x38,0xfe,0xff,0x1a,0x28,0x00,0xa0,0xe3,0x23,0x0c,0x00,0xeb, -0x32,0x33,0xa0,0xe3,0x24,0x36,0x93,0xe5,0x0f,0x36,0x03,0xe2,0x0f,0x06,0x53,0xe3, -0x00,0x00,0xa0,0x03,0xb2,0xfe,0xff,0x1a,0x1a,0xfe,0xff,0xea,0xb0,0x41,0x9f,0xe5, -0x32,0x63,0xa0,0xe3,0x02,0x00,0x00,0xea,0x18,0x0c,0x00,0xeb,0x01,0x40,0x54,0xe2, -0xa3,0xfe,0xff,0x0a,0x24,0x36,0x96,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3, -0x01,0x00,0x13,0xe3,0xf7,0xff,0xff,0x1a,0x07,0x30,0x95,0xe7,0x48,0x42,0x93,0xe5, -0x00,0x00,0x54,0xe3,0x96,0xfe,0xff,0x0a,0x24,0x36,0x92,0xe5,0x02,0x00,0x13,0xe3, -0x93,0xfe,0xff,0x0a,0x02,0x60,0xa0,0xe1,0x02,0x00,0x00,0xea,0x24,0x36,0x96,0xe5, -0x02,0x00,0x13,0xe3,0x8e,0xfe,0xff,0x0a,0x01,0x00,0xa0,0xe3,0x03,0x0c,0x00,0xeb, -0x01,0x40,0x54,0xe2,0xf8,0xff,0xff,0x1a,0x8d,0xfe,0xff,0xea,0x02,0x04,0x13,0xe3, -0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13,0xc6,0xfe,0xff,0xea,0x02,0xaa,0xa0,0xe3, -0x22,0x10,0xa0,0xe3,0xfa,0x0f,0xa0,0xe3,0x2a,0x90,0xa0,0xe3,0x12,0x80,0xa0,0xe3, -0xec,0xfe,0xff,0xea,0x03,0xe0,0xda,0xe5,0x24,0x00,0xda,0xe5,0x0e,0x10,0xa0,0xe1, -0x0c,0xe0,0x8d,0xe5,0x10,0x00,0x8d,0xe5,0x6b,0x0f,0x8e,0xe2,0x03,0x00,0x80,0xe2, -0xca,0x15,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2, -0xc6,0x15,0x00,0xeb,0x0c,0x20,0x9d,0xe5,0x10,0x10,0x9d,0xe5,0x1c,0x00,0x8d,0xe5, -0x92,0x01,0x01,0xe0,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2,0xbf,0x15,0x00,0xeb, -0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2,0xbb,0x15,0x00,0xeb, -0x10,0xc0,0x9d,0xe5,0x0c,0xe0,0x9d,0xe5,0xac,0x30,0xa0,0xe1,0x06,0x11,0x4e,0xe2, -0x81,0x10,0xa0,0xe1,0x03,0x34,0xa0,0xe1,0x10,0x30,0x8d,0xe5,0x4c,0xff,0xff,0xea, -0xf9,0x2f,0x82,0xe2,0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x38,0xa0,0xe1, -0xb8,0x20,0x9f,0xe5,0x91,0xc2,0x82,0xe0,0x22,0x23,0xa0,0xe1,0x88,0xff,0xff,0xea, -0xf9,0x2f,0x82,0xe2,0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x28,0xa0,0xe1, -0x98,0x30,0x9f,0xe5,0x91,0x03,0x83,0xe0,0x23,0x33,0xa0,0xe1,0x03,0xff,0xff,0xea, -0x03,0x80,0xd4,0xe5,0x24,0xa0,0xd4,0xe5,0x6b,0x0f,0x88,0xe2,0x08,0x10,0xa0,0xe1, -0x03,0x00,0x80,0xe2,0x9d,0x15,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1, -0x03,0x00,0x83,0xe2,0x99,0x15,0x00,0xeb,0x98,0x0a,0x01,0xe0,0x00,0x90,0xa0,0xe1, -0xaa,0xa0,0xa0,0xe1,0x0a,0xa4,0xa0,0xe1,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2, -0x92,0x15,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2, -0x8e,0x15,0x00,0xeb,0x06,0x11,0x48,0xe2,0x81,0x10,0xa0,0xe1,0xa5,0xfe,0xff,0xea, -0x18,0x92,0x00,0x00,0xa0,0x86,0x01,0x00,0x4c,0xf2,0xff,0xff,0xcc,0x10,0x00,0x00, -0xd0,0x10,0x00,0x00,0x00,0x00,0xdb,0x0c,0xa0,0xf2,0xff,0xff,0x40,0x00,0x00,0x00, -0x4f,0x00,0x64,0x01,0x01,0x20,0x00,0x00,0xcb,0x00,0x7f,0x00,0x3f,0x0d,0x03,0x00, -0xd3,0x4d,0x62,0x10,0x40,0x0d,0x03,0x00,0x00,0x35,0x0c,0x00,0x4a,0x0c,0x02,0x00, -0x38,0x40,0x2d,0xe9,0x2b,0x00,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x6c,0x40,0x9f,0xe5, -0x01,0x14,0xa0,0xe3,0x08,0x20,0xa0,0xe3,0x1e,0xfa,0xff,0xeb,0x00,0x30,0x50,0xe2, -0x04,0x40,0x8f,0xe0,0x04,0x00,0x00,0x0a,0x54,0x30,0x9f,0xe5,0x00,0x20,0xa0,0xe3, -0x03,0x30,0x94,0xe7,0xdc,0x20,0x83,0xe5,0x38,0x80,0xbd,0xe8,0x44,0x50,0x9f,0xe5, -0x0d,0x00,0xa0,0xe3,0x01,0x20,0xa0,0xe3,0x05,0x10,0x94,0xe7,0x04,0x10,0x91,0xe5, -0x10,0xfa,0xff,0xeb,0x00,0x00,0x50,0xe3,0xf2,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x0c,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0xee,0xff,0xff,0xba,0x10,0x30,0x9f,0xe5, -0x01,0x20,0xa0,0xe3,0x03,0x30,0x94,0xe7,0xdc,0x20,0x83,0xe5,0x38,0x80,0xbd,0xe8, -0x00,0x88,0x00,0x00,0x40,0x00,0x00,0x00,0xcc,0x10,0x00,0x00,0x88,0x30,0x9f,0xe5, -0xf0,0x0f,0x2d,0xe9,0xa0,0x60,0xa0,0xe1,0x80,0xa0,0x9f,0xe5,0x20,0x92,0xa0,0xe1, -0xa0,0xb2,0xa0,0xe1,0x03,0x30,0x8f,0xe0,0x74,0x20,0x9f,0xe5,0x20,0x51,0xa0,0xe1, -0x70,0x80,0x9f,0xe5,0x0a,0x40,0x83,0xe0,0x01,0x70,0x00,0xe2,0x01,0x60,0x06,0xe2, -0x02,0x20,0x93,0xe7,0x01,0x00,0x09,0xe2,0x01,0x90,0x0b,0xe2,0x03,0x50,0x05,0xe2, -0x08,0x60,0x84,0xe5,0x08,0xc0,0x83,0xe0,0x04,0x00,0xc4,0xe5,0x01,0x70,0x87,0xe2, -0x0c,0x90,0xc4,0xe5,0x16,0x40,0xa0,0xe3,0x0a,0x50,0x83,0xe7,0x08,0x40,0xc3,0xe7, -0x00,0x30,0xa0,0xe3,0x04,0x70,0x8c,0xe5,0x08,0x30,0xcc,0xe5,0x00,0xc0,0x81,0xe5, -0xa0,0x70,0x82,0xe5,0xa4,0x60,0x82,0xe5,0xa8,0x50,0x82,0xe5,0xac,0x00,0x82,0xe5, -0xb0,0x90,0x82,0xe5,0xf0,0x0f,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x7c,0x87,0x00,0x00, -0xd0,0x10,0x00,0x00,0x40,0x00,0x00,0x00,0xe0,0x10,0x00,0x00,0x00,0x30,0xd0,0xe5, -0x01,0x30,0x43,0xe2,0x2a,0x00,0x53,0xe3,0x00,0x00,0xa0,0x83,0x1e,0xff,0x2f,0x81, -0x04,0x30,0x90,0xe5,0x01,0x30,0x43,0xe2,0x01,0x00,0x53,0xe3,0x01,0x00,0x00,0x9a, -0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x08,0x00,0xd0,0xe5,0x10,0x00,0x50,0xe3, -0x00,0x00,0xa0,0x83,0x01,0x00,0xa0,0x93,0x1e,0xff,0x2f,0xe1,0x1c,0x30,0x9f,0xe5, -0x1c,0x00,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x00,0x30,0x93,0xe7,0x00,0x00,0xd3,0xe5, -0x00,0x00,0x81,0xe5,0x01,0x30,0xd3,0xe5,0x00,0x30,0x82,0xe5,0x1e,0xff,0x2f,0xe1, -0xac,0x86,0x00,0x00,0xcc,0x10,0x00,0x00,0xf8,0x4f,0x2d,0xe9,0x02,0x90,0xa0,0xe1, -0xac,0x42,0x9f,0xe5,0x01,0x60,0xa0,0xe1,0x00,0x80,0xa0,0xe1,0x01,0x70,0xa0,0xe3, -0xa0,0x52,0x9f,0xe5,0xa0,0x32,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x9c,0x22,0x9f,0xe5, -0x05,0x10,0x94,0xe7,0x03,0x30,0x94,0xe7,0x02,0xc0,0xd4,0xe7,0x01,0x00,0xd1,0xe5, -0xd4,0x20,0x93,0xe5,0x00,0x00,0x58,0xe3,0x01,0x00,0x5c,0x03,0x01,0x20,0x82,0xe2, -0x17,0x70,0xa0,0xe1,0xd4,0x20,0x83,0xe5,0x01,0x00,0x00,0x1a,0x00,0x00,0x56,0xe3, -0x77,0x00,0x00,0x0a,0x48,0xa2,0x91,0xe5,0x00,0x00,0x5a,0xe3,0x10,0x00,0x00,0x0a, -0x32,0xb3,0xa0,0xe3,0x24,0x36,0x9b,0xe5,0x04,0x00,0x13,0xe3,0x03,0x00,0x00,0x1a, -0x0b,0x00,0x00,0xea,0x24,0x36,0x9b,0xe5,0x04,0x00,0x13,0xe3,0x07,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x15,0x0b,0x00,0xeb,0x01,0xa0,0x5a,0xe2,0xf8,0xff,0xff,0x1a, -0x01,0x00,0xa0,0xe3,0xeb,0xfc,0xff,0xeb,0x00,0xa0,0x50,0xe2,0x1e,0x00,0x00,0x1a, -0x05,0x10,0x94,0xe7,0x28,0x30,0x91,0xe5,0x00,0xb0,0xd1,0xe5,0x00,0x00,0x53,0xe3, -0x2c,0x30,0x81,0x05,0x08,0xb0,0xa0,0x01,0x28,0x00,0x00,0x0a,0x33,0xbb,0xa0,0xe1, -0x0b,0x00,0x58,0xe1,0x08,0xb0,0xa0,0x31,0x01,0x80,0xa0,0x33,0x51,0x00,0x00,0x2a, -0x2c,0x30,0x91,0xe5,0x08,0x00,0x53,0xe1,0x20,0x00,0x00,0x0a,0x3f,0x12,0xd1,0xe5, -0x06,0x00,0xa0,0xe3,0xd8,0x21,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0x07,0x10,0xc1,0xe3, -0x02,0x20,0x84,0xe0,0x01,0x10,0x88,0xe1,0x08,0x20,0x92,0xe5,0x01,0x14,0xa0,0xe1, -0x3b,0x16,0x81,0xe3,0x01,0x00,0x52,0xe3,0x03,0x18,0x81,0xe3,0x08,0x20,0xa0,0x13, -0x78,0xf9,0xff,0xeb,0x00,0xa0,0x50,0xe2,0x01,0x00,0x00,0x0a,0x0a,0x00,0xa0,0xe1, -0xf8,0x8f,0xbd,0xe8,0x05,0x10,0x94,0xe7,0x0a,0x30,0xa0,0xe1,0x0d,0x00,0xa0,0xe3, -0x01,0x20,0xa0,0xe3,0x04,0x10,0x91,0xe5,0x6e,0xf9,0xff,0xeb,0x00,0xa0,0x50,0xe2, -0xf5,0xff,0xff,0x1a,0x05,0x20,0x94,0xe7,0x0c,0x30,0x92,0xe5,0xa3,0x1b,0xa0,0xe1, -0xa3,0x33,0x81,0xe1,0x01,0x00,0x13,0xe3,0x52,0x00,0x00,0x1a,0x2c,0x80,0x82,0xe5, -0x10,0x00,0xa0,0xe3,0x07,0x10,0xa0,0xe1,0x01,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3, -0x60,0xf9,0xff,0xeb,0x00,0xa0,0x50,0xe2,0xe7,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7, -0x0c,0x20,0x93,0xe5,0xa2,0x1e,0xa0,0xe1,0x22,0x2a,0x81,0xe1,0x01,0x00,0x12,0xe3, -0x44,0x00,0x00,0x1a,0x07,0x0a,0xa0,0xe1,0x32,0x23,0xa0,0xe3,0x02,0x10,0xd3,0xe5, -0x32,0x73,0xa0,0xe3,0x20,0x0a,0xa0,0xe1,0x17,0x0a,0x80,0xe3,0x04,0x06,0x82,0xe5, -0x1b,0x11,0x86,0xe0,0x26,0x20,0xd3,0xe5,0x11,0x00,0xa0,0xe3,0x00,0x00,0x52,0xe3, -0x01,0x20,0xa0,0xe3,0x01,0x30,0xd3,0x05,0x00,0x96,0x87,0xe5,0x11,0x13,0xa0,0x01, -0x02,0x30,0xa0,0xe1,0x47,0xf9,0xff,0xeb,0x00,0xa0,0x50,0xe2,0xce,0xff,0xff,0x1a, -0x05,0x40,0x94,0xe7,0x0c,0x30,0x94,0xe5,0xa3,0x1e,0xa0,0xe1,0x83,0x25,0xa0,0xe1, -0x23,0x1f,0x81,0xe1,0x01,0x10,0x01,0xe2,0xa3,0x3f,0x81,0xe1,0xa2,0x2f,0x93,0xe1, -0x12,0x00,0x00,0x1a,0x02,0x30,0xa0,0xe3,0x1c,0x30,0x84,0xe5,0xaa,0x0a,0x00,0xeb, -0x20,0x00,0x84,0xe5,0xc0,0xff,0xff,0xea,0x8b,0x30,0xa0,0xe1,0x03,0x00,0x58,0xe1, -0x08,0xb0,0x6b,0x30,0x08,0xb0,0x63,0x20,0x02,0x80,0xa0,0x33,0x00,0x80,0xa0,0x23, -0xa6,0xff,0xff,0xea,0x09,0x00,0xa0,0xe1,0x93,0x1f,0x81,0xe2,0x07,0x20,0xa0,0xe1, -0x06,0xa0,0xa0,0xe1,0x9b,0x0a,0x00,0xeb,0x0a,0x00,0xa0,0xe1,0xf8,0x8f,0xbd,0xe8, -0x2c,0x36,0x97,0xe5,0x07,0x50,0xa0,0xe1,0x68,0x40,0x9f,0xe5,0x01,0x33,0x83,0xe3, -0x2c,0x36,0x87,0xe5,0x02,0x00,0x00,0xea,0x9c,0x0a,0x00,0xeb,0x01,0x40,0x54,0xe2, -0x03,0x00,0x00,0x0a,0x2c,0x36,0x95,0xe5,0x01,0x00,0xa0,0xe3,0x01,0x03,0x13,0xe3, -0xf8,0xff,0xff,0x1a,0x32,0x43,0xa0,0xe3,0x24,0x36,0x94,0xe5,0x0f,0x36,0x03,0xe2, -0x0f,0x06,0x53,0xe3,0x03,0x00,0x00,0x0a,0x08,0xf8,0xff,0xeb,0x0b,0xa0,0xa0,0xe3, -0x24,0x36,0x94,0xe5,0x9c,0xff,0xff,0xea,0x0b,0xa0,0xa0,0xe3,0x0a,0x00,0xa0,0xe1, -0xf8,0x8f,0xbd,0xe8,0x68,0x86,0x00,0x00,0xcc,0x10,0x00,0x00,0x40,0x00,0x00,0x00, -0xc8,0x10,0x00,0x00,0xd0,0x10,0x00,0x00,0xa0,0x86,0x01,0x00,0x70,0x40,0x2d,0xe9, -0x0c,0x51,0x9f,0xe5,0x0c,0x61,0x9f,0xe5,0x05,0x50,0x8f,0xe0,0x06,0x10,0x95,0xe7, -0x06,0x40,0x85,0xe0,0x1c,0x00,0x91,0xe5,0x02,0x00,0x50,0xe3,0x70,0x80,0xbd,0x18, -0x32,0xc3,0xa0,0xe3,0x30,0x36,0x9c,0xe5,0x7f,0x28,0x13,0xe2,0x0b,0x00,0x00,0x1a, -0x08,0x00,0x13,0xe3,0x19,0x00,0x00,0x1a,0x02,0x00,0x13,0xe3,0x1c,0x00,0x00,0x0a, -0x01,0x20,0xa0,0xe3,0x1c,0x20,0x81,0xe5,0x30,0x36,0x8c,0xe5,0x4c,0x34,0xd1,0xe5, -0x00,0x00,0x53,0xe3,0x1f,0x00,0x00,0x0a,0x02,0x00,0xa0,0xe1,0x70,0x80,0xbd,0xe8, -0x01,0x06,0x52,0xe3,0x07,0x30,0xa0,0x03,0x1c,0x30,0x81,0x05,0x06,0x00,0x00,0x0a, -0x06,0x30,0xa0,0xe3,0x1c,0x30,0x81,0xe5,0x9c,0x30,0x9f,0xe5,0x03,0x30,0x95,0xe7, -0xd8,0x20,0x93,0xe5,0x01,0x20,0x82,0xe2,0xd8,0x20,0x83,0xe5,0x01,0x00,0xa0,0xe3, -0x38,0xfc,0xff,0xeb,0x06,0x30,0x95,0xe7,0x1c,0x00,0x93,0xe5,0x70,0x80,0xbd,0xe8, -0x08,0x30,0xa0,0xe3,0x30,0x36,0x8c,0xe5,0x00,0x36,0x9c,0xe5,0x00,0x36,0x8c,0xe5, -0x70,0x80,0xbd,0xe8,0x20,0x00,0x91,0xe5,0x4f,0x0a,0x00,0xeb,0x00,0x30,0x94,0xe5, -0x48,0x22,0x93,0xe5,0x02,0x00,0x50,0xe1,0x0f,0x00,0x00,0x9a,0x03,0x00,0xa0,0xe3, -0x1c,0x00,0x83,0xe5,0x70,0x80,0xbd,0xe8,0x0d,0x00,0xa0,0xe3,0x04,0x10,0x91,0xe5, -0xd0,0xf8,0xff,0xeb,0x00,0x00,0x50,0xe3,0x00,0x30,0x94,0x15,0xf6,0xff,0xff,0x1a, -0x00,0x30,0x94,0xe5,0x0c,0x20,0x93,0xe5,0xa2,0x1b,0xa0,0xe1,0x22,0x1b,0x81,0xe1, -0xa2,0x2a,0x81,0xe1,0x01,0x00,0x12,0xe3,0xef,0xff,0xff,0x1a,0x1c,0x00,0x93,0xe5, -0x70,0x80,0xbd,0xe8,0xa8,0x83,0x00,0x00,0xcc,0x10,0x00,0x00,0x40,0x00,0x00,0x00, -0xf0,0x41,0x2d,0xe9,0x01,0xe0,0xa0,0xe3,0xf8,0x40,0x9f,0xe5,0x0e,0x20,0xa0,0xe1, -0x0e,0x30,0xa0,0xe1,0x32,0xc3,0xa0,0xe3,0xec,0x60,0x9f,0xe5,0x08,0x00,0xa0,0xe3, -0x04,0x40,0x8f,0xe0,0x00,0x10,0xa0,0xe3,0x06,0x50,0x94,0xe7,0x01,0x70,0xd5,0xe5, -0x34,0x80,0x85,0xe2,0x1e,0xe7,0xa0,0xe1,0x0e,0xea,0xa0,0xe1,0x2e,0xea,0xa0,0xe1, -0x17,0xea,0x8e,0xe3,0x04,0xe6,0x8c,0xe5,0x00,0x86,0x8c,0xe5,0xad,0xf8,0xff,0xeb, -0x00,0x70,0x50,0xe2,0x0e,0x00,0x00,0x1a,0x06,0x80,0x94,0xe7,0x0c,0x30,0x98,0xe5, -0x01,0x06,0x13,0xe3,0x0b,0x70,0xa0,0x13,0x09,0x00,0x00,0x1a,0x02,0x30,0xa0,0xe3, -0x1c,0x30,0x88,0xe5,0x14,0x0a,0x00,0xeb,0x20,0x00,0x88,0xe5,0x96,0xff,0xff,0xeb, -0x02,0x00,0x50,0xe3,0xfc,0xff,0xff,0x0a,0x01,0x00,0x50,0xe3,0x08,0x70,0xa0,0x13, -0x01,0x00,0x00,0x0a,0x07,0x00,0xa0,0xe1,0xf0,0x81,0xbd,0xe8,0x06,0x30,0x94,0xe7, -0x16,0x61,0xd5,0xe5,0xff,0x40,0xd5,0xe5,0x26,0x20,0xd3,0xe5,0xfe,0xc0,0xd5,0xe5, -0xfd,0x00,0xd5,0xe5,0x86,0x68,0xa0,0xe1,0xfc,0x10,0xd5,0xe5,0x00,0x00,0x52,0xe3, -0xe7,0x20,0xd5,0xe5,0x28,0x60,0x83,0xe5,0x3b,0x42,0xc3,0xe5,0x3c,0xc2,0xc3,0xe5, -0x3d,0x02,0xc3,0xe5,0x3e,0x12,0xc3,0xe5,0x3f,0x22,0xc3,0xe5,0xec,0xff,0xff,0x0a, -0x0a,0x21,0xd5,0xe5,0x09,0xc1,0xd5,0xe5,0x08,0x01,0xd5,0xe5,0x0b,0x11,0xd5,0xe5, -0x02,0x28,0xa0,0xe1,0x0c,0x24,0x82,0xe1,0x00,0x20,0x82,0xe1,0x01,0x2c,0x82,0xe1, -0x44,0x22,0x83,0xe5,0xe2,0xff,0xff,0xea,0x70,0x82,0x00,0x00,0xcc,0x10,0x00,0x00, -0x32,0x33,0xa0,0xe3,0x10,0x40,0x2d,0xe9,0x2c,0x26,0x93,0xe5,0x0f,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x34,0x40,0x9f,0xe5,0x04,0x20,0xc2,0xe3,0x2c,0x26,0x83,0xe5, -0x28,0x26,0x93,0xe5,0x04,0x40,0x8f,0xe0,0x01,0x2c,0xc2,0xe3,0x28,0x26,0x83,0xe5, -0x0a,0xf6,0xff,0xeb,0x18,0x00,0x9f,0xe5,0x00,0x10,0xa0,0xe3,0x3d,0xef,0xff,0xeb, -0x10,0x30,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0x03,0x20,0x84,0xe7,0x10,0x80,0xbd,0xe8, -0x5c,0x81,0x00,0x00,0x4f,0x00,0x64,0x01,0xcc,0x10,0x00,0x00,0x00,0x30,0xa0,0xe3, -0xf0,0x4f,0x2d,0xe9,0x34,0x32,0xc1,0xe5,0x94,0xd0,0x4d,0xe2,0x35,0x32,0xc1,0xe5, -0x00,0x20,0xd0,0xe5,0xa8,0x4f,0x9f,0xe5,0xa8,0x6f,0x9f,0xe5,0x03,0x20,0xc1,0xe5, -0x04,0x20,0x90,0xe5,0x04,0x40,0x8f,0xe0,0x06,0xc0,0x84,0xe0,0x98,0x5f,0x9f,0xe5, -0x08,0x20,0x81,0xe5,0x08,0x00,0xd0,0xe5,0x39,0x32,0xc1,0xe5,0x4c,0x34,0xc1,0xe5, -0x41,0x02,0xc1,0xe5,0x0c,0x00,0xdc,0xe5,0x80,0xcf,0x9f,0xe5,0x28,0x30,0x81,0xe5, -0x03,0x00,0x50,0xe1,0x30,0x30,0x81,0xe5,0x04,0x30,0xa0,0xe3,0x05,0x10,0x84,0xe7, -0x48,0xc2,0x81,0xe5,0x2c,0x30,0x81,0xe5,0x01,0x10,0xa0,0x13,0x02,0x00,0x00,0x1a, -0x02,0x00,0x52,0xe3,0x02,0x10,0xa0,0x01,0x03,0x10,0xa0,0x13,0x00,0x00,0xa0,0xe3, -0x4c,0x7f,0x9f,0xe5,0x6c,0xf3,0xff,0xeb,0x0f,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0xda,0xf5,0xff,0xeb,0x00,0x20,0xa0,0xe3,0x38,0x0f,0x9f,0xe5,0x22,0x10,0xa0,0xe3, -0x95,0xee,0xff,0xeb,0x2c,0x0f,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0x09,0xef,0xff,0xeb, -0x0f,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xd0,0xf5,0xff,0xeb,0x32,0x33,0xa0,0xe3, -0x01,0x24,0xa0,0xe3,0x03,0x80,0xa0,0xe1,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea, -0xaa,0x09,0x00,0xeb,0x01,0x70,0x57,0xe2,0x63,0x01,0x00,0x0a,0x2c,0x36,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x01,0x04,0x13,0xe3,0xf7,0xff,0xff,0x1a, -0xe4,0x3e,0x9f,0xe5,0x02,0x80,0xa0,0xe1,0xd4,0x7e,0x9f,0xe5,0x2c,0x36,0x82,0xe5, -0x02,0x00,0x00,0xea,0x9d,0x09,0x00,0xeb,0x01,0x70,0x57,0xe2,0x56,0x01,0x00,0x0a, -0x2c,0x36,0x98,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x23,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf7,0xff,0xff,0x0a,0x2c,0x36,0x92,0xe5,0x40,0x36,0x92,0xe5,0x01,0x04,0x13,0xe3, -0x0f,0x2c,0xa0,0x13,0x56,0x01,0x00,0x0a,0x02,0x06,0x13,0xe3,0x32,0x33,0xa0,0xe3, -0x05,0x70,0x94,0xe7,0x70,0x10,0x8d,0xe2,0x28,0x26,0x83,0xe5,0x00,0x30,0xa0,0xe3, -0x88,0x2e,0x9f,0xe5,0x32,0x83,0xa0,0xe3,0x38,0x32,0xc7,0xe5,0x01,0x30,0xa0,0x13, -0x38,0x32,0xc7,0x15,0x30,0x30,0x8d,0xe2,0x1c,0x20,0x8d,0xe5,0x1c,0xc0,0x9d,0xe5, -0x6c,0x0e,0x9f,0xe5,0x14,0x10,0x8d,0xe5,0x0c,0xa0,0x84,0xe0,0x64,0xce,0x9f,0xe5, -0x00,0xe0,0x84,0xe0,0x10,0x30,0x8d,0xe5,0x18,0x00,0x8d,0xe5,0x0f,0x00,0xbe,0xe8, -0x30,0x90,0x97,0xe5,0x34,0xc6,0x88,0xe5,0x14,0xc0,0x9d,0xe5,0x00,0x00,0x59,0xe3, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0x9e,0xe8,0x0a,0xe0,0xa0,0xe1,0x0f,0x00,0x8c,0xe8, -0x10,0xc0,0x9d,0xe5,0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xac,0xe8,0x0f,0x00,0xbe,0xe8, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xac,0xe8,0x0f,0x00,0x9e,0xe8, -0x0f,0x00,0x8c,0xe8,0x2c,0xa6,0x98,0xe5,0x04,0xa0,0xca,0xe3,0x2c,0xa6,0x88,0xe5, -0x25,0x01,0x00,0x0a,0x01,0x00,0x59,0xe3,0xc8,0x03,0x00,0x0a,0x32,0x00,0xa0,0xe3, -0x00,0x90,0xa0,0xe3,0x2a,0x10,0xa0,0xe3,0x00,0xb0,0xa0,0xe1,0x16,0x80,0xa0,0xe3, -0x34,0x22,0xd7,0xe5,0x00,0x00,0x52,0xe3,0x1a,0x00,0x00,0x0a,0xa2,0x30,0xa0,0xe1, -0x90,0xe0,0x8d,0xe2,0x07,0x20,0x02,0xe2,0x35,0xc2,0xd7,0xe5,0x02,0x21,0x8e,0xe0, -0x3c,0x30,0x03,0xe2,0x03,0x30,0x8e,0xe0,0x20,0x20,0x12,0xe5,0xfa,0xef,0xa0,0xe3, -0x60,0x30,0x13,0xe5,0x9e,0x0c,0x0c,0xe0,0x92,0x03,0x03,0xe0,0xf0,0x2d,0x9f,0xe5, -0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2,0x90,0x3c,0x23,0xe0,0x92,0x03,0x83,0xe0, -0xe0,0x2d,0x9f,0xe5,0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x87,0xe5, -0x68,0x3d,0x9f,0x95,0x48,0x32,0x87,0x95,0x02,0x00,0x00,0x9a,0xcc,0x2d,0x9f,0xe5, -0x02,0x00,0x53,0xe1,0x48,0x22,0x87,0x85,0x00,0x20,0xa0,0xe3,0x54,0x0d,0x9f,0xe5, -0x1d,0xee,0xff,0xeb,0xff,0x2c,0xca,0xe3,0x32,0x33,0xa0,0xe3,0x02,0x90,0x89,0xe1, -0x3c,0x7d,0x9f,0xe5,0x03,0xa0,0xa0,0xe1,0x2c,0x96,0x83,0xe5,0x02,0x00,0x00,0xea, -0x36,0x09,0x00,0xeb,0x01,0x70,0x57,0xe2,0x29,0x00,0x00,0x0a,0x2c,0x36,0x9a,0xe5, -0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x05,0x70,0x94,0xe7, -0x32,0x33,0xa0,0xe3,0x2c,0xa6,0x93,0xe5,0x1b,0x2e,0xa0,0xe3,0x08,0x10,0xa0,0xe1, -0x48,0x32,0x97,0xe5,0x04,0xa0,0x8a,0xe3,0x92,0x03,0x03,0xe0,0x01,0x00,0x43,0xe2, -0x08,0x00,0x80,0xe0,0x01,0x13,0x00,0xeb,0x00,0x30,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0x0d,0x20,0x83,0xe2,0x11,0x22,0xa0,0xe1,0x02,0x00,0x50,0xe1,0xd7,0x02,0x00,0x9a, -0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0xd8,0x2c,0x9f,0xe5, -0x0e,0x38,0xa0,0xe3,0x9b,0x02,0x02,0xe0,0x18,0x1d,0x9f,0xe5,0xc3,0x2c,0x82,0xe2, -0x50,0x20,0x82,0xe2,0x01,0x00,0x52,0xe1,0x48,0x22,0x87,0xe5,0x9c,0x2c,0x9f,0x95, -0x48,0x22,0x87,0x95,0x02,0x00,0x00,0x9a,0x00,0x1d,0x9f,0xe5,0x01,0x00,0x52,0xe1, -0x48,0x12,0x87,0x85,0x0f,0xa8,0xca,0xe3,0x32,0x23,0xa0,0xe3,0x0a,0x30,0x83,0xe1, -0x2c,0x36,0x82,0xe5,0x05,0x20,0x94,0xe7,0x32,0x33,0xa0,0xe3,0x28,0xc6,0x93,0xe5, -0x03,0x80,0xa0,0xe1,0x84,0xac,0x9f,0xe5,0x08,0x20,0x92,0xe5,0x02,0xc0,0xcc,0xe3, -0x5c,0x7c,0x9f,0xe5,0x0a,0x00,0x94,0xe7,0x01,0x90,0x02,0xe2,0x02,0x00,0x52,0xe3, -0x89,0xc0,0x8c,0xe1,0x20,0x10,0xa0,0x03,0x00,0x10,0xa0,0x13,0xbc,0x20,0x80,0xe5, -0x20,0xc0,0xcc,0xe3,0x0c,0x10,0x81,0xe1,0x28,0x16,0x83,0xe5,0x02,0x00,0x00,0xea, -0xf6,0x08,0x00,0xeb,0x01,0x70,0x57,0xe2,0xbd,0x00,0x00,0x0a,0x24,0x36,0x98,0xe5, -0x01,0x00,0xa0,0xe3,0x32,0xc3,0xa0,0xe3,0x02,0x08,0x13,0xe3,0xf7,0xff,0xff,0x0a, -0x01,0x08,0x13,0xe3,0xb6,0x00,0x00,0x0a,0x06,0x30,0x84,0xe0,0x04,0x30,0xd3,0xe5, -0x00,0x00,0x53,0xe3,0x91,0x00,0x00,0x1a,0x14,0xbc,0x9f,0xe5,0x05,0x70,0x94,0xe7, -0x0b,0x30,0xd4,0xe7,0x48,0x92,0x97,0xe5,0x01,0x00,0x53,0xe3,0x28,0x90,0x8d,0xe5, -0x8b,0x00,0x00,0x0a,0x18,0x00,0x9d,0xe5,0x1c,0x10,0x9d,0xe5,0x28,0xe6,0x9c,0xe5, -0x00,0x30,0x84,0xe0,0x08,0x80,0x97,0xe5,0x01,0x10,0x84,0xe0,0x03,0x90,0xa0,0xe1, -0x20,0x10,0x8d,0xe5,0x02,0xe0,0xce,0xe3,0x0f,0x00,0xb9,0xe8,0x02,0x00,0x58,0xe3, -0x04,0xe0,0x8d,0xe5,0x01,0xe0,0x08,0xe2,0x24,0x90,0x8d,0xe5,0x20,0x90,0xa0,0x03, -0x00,0x90,0xa0,0x13,0x2c,0x90,0x8d,0xe5,0x04,0x90,0x9d,0xe5,0x8e,0xe0,0x89,0xe1, -0x0a,0x90,0x94,0xe7,0x20,0xe0,0xce,0xe3,0x04,0x90,0x8d,0xe5,0x2c,0x90,0x9d,0xe5, -0x0e,0xe0,0x89,0xe1,0x04,0x90,0x9d,0xe5,0xbc,0x80,0x89,0xe5,0x24,0x80,0x9d,0xe5, -0x28,0xe6,0x8c,0xe5,0x14,0xe0,0x9d,0xe5,0x0f,0x00,0xae,0xe8,0x0f,0x00,0x98,0xe8, -0x10,0x80,0x9d,0xe5,0x0f,0x00,0x8e,0xe8,0x20,0xe0,0x9d,0xe5,0x0f,0x00,0xbe,0xe8, -0x0f,0x00,0xa8,0xe8,0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xa8,0xe8,0x02,0x30,0xa0,0xe3, -0x30,0x30,0x87,0xe5,0x0f,0x00,0xbe,0xe8,0x0f,0x00,0xa8,0xe8,0x0f,0x00,0x9e,0xe8, -0x0f,0x00,0x88,0xe8,0x2c,0x96,0x9c,0xe5,0x04,0x90,0xc9,0xe3,0x2c,0x96,0x8c,0xe5, -0x34,0x12,0xd7,0xe5,0x00,0x00,0x51,0xe3,0xa6,0x02,0x00,0x1a,0x00,0x20,0xa0,0xe3, -0x10,0x0b,0x9f,0xe5,0x2a,0x10,0xa0,0xe3,0x04,0x8b,0x9f,0xe5,0x8a,0xed,0xff,0xeb, -0x32,0x33,0xa0,0xe3,0xff,0x2c,0xc9,0xe3,0x2c,0x26,0x83,0xe5,0x03,0x90,0xa0,0xe1, -0x02,0x00,0x00,0xea,0xa5,0x08,0x00,0xeb,0x01,0x80,0x58,0xe2,0x1e,0x00,0x00,0x0a, -0x2c,0x36,0x99,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a, -0x05,0xc0,0x94,0xe7,0x1b,0x1e,0xa0,0xe3,0x32,0x33,0xa0,0xe3,0x01,0x00,0xa0,0xe3, -0x2c,0x26,0x93,0xe5,0x00,0x30,0xa0,0xe3,0x48,0x82,0x9c,0xe5,0x04,0xe0,0x82,0xe3, -0xd0,0x2a,0x9f,0xe5,0x98,0x01,0x01,0xe0,0x15,0x10,0x81,0xe2,0x92,0x81,0x81,0xe0, -0x21,0x12,0xa0,0xe1,0x0d,0x20,0x83,0xe2,0x10,0x22,0xa0,0xe1,0x02,0x00,0x51,0xe1, -0x30,0x03,0x00,0x9a,0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a, -0xe8,0x2a,0x9f,0xe5,0x48,0x22,0x8c,0xe5,0x0f,0x30,0x03,0xe2,0x0f,0xe8,0xce,0xe3, -0x03,0x28,0x8e,0xe1,0x32,0x33,0xa0,0xe3,0x2c,0x26,0x83,0xe5,0x88,0x0a,0x9f,0xe5, -0x32,0x33,0xa0,0xe3,0x93,0x7f,0x87,0xe2,0x80,0x2a,0x9f,0xe5,0x00,0x10,0xa0,0xe3, -0x03,0x90,0xa0,0xe1,0x04,0x06,0x83,0xe5,0x74,0x0a,0x9f,0xe5,0x00,0x76,0x83,0xe5, -0x3c,0x8a,0x9f,0xe5,0x14,0x07,0x83,0xe5,0x68,0x0a,0x9f,0xe5,0x18,0x07,0x83,0xe5, -0x03,0x30,0xa0,0xe3,0x0c,0x30,0xc2,0xe5,0x0d,0x10,0xc2,0xe5,0x0e,0x10,0xc2,0xe5, -0x02,0x00,0x00,0xea,0x71,0x08,0x00,0xeb,0x01,0x80,0x58,0xe2,0x14,0x00,0x00,0x0a, -0x24,0x26,0x99,0xe5,0x01,0x00,0xa0,0xe3,0x32,0x33,0xa0,0xe3,0x01,0x00,0x12,0xe3, -0xf7,0xff,0xff,0x1a,0x05,0x20,0x94,0xe7,0x48,0x72,0x92,0xe5,0x00,0x00,0x57,0xe3, -0xa3,0x02,0x00,0x0a,0x24,0x26,0x93,0xe5,0x02,0x00,0x12,0xe3,0xa0,0x02,0x00,0x0a, -0x03,0x80,0xa0,0xe1,0x02,0x00,0x00,0xea,0x24,0x36,0x98,0xe5,0x02,0x00,0x13,0xe3, -0x9b,0x02,0x00,0x0a,0x01,0x00,0xa0,0xe3,0x5c,0x08,0x00,0xeb,0x01,0x70,0x57,0xe2, -0xf8,0xff,0xff,0x1a,0xd1,0xf5,0xff,0xeb,0x00,0x30,0x50,0xe2,0x13,0x00,0x00,0x1a, -0x05,0x70,0x94,0xe7,0x06,0x30,0x84,0xe0,0x08,0xc0,0x93,0xe5,0x00,0x00,0x5c,0xe3, -0x00,0x30,0xa0,0x13,0xc5,0x00,0x00,0x0a,0x01,0x00,0x5c,0xe3,0x01,0x30,0x83,0x03, -0x00,0x00,0x53,0xe3,0x19,0x00,0x00,0x1a,0x01,0x10,0xa0,0xe3,0x0a,0x20,0x94,0xe7, -0x1c,0x10,0x87,0xe5,0x00,0x30,0xa0,0xe3,0x94,0x19,0x9f,0xe5,0xb4,0xc0,0x82,0xe5, -0x01,0x10,0xd4,0xe7,0xe0,0x10,0x82,0xe5,0x00,0x00,0x00,0xea,0x03,0x30,0xa0,0xe3, -0x03,0x00,0xa0,0xe1,0x94,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x02,0x9a,0xa0,0xe3, -0x22,0x10,0xa0,0xe3,0xfa,0x0f,0xa0,0xe3,0x2a,0xb0,0xa0,0xe3,0x12,0x80,0xa0,0xe3, -0xda,0xfe,0xff,0xea,0x02,0x04,0x13,0xe3,0x0b,0x2c,0xa0,0x03,0x0d,0x2c,0xa0,0x13, -0xa4,0xfe,0xff,0xea,0x3d,0xfe,0xff,0xeb,0x08,0x30,0xa0,0xe3,0xef,0xff,0xff,0xea, -0x18,0xe0,0x9d,0xe5,0x01,0xc0,0xa0,0xe3,0x1c,0x00,0x9d,0xe5,0x32,0x83,0xa0,0xe3, -0x08,0xc0,0x87,0xe5,0x0e,0x90,0x84,0xe0,0x06,0xe0,0x84,0xe0,0x00,0xb0,0x84,0xe0, -0x0f,0x00,0xb9,0xe8,0x08,0xc0,0x8e,0xe5,0x14,0xc0,0x9d,0xe5,0x10,0xe0,0x9d,0xe5, -0x0f,0x00,0xac,0xe8,0x0f,0x00,0x99,0xe8,0x0f,0x00,0x8c,0xe8,0x0b,0xc0,0xa0,0xe1, -0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x00,0x30,0xa0,0xe3,0x30,0x30,0x87,0xe5,0x0f,0x00,0xbc,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0x9c,0xe8,0x0f,0x00,0x8e,0xe8,0x2c,0x96,0x98,0xe5,0x04,0x90,0xc9,0xe3, -0x2c,0x96,0x88,0xe5,0x34,0x32,0xd7,0xe5,0x00,0x00,0x53,0xe3,0xee,0x01,0x00,0x1a, -0x00,0x20,0xa0,0xe3,0x9c,0x08,0x9f,0xe5,0x22,0x10,0xa0,0xe3,0x90,0x88,0x9f,0xe5, -0xed,0xec,0xff,0xeb,0xff,0x2c,0xc9,0xe3,0x32,0x33,0xa0,0xe3,0x02,0x2a,0x82,0xe3, -0x03,0xb0,0xa0,0xe1,0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0x07,0x08,0x00,0xeb, -0x01,0x80,0x58,0xe2,0x1e,0x00,0x00,0x0a,0x2c,0x36,0x9b,0xe5,0x01,0x00,0xa0,0xe3, -0x02,0x00,0x13,0xe3,0xf8,0xff,0xff,0x0a,0x05,0xc0,0x94,0xe7,0x1b,0x1e,0xa0,0xe3, -0x32,0x33,0xa0,0xe3,0x01,0x00,0xa0,0xe3,0x2c,0xe6,0x93,0xe5,0x00,0x30,0xa0,0xe3, -0x48,0x22,0x9c,0xe5,0x04,0xe0,0x8e,0xe3,0x92,0x01,0x01,0xe0,0x68,0x28,0x9f,0xe5, -0x11,0x10,0x81,0xe2,0x92,0x91,0x81,0xe0,0x21,0x11,0xa0,0xe1,0x0d,0x20,0x83,0xe2, -0x10,0x22,0xa0,0xe1,0x02,0x00,0x51,0xe1,0x6c,0x02,0x00,0x9a,0x01,0x30,0x83,0xe2, -0x0e,0x00,0x53,0xe3,0xf8,0xff,0xff,0x1a,0x70,0x28,0x9f,0xe5,0x48,0x22,0x8c,0xe5, -0x0f,0x30,0x03,0xe2,0x0f,0x28,0xce,0xe3,0x03,0x28,0x82,0xe1,0x32,0x33,0xa0,0xe3, -0x2c,0x26,0x83,0xe5,0x00,0x00,0xa0,0xe3,0x00,0x30,0xa0,0xe1,0x00,0x10,0xa0,0xe1, -0x00,0x20,0xa0,0xe1,0x67,0xf6,0xff,0xeb,0x00,0x30,0x50,0xe2,0x9b,0xff,0xff,0x1a, -0x06,0x30,0x94,0xe7,0x04,0x28,0x9f,0xe5,0x05,0x10,0x94,0xe7,0x01,0x00,0x53,0xe3, -0x02,0x20,0x84,0xe0,0xf8,0x97,0x9f,0x95,0x10,0x10,0x8d,0xe5,0x03,0x81,0x92,0xe7, -0x05,0x00,0x00,0x9a,0x03,0x00,0x53,0xe3,0xe8,0x97,0x9f,0x05,0x02,0x00,0x00,0x0a, -0x02,0x00,0x53,0xe3,0xe0,0x97,0x9f,0xe5,0x00,0x90,0xa0,0x13,0x09,0x10,0xa0,0xe1, -0x08,0x00,0xa0,0xe3,0x07,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x51,0xf6,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x00,0x90,0xa0,0x13,0x14,0x90,0x8d,0x15,0xfc,0x01,0x00,0x0a, -0x00,0x00,0x58,0xe3,0x05,0xb0,0x84,0xe0,0x14,0xc0,0x9d,0x05,0x00,0x90,0xa0,0xe3, -0x14,0xe0,0x9d,0x15,0x0c,0x3f,0xa0,0x01,0x0e,0x3f,0xa0,0x11,0x03,0x80,0x88,0x11, -0x0c,0x30,0x8d,0xe5,0xb4,0x07,0x00,0xeb,0x0c,0x30,0x9d,0xe5,0x18,0x70,0x8d,0xe5, -0x1c,0x50,0x8d,0xe5,0x03,0x70,0xa0,0xe1,0x10,0x50,0x9d,0xe5,0x10,0x60,0x8d,0xe5, -0x00,0x60,0xa0,0xe1,0x0b,0x00,0x00,0xea,0x00,0x10,0x9b,0xe5,0x01,0x00,0xa0,0xe3, -0x0a,0x20,0x94,0xe7,0x64,0x37,0x9f,0xe5,0x40,0x02,0xc1,0xe5,0xb8,0x30,0x82,0xe5, -0x07,0x80,0x83,0xe1,0xa4,0x07,0x00,0xeb,0x00,0x60,0xa0,0xe1,0x30,0x07,0x9f,0xe5, -0x00,0x00,0x59,0xe1,0x64,0xff,0xff,0x8a,0x00,0x10,0xa0,0xe3,0x37,0x00,0xa0,0xe3, -0x01,0x30,0xa0,0xe1,0x01,0x20,0xa0,0xe3,0x2a,0xf6,0xff,0xeb,0x00,0x30,0x50,0xe2, -0x5e,0xff,0xff,0x1a,0x29,0x00,0xa0,0xe3,0x08,0x10,0xa0,0xe1,0x03,0x20,0xa0,0xe3, -0x24,0xf6,0xff,0xeb,0x00,0x30,0x50,0xe2,0x58,0xff,0xff,0x1a,0x0c,0x20,0x95,0xe5, -0x00,0x00,0x52,0xe3,0x8e,0x02,0x00,0xba,0x00,0x00,0x58,0xe3,0x8e,0x00,0x00,0x1a, -0xf8,0x36,0x9f,0xe5,0x03,0x30,0x02,0xe0,0x00,0x00,0x53,0xe3,0xdd,0xff,0xff,0x1a, -0x80,0x00,0x12,0xe3,0x45,0x01,0x00,0x0a,0x00,0x10,0x9b,0xe5,0x80,0x30,0xa0,0xe3, -0x0a,0x20,0x94,0xe7,0x40,0x82,0xc1,0xe5,0xb8,0x30,0x82,0xe5,0xdb,0xff,0xff,0xea, -0x18,0xe0,0x9d,0xe5,0x32,0x93,0xa0,0xe3,0x1c,0x00,0x9d,0xe5,0x0e,0x80,0x84,0xe0, -0x14,0xe0,0x9d,0xe5,0x00,0xb0,0x84,0xe0,0x0f,0x00,0xb8,0xe8,0x0f,0x00,0xae,0xe8, -0x0f,0x00,0x98,0xe8,0x0b,0x80,0xa0,0xe1,0x0f,0x00,0x8e,0xe8,0x10,0xe0,0x9d,0xe5, -0x0f,0x00,0xb8,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0xb8,0xe8,0x0f,0x00,0xae,0xe8, -0x30,0xc0,0x87,0xe5,0x0f,0x00,0xb8,0xe8,0x0f,0x00,0xae,0xe8,0x0f,0x00,0x98,0xe8, -0x0f,0x00,0x8e,0xe8,0x2c,0x86,0x99,0xe5,0x04,0x80,0xc8,0xe3,0x2c,0x86,0x89,0xe5, -0x34,0x32,0xd7,0xe5,0x00,0x00,0x53,0xe3,0x30,0x01,0x00,0x1a,0x00,0x20,0xa0,0xe3, -0x10,0x06,0x9f,0xe5,0x22,0x10,0xa0,0xe3,0x04,0x76,0x9f,0xe5,0x4a,0xec,0xff,0xeb, -0xff,0x2c,0xc8,0xe3,0x32,0x33,0xa0,0xe3,0x02,0x2a,0x82,0xe3,0x03,0x90,0xa0,0xe1, -0x2c,0x26,0x83,0xe5,0x02,0x00,0x00,0xea,0x64,0x07,0x00,0xeb,0x01,0x70,0x57,0xe2, -0x1e,0x00,0x00,0x0a,0x2c,0x36,0x99,0xe5,0x01,0x00,0xa0,0xe3,0x02,0x00,0x13,0xe3, -0xf8,0xff,0xff,0x0a,0x05,0xc0,0x94,0xe7,0x1b,0x1e,0xa0,0xe3,0x32,0x33,0xa0,0xe3, -0x01,0x00,0xa0,0xe3,0x2c,0xe6,0x93,0xe5,0x00,0x30,0xa0,0xe3,0x48,0x22,0x9c,0xe5, -0x04,0xe0,0x8e,0xe3,0x92,0x01,0x01,0xe0,0xdc,0x25,0x9f,0xe5,0x11,0x10,0x81,0xe2, -0x92,0x71,0x81,0xe0,0x21,0x11,0xa0,0xe1,0x0d,0x20,0x83,0xe2,0x10,0x22,0xa0,0xe1, -0x02,0x00,0x51,0xe1,0xdc,0x01,0x00,0x9a,0x01,0x30,0x83,0xe2,0x0e,0x00,0x53,0xe3, -0xf8,0xff,0xff,0x1a,0xe4,0x25,0x9f,0xe5,0x48,0x22,0x8c,0xe5,0x0f,0x30,0x03,0xe2, -0x0f,0xe8,0xce,0xe3,0x03,0x28,0x8e,0xe1,0x32,0x33,0xa0,0xe3,0x2c,0x26,0x83,0xe5, -0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe1,0x00,0x20,0xa0,0xe1,0x00,0x30,0xa0,0xe1, -0xc4,0xf5,0xff,0xeb,0x00,0x80,0x50,0xe2,0xe6,0x00,0x00,0x1a,0x7c,0x35,0x9f,0xe5, -0x05,0xb0,0x84,0xe0,0x06,0x20,0x94,0xe7,0x00,0x90,0xa0,0xe3,0x05,0x80,0x94,0xe7, -0x03,0x30,0x84,0xe0,0x02,0x71,0x93,0xe7,0x00,0x00,0x57,0xe3,0x01,0x71,0x87,0x13, -0x29,0x07,0x00,0xeb,0x20,0x50,0x8d,0xe5,0x08,0x50,0xa0,0xe1,0x06,0x80,0xa0,0xe1, -0x00,0x60,0xa0,0xe1,0x0b,0x00,0x00,0xea,0x54,0x75,0x9f,0xe5,0x01,0xc0,0xa0,0xe3, -0x00,0x20,0x9b,0xe5,0x0a,0x30,0x94,0xe7,0x40,0xe5,0x9f,0xe5,0x40,0xc2,0xc2,0xe5, -0xb8,0xe0,0x83,0xe5,0x1c,0x07,0x00,0xeb,0x00,0x60,0xa0,0xe1,0x10,0x15,0x9f,0xe5, -0x01,0x00,0x59,0xe1,0xd6,0x01,0x00,0x8a,0x01,0x00,0xa0,0xe3,0x07,0x10,0xa0,0xe1, -0x03,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0xa2,0xf5,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x0b,0x02,0x00,0x1a,0x0c,0x30,0x95,0xe5,0x00,0x00,0x53,0xe3,0xd0,0x01,0x00,0xba, -0x00,0x00,0x57,0xe3,0x12,0x00,0x00,0x1a,0xf0,0x24,0x9f,0xe5,0x02,0x20,0x03,0xe0, -0x00,0x00,0x52,0xe3,0xe3,0xff,0xff,0x1a,0x80,0x00,0x13,0xe3,0xbf,0x00,0x00,0x0a, -0x00,0x20,0x9b,0xe5,0x80,0x00,0xa0,0xe3,0x0a,0x30,0x94,0xe7,0x40,0x72,0xc2,0xe5, -0xb8,0x00,0x83,0xe5,0xcc,0x74,0x9f,0xe5,0xe1,0xff,0xff,0xea,0x06,0x00,0xa0,0xe1, -0x01,0x07,0x00,0xeb,0x00,0x90,0xa0,0xe1,0xbc,0x04,0x9f,0xe5,0x03,0x07,0x00,0xeb, -0x55,0xff,0xff,0xea,0x06,0x00,0xa0,0xe1,0xfb,0x06,0x00,0xeb,0x00,0x90,0xa0,0xe1, -0xa4,0x04,0x9f,0xe5,0xfd,0x06,0x00,0xeb,0xd7,0xff,0xff,0xea,0x18,0x10,0x97,0xe5, -0x22,0xcc,0xa0,0xe1,0x0e,0x00,0x60,0xe2,0x02,0x00,0xc3,0xe5,0x32,0x00,0x5c,0xe3, -0x35,0x12,0xc3,0xe5,0x21,0x09,0xa0,0xe1,0x21,0xe4,0xa0,0xe1,0x36,0xc2,0xc3,0xe5, -0x0f,0x00,0x00,0xe2,0x14,0x10,0xa0,0xe3,0x34,0xe2,0xc3,0xe5,0x27,0x00,0xc3,0xe5, -0x37,0x12,0xc3,0xe5,0xda,0x02,0x00,0x0a,0x03,0x00,0x50,0xe3,0x10,0x00,0x97,0xe5, -0x03,0x20,0x02,0xe2,0x01,0x10,0xa0,0x83,0x02,0x25,0xa0,0xe1,0x39,0x12,0xc3,0x85, -0x20,0x2b,0x82,0xe1,0xa0,0x13,0xa0,0xe1,0x54,0x04,0x9f,0xe5,0x07,0x10,0x01,0xe2, -0x00,0x00,0x52,0xe1,0x07,0x00,0x51,0x03,0x09,0x00,0x00,0x0a,0x01,0x00,0xa0,0xe3, -0x02,0x10,0x81,0xe2,0x10,0x11,0xa0,0xe1,0x00,0x20,0x82,0xe0,0x3a,0x02,0xd3,0xe5, -0x92,0x01,0x01,0xe0,0x01,0x20,0xd3,0xe5,0x00,0x20,0x62,0xe0,0x11,0x22,0xa0,0xe1, -0x44,0x22,0x83,0xe5,0x04,0x10,0x93,0xe5,0x07,0x00,0xa0,0xe3,0x01,0x20,0xa0,0xe3, -0x00,0x30,0xa0,0xe3,0x57,0xf5,0xff,0xeb,0x00,0x80,0x50,0xe2,0x79,0x00,0x00,0x1a, -0x05,0x70,0x94,0xe7,0x08,0x30,0xa0,0xe1,0x0d,0x00,0xa0,0xe3,0x01,0x20,0xa0,0xe3, -0x05,0x80,0x84,0xe0,0x04,0x10,0x97,0xe5,0x4e,0xf5,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xb5,0x01,0x00,0x1a,0x0c,0x30,0x97,0xe5,0xa3,0x34,0xa0,0xe1,0x0f,0x30,0x03,0xe2, -0x04,0x00,0x53,0xe3,0xb0,0x01,0x00,0x1a,0x00,0x70,0x98,0xe5,0x01,0x20,0xa0,0xe3, -0x38,0x32,0xd7,0xe5,0x03,0x10,0xd7,0xe5,0x24,0x20,0xc7,0xe5,0x00,0x00,0x53,0xe3, -0x25,0x00,0xc7,0xe5,0x02,0x00,0x00,0x0a,0x39,0x32,0xd7,0xe5,0x00,0x00,0x53,0xe3, -0xe0,0x02,0x00,0x1a,0x27,0x80,0xd7,0xe5,0x37,0xb2,0xd7,0xe5,0x6b,0x0f,0x81,0xe2, -0x03,0x00,0x80,0xe2,0x96,0x10,0x00,0xeb,0x0b,0x00,0x50,0xe1,0x04,0x00,0x00,0xda, -0x6b,0x0f,0x8b,0xe2,0x0b,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2,0x90,0x10,0x00,0xeb, -0x03,0x00,0xc7,0xe5,0x03,0x00,0x58,0xe3,0x3c,0x00,0x00,0x9a,0x00,0x00,0xa0,0xe3, -0xd4,0xf2,0xff,0xeb,0x02,0x00,0xa0,0xe3,0x65,0xf3,0xff,0xeb,0x67,0xfc,0xff,0xeb, -0x00,0x80,0x50,0xe2,0x4b,0x00,0x00,0x1a,0x05,0x70,0x94,0xe7,0x40,0x22,0xd7,0xe5, -0x00,0x00,0x52,0xe3,0x20,0x20,0x8d,0xe5,0xd5,0x02,0x00,0x0a,0x25,0x30,0xd7,0xe5, -0x00,0x00,0x53,0xe3,0x3c,0x92,0xd7,0x15,0x3b,0x92,0xd7,0x05,0x08,0x80,0x97,0xe5, -0x01,0x00,0x58,0xe3,0x0f,0x90,0x09,0x02,0x02,0x00,0x00,0x0a,0x02,0x00,0x58,0xe3, -0x29,0x92,0xa0,0x01,0x00,0x90,0xa0,0x13,0x41,0xc2,0xd7,0xe5,0x01,0xb0,0xa0,0xe3, -0x09,0x20,0xa0,0xe1,0x24,0xc0,0x8d,0xe5,0x24,0xc0,0x9d,0xe5,0x02,0x00,0x5c,0xe1, -0x67,0x02,0x00,0x2a,0x00,0x00,0x53,0xe3,0x9f,0x02,0x00,0x1a,0x02,0x00,0x58,0xe3, -0x08,0xb0,0x87,0x05,0x0b,0x80,0xa0,0x01,0x02,0x00,0x00,0x0a,0x01,0x00,0x58,0xe3, -0x03,0x80,0xa0,0x01,0x08,0x30,0x87,0x05,0x20,0x90,0x9d,0xe5,0x00,0x00,0x59,0xe3, -0x67,0x02,0x00,0x0a,0x00,0x00,0x53,0xe3,0x3c,0x22,0xd7,0x15,0x3b,0x22,0xd7,0x05, -0x01,0x00,0x58,0xe3,0x0f,0x20,0x02,0x02,0xea,0xff,0xff,0x0a,0x02,0x00,0x58,0xe3, -0x5d,0x02,0x00,0x0a,0x00,0x90,0xa0,0xe3,0x32,0x33,0xa0,0xe3,0x05,0x70,0x94,0xe7, -0x28,0x26,0x93,0xe5,0x0a,0x10,0x94,0xe7,0x04,0x20,0xc2,0xe3,0xc0,0x90,0x81,0xe5, -0x28,0x26,0x83,0xe5,0x25,0x30,0xd7,0xe5,0x00,0x00,0x53,0xe3,0x37,0x02,0x00,0x1a, -0x01,0x00,0xa0,0xe3,0x2a,0xf3,0xff,0xeb,0x05,0x30,0x94,0xe7,0x08,0x00,0x93,0xe5, -0x00,0x04,0xa0,0xe1,0xed,0x07,0x80,0xe3,0x03,0x08,0x80,0xe3,0x1c,0xf8,0xff,0xeb, -0x00,0x80,0x50,0xe2,0x0b,0x00,0x00,0x1a,0x05,0x70,0x94,0xe7,0x08,0x00,0x97,0xe5, -0x8c,0xf2,0xff,0xeb,0x28,0x30,0x97,0xe5,0x00,0x00,0x53,0xe3,0x50,0x02,0x00,0x1a, -0x05,0x20,0x94,0xe7,0x0a,0x30,0x94,0xe7,0x28,0x20,0x92,0xe5,0x00,0x20,0x52,0xe2, -0x01,0x20,0xa0,0x13,0xdc,0x20,0x83,0xe5,0x06,0x20,0x84,0xe0,0x00,0x30,0x58,0xe2, -0x01,0x30,0xa0,0x13,0x08,0xc0,0x92,0xe5,0x05,0x70,0x94,0xe7,0xfd,0xfd,0xff,0xea, -0x06,0x00,0xa0,0xe1,0x48,0x06,0x00,0xeb,0x00,0x90,0xa0,0xe1,0x26,0xff,0xff,0xea, -0x06,0x00,0xa0,0xe1,0x44,0x06,0x00,0xeb,0x00,0x90,0xa0,0xe1,0x9a,0xfe,0xff,0xea, -0xf9,0x2f,0x82,0xe2,0x0f,0x30,0x03,0xe2,0x03,0x10,0x82,0xe2,0x03,0x38,0xa0,0xe1, -0xbc,0x21,0x9f,0xe5,0x91,0x82,0x82,0xe0,0x22,0x23,0xa0,0xe1,0x24,0xfd,0xff,0xea, -0xa3,0x20,0xa0,0xe1,0x07,0x10,0x03,0xe2,0x35,0x02,0xd7,0xe5,0x3c,0x30,0x02,0xe2, -0x90,0x20,0x8d,0xe2,0x03,0x30,0x82,0xe0,0x01,0x11,0x82,0xe0,0x60,0x20,0x13,0xe5, -0x5c,0x31,0x9f,0xe5,0x20,0x10,0x11,0xe5,0x90,0x03,0x03,0xe0,0xf9,0x3f,0x83,0xe2, -0x03,0x30,0x83,0xe2,0x91,0x32,0x22,0xe0,0x74,0x31,0x9f,0xe5,0x92,0x93,0x83,0xe0, -0x70,0x21,0x9f,0xe5,0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x87,0xe5, -0xf8,0x30,0x9f,0x95,0x48,0x32,0x87,0x95,0xb7,0xfe,0xff,0x9a,0x5c,0x21,0x9f,0xe5, -0x02,0x00,0x53,0xe1,0x48,0x22,0x87,0x85,0xb3,0xfe,0xff,0xea,0xa3,0x20,0xa0,0xe1, -0x07,0x10,0x03,0xe2,0x35,0x02,0xd7,0xe5,0x3c,0x30,0x02,0xe2,0x90,0x20,0x8d,0xe2, -0x03,0x30,0x82,0xe0,0x01,0x11,0x82,0xe0,0x60,0x20,0x13,0xe5,0xf0,0x30,0x9f,0xe5, -0x20,0x10,0x11,0xe5,0x90,0x03,0x03,0xe0,0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2, -0x91,0x32,0x22,0xe0,0x08,0x31,0x9f,0xe5,0x92,0x83,0x83,0xe0,0x04,0x21,0x9f,0xe5, -0x23,0x33,0xa0,0xe1,0x02,0x00,0x53,0xe1,0x48,0x32,0x87,0xe5,0x8c,0x30,0x9f,0x95, -0x48,0x32,0x87,0x95,0xf9,0xfd,0xff,0x9a,0xf0,0x20,0x9f,0xe5,0x02,0x00,0x53,0xe1, -0x48,0x22,0x87,0x85,0xf5,0xfd,0xff,0xea,0xa1,0x30,0xa0,0xe1,0x90,0xc0,0x8d,0xe2, -0x35,0x02,0xd7,0xe5,0x07,0x10,0x01,0xe2,0x3c,0x30,0x03,0xe2,0x01,0x11,0x8c,0xe0, -0x03,0x30,0x8c,0xe0,0x60,0x20,0x13,0xe5,0xb0,0x30,0x9f,0xe5,0x20,0x10,0x11,0xe5, -0x90,0x03,0x03,0xe0,0xa8,0x00,0x9f,0xe5,0xf9,0x3f,0x83,0xe2,0x03,0x30,0x83,0xe2, -0x91,0x32,0x23,0xe0,0x9c,0x20,0x9f,0xe5,0x90,0xe3,0x83,0xe0,0x23,0x33,0xa0,0xe1, -0x02,0x00,0x53,0xe1,0x48,0x32,0x87,0xe5,0x20,0x30,0x9f,0x95,0x48,0x32,0x87,0x95, -0x41,0xfd,0xff,0x9a,0x84,0x20,0x9f,0xe5,0x02,0x00,0x53,0xe1,0x48,0x22,0x87,0x85, -0x3d,0xfd,0xff,0xea,0xfc,0x80,0x00,0x00,0xd0,0x10,0x00,0x00,0xcc,0x10,0x00,0x00, -0x40,0x0d,0x03,0x00,0xa0,0x86,0x01,0x00,0x4f,0x00,0x64,0x01,0x01,0x20,0x00,0x00, -0xa0,0xf2,0xff,0xff,0x4c,0xf2,0xff,0xff,0xcb,0x00,0x7f,0x00,0x4a,0x0c,0x02,0x00, -0x40,0x00,0x00,0x00,0xc8,0x10,0x00,0x00,0xa3,0x8b,0x2e,0xba,0x00,0x72,0x01,0x00, -0x00,0x06,0x00,0xc8,0x40,0x42,0x0f,0x00,0x00,0x2d,0x31,0x01,0x39,0x8e,0xe3,0x38, -0x6c,0xf2,0xff,0xff,0xa5,0x01,0x00,0x00,0xa5,0x02,0x00,0x00,0xa5,0x03,0x00,0x00, -0x00,0x80,0xff,0x00,0x00,0x80,0xff,0x40,0x80,0x00,0x00,0x40,0x10,0x27,0x00,0x00, -0x50,0xc3,0x00,0x00,0xd3,0x4d,0x62,0x10,0x3f,0x0d,0x03,0x00,0x40,0x0d,0x03,0x00, -0x00,0x35,0x0c,0x00,0xff,0x0f,0x00,0x00,0x08,0x70,0x01,0x00,0x00,0x01,0xb9,0x03, -0x01,0xff,0xff,0x80,0x10,0x20,0x9d,0xe5,0x0c,0x30,0x92,0xe5,0x03,0x3a,0xa0,0xe1, -0x23,0x0a,0x59,0xe1,0x00,0x30,0xa0,0x13,0x01,0x30,0xa0,0x03,0x14,0x30,0x8d,0xe5, -0xfa,0xfd,0xff,0xea,0x05,0x70,0x94,0xe7,0x03,0x20,0xa0,0xe3,0x32,0x33,0xa0,0xe3, -0x10,0x27,0x83,0xe5,0x8e,0x33,0x83,0xe2,0x1c,0x30,0x87,0xe5,0xb2,0x05,0x00,0xeb, -0x05,0x30,0x94,0xe7,0x01,0x20,0xa0,0xe3,0x20,0x00,0x87,0xe5,0x4c,0x24,0xc3,0xe5, -0x31,0xfb,0xff,0xeb,0x02,0x00,0x50,0xe3,0xfc,0xff,0xff,0x0a,0x05,0x70,0x94,0xe7, -0x01,0x00,0x50,0xe3,0x00,0x30,0xa0,0xe3,0x4c,0x34,0xc7,0xe5,0xd9,0x00,0x00,0x0a, -0x28,0xc0,0x9d,0xe5,0x03,0x00,0x5c,0xe1,0x0c,0x00,0x00,0x0a,0x32,0x23,0xa0,0xe3, -0x10,0x37,0x82,0xe5,0x10,0x17,0x92,0xe5,0x03,0x00,0x51,0xe1,0x28,0x10,0x9d,0x15, -0x04,0x00,0x00,0x1a,0x05,0x00,0x00,0xea,0x10,0x37,0x82,0xe5,0x10,0x07,0x92,0xe5, -0x00,0x00,0x50,0xe3,0x01,0x00,0x00,0x0a,0x01,0x10,0x51,0xe2,0xf9,0xff,0xff,0x1a, -0x32,0x33,0xa0,0xe3,0x30,0x26,0x93,0xe5,0x30,0x26,0x83,0xe5,0x40,0xfd,0xff,0xea, -0x03,0x80,0xd7,0xe5,0x24,0x90,0xd7,0xe5,0x6b,0x0f,0x88,0xe2,0x08,0x10,0xa0,0xe1, -0x03,0x00,0x80,0xe2,0x71,0x0f,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1, -0x03,0x00,0x83,0xe2,0x6d,0x0f,0x00,0xeb,0x98,0x09,0x01,0xe0,0x00,0xb0,0xa0,0xe1, -0xa9,0x90,0xa0,0xe1,0x09,0x94,0xa0,0xe1,0x6b,0x0f,0x81,0xe2,0x03,0x00,0x80,0xe2, -0x66,0x0f,0x00,0xeb,0xf9,0x3f,0x80,0xe2,0x00,0x10,0xa0,0xe1,0x03,0x00,0x83,0xe2, -0x62,0x0f,0x00,0xeb,0x06,0x11,0x48,0xe2,0x81,0x10,0xa0,0xe1,0x23,0xfc,0xff,0xea, -0xf9,0x2f,0x82,0xe2,0x03,0x10,0x82,0xe2,0x4c,0x21,0x1f,0xe5,0x91,0x02,0x82,0xe0, -0x22,0x23,0xa0,0xe1,0x2a,0x10,0xa0,0xe3,0x91,0x02,0x02,0xe0,0x5c,0x11,0x1f,0xe5, -0xc3,0x2c,0x82,0xe2,0x50,0x20,0x82,0xe2,0x01,0x00,0x52,0xe1,0x48,0x22,0x8c,0xe5, -0x6c,0x21,0x1f,0x95,0x48,0x22,0x8c,0x95,0x88,0xfd,0xff,0x9a,0x74,0x11,0x1f,0xe5, -0x01,0x00,0x52,0xe1,0x85,0xfd,0xff,0x9a,0x82,0xfd,0xff,0xea,0xf9,0x2f,0x82,0xe2, -0x03,0x10,0x82,0xe2,0x98,0x21,0x1f,0xe5,0x91,0x82,0x82,0xe0,0x22,0x23,0xa0,0xe1, -0x2a,0x10,0xa0,0xe3,0x91,0x02,0x02,0xe0,0xa8,0x11,0x1f,0xe5,0xc3,0x2c,0x82,0xe2, -0x50,0x20,0x82,0xe2,0x01,0x00,0x52,0xe1,0x48,0x22,0x8c,0xe5,0xb8,0x21,0x1f,0x95, -0x48,0x22,0x8c,0x95,0x18,0xfe,0xff,0x9a,0xc0,0x11,0x1f,0xe5,0x01,0x00,0x52,0xe1, -0x15,0xfe,0xff,0x9a,0x12,0xfe,0xff,0xea,0xf9,0x2f,0x82,0xe2,0x03,0x10,0x82,0xe2, -0xe4,0x21,0x1f,0xe5,0x91,0x92,0x82,0xe0,0x22,0x13,0xa0,0xe1,0x32,0x20,0xa0,0xe3, -0x91,0x02,0x02,0xe0,0xf4,0x11,0x1f,0xe5,0xc3,0x2c,0x82,0xe2,0x50,0x20,0x82,0xe2, -0x01,0x00,0x52,0xe1,0x48,0x22,0x8c,0xe5,0x04,0x22,0x1f,0x95,0x48,0x22,0x8c,0x95, -0xc4,0xfc,0xff,0x9a,0x0c,0x12,0x1f,0xe5,0x01,0x00,0x52,0xe1,0xc1,0xfc,0xff,0x9a, -0xbe,0xfc,0xff,0xea,0x08,0x60,0xa0,0xe1,0x20,0x50,0x9d,0xe5,0x03,0x80,0xa0,0xe3, -0xf0,0xfe,0xff,0xea,0x20,0x50,0x9d,0xe5,0x01,0x01,0x13,0xe3,0x00,0x20,0xa0,0x03, -0x01,0x20,0xa0,0x13,0x00,0x10,0xa0,0xe1,0x08,0x60,0xa0,0xe1,0x00,0x80,0xa0,0xe1, -0x05,0xc0,0x94,0xe7,0x02,0x00,0xa0,0xe3,0x08,0x30,0xa0,0xe1,0x05,0x90,0x84,0xe0, -0x26,0x20,0xcc,0xe5,0x00,0x20,0xa0,0xe1,0xbe,0xf3,0xff,0xeb,0x00,0x80,0x50,0xe2, -0xe0,0xfe,0xff,0x1a,0x0a,0x00,0x94,0xe7,0x10,0x20,0xa0,0xe3,0x05,0x10,0x94,0xe7, -0xc4,0x00,0x80,0xe2,0x0c,0x10,0x81,0xe2,0x26,0x05,0x00,0xeb,0x05,0xe0,0x94,0xe7, -0x02,0xc8,0xa0,0xe3,0x08,0x30,0xa0,0xe1,0x03,0x00,0xa0,0xe3,0x0c,0x10,0xa0,0xe1, -0x01,0x20,0xa0,0xe3,0x04,0xc0,0x8e,0xe5,0xae,0xf3,0xff,0xeb,0x00,0x80,0x50,0xe2, -0xd0,0xfe,0xff,0x1a,0x00,0x70,0x99,0xe5,0x08,0x30,0xa0,0xe1,0x09,0x00,0x80,0xe2, -0x02,0x20,0xa0,0xe3,0x04,0x10,0x97,0xe5,0xa6,0xf3,0xff,0xeb,0x00,0x80,0x50,0xe2, -0xc8,0xfe,0xff,0x1a,0x14,0x20,0x97,0xe5,0x0e,0x10,0xa0,0xe3,0x00,0x30,0x99,0xe5, -0x22,0x04,0xa0,0xe1,0x00,0x10,0xc3,0xe5,0x0f,0x00,0x00,0xe2,0x09,0x00,0x50,0xe3, -0x01,0x00,0xc3,0xe5,0x3a,0x02,0xc3,0xe5,0x09,0x00,0xa0,0x83,0x01,0x00,0xc3,0x85, -0x15,0xfe,0xff,0x8a,0x00,0x00,0x50,0xe3,0x13,0xfe,0xff,0x1a,0x08,0x80,0xa0,0xe3, -0xb8,0xfe,0xff,0xea,0x20,0x50,0x9d,0xe5,0x08,0x60,0xa0,0xe1,0x00,0x80,0xa0,0xe1, -0xb4,0xfe,0xff,0xea,0x1c,0x50,0x9d,0xe5,0x02,0x00,0xa0,0xe3,0x14,0x10,0x9d,0xe5, -0x18,0x70,0x9d,0xe5,0x05,0xc0,0x94,0xe7,0x05,0x80,0x84,0xe0,0x10,0x60,0x9d,0xe5, -0x22,0x2f,0x01,0xe0,0x03,0x10,0xa0,0xe1,0x26,0x20,0xcc,0xe5,0x00,0x20,0xa0,0xe1, -0x84,0xf3,0xff,0xeb,0x00,0x30,0x50,0xe2,0xb8,0xfc,0xff,0x1a,0x05,0x10,0x94,0xe7, -0x10,0x20,0xa0,0xe3,0x0a,0x00,0x94,0xe7,0x0c,0x30,0x8d,0xe5,0x0c,0x10,0x81,0xe2, -0xc4,0x00,0x80,0xe2,0xeb,0x04,0x00,0xeb,0x0c,0x30,0x9d,0xe5,0x03,0x00,0xa0,0xe3, -0x06,0x20,0xa0,0xe3,0x03,0x10,0xa0,0xe1,0x76,0xf3,0xff,0xeb,0x00,0x30,0x50,0xe2, -0xaa,0xfc,0xff,0x1a,0xbe,0x10,0xd7,0xe1,0x09,0x00,0x80,0xe2,0x00,0x70,0x98,0xe5, -0x02,0x20,0xa0,0xe3,0x01,0x18,0xa0,0xe1,0x04,0x10,0x87,0xe5,0x6d,0xf3,0xff,0xeb, -0x00,0x30,0x50,0xe2,0xa1,0xfc,0xff,0x1a,0x14,0x10,0x97,0xe5,0x0e,0x00,0x80,0xe2, -0x00,0x30,0x98,0xe5,0x21,0x24,0xa0,0xe1,0x00,0x00,0xc3,0xe5,0x0f,0x20,0x02,0xe2, -0x09,0x00,0x52,0xe3,0x01,0x20,0xc3,0xe5,0x3a,0x22,0xc3,0xe5,0x09,0x20,0xa0,0x83, -0x01,0x20,0xc3,0x85,0x05,0x00,0x00,0x8a,0x00,0x00,0x52,0xe3,0x03,0x00,0x00,0x1a, -0x08,0x30,0xa0,0xe3,0x91,0xfc,0xff,0xea,0x0b,0x00,0xc4,0xe7,0x7c,0xfc,0xff,0xea, -0x18,0x00,0x97,0xe5,0x21,0xcc,0xa0,0xe1,0x0e,0x20,0x62,0xe2,0x02,0x20,0xc3,0xe5, -0x32,0x00,0x5c,0xe3,0x35,0x02,0xc3,0xe5,0x20,0x29,0xa0,0xe1,0x20,0xe4,0xa0,0xe1, -0x36,0xc2,0xc3,0xe5,0x0f,0x20,0x02,0xe2,0x14,0x00,0xa0,0xe3,0x34,0xe2,0xc3,0xe5, -0x27,0x20,0xc3,0xe5,0x37,0x02,0xc3,0xe5,0x88,0x00,0x00,0x0a,0x03,0x00,0x52,0xe3, -0x03,0x10,0x01,0xe2,0x01,0x20,0xa0,0x83,0x01,0x05,0xa0,0xe1,0x39,0x22,0xc3,0x85, -0x10,0x20,0x97,0xe5,0xa2,0x13,0xa0,0xe1,0x22,0x2b,0x80,0xe1,0x50,0x04,0x1f,0xe5, -0x07,0x10,0x01,0xe2,0x00,0x00,0x52,0xe1,0x07,0x00,0x51,0x03,0x09,0x00,0x00,0x0a, -0x01,0x00,0xa0,0xe3,0x02,0x10,0x81,0xe2,0x10,0x11,0xa0,0xe1,0x00,0x20,0x82,0xe0, -0x3a,0x02,0xd3,0xe5,0x92,0x01,0x01,0xe0,0x01,0x20,0xd3,0xe5,0x00,0x20,0x62,0xe0, -0x11,0x22,0xa0,0xe1,0x44,0x22,0x83,0xe5,0x04,0x10,0x93,0xe5,0x07,0x00,0xa0,0xe3, -0x00,0x30,0xa0,0xe3,0x08,0x20,0xa0,0xe3,0x2e,0xf3,0xff,0xeb,0x00,0x30,0x50,0xe2, -0x62,0xfc,0xff,0x1a,0x05,0x70,0x94,0xe7,0x0d,0x00,0xa0,0xe3,0x01,0x20,0xa0,0xe3, -0x05,0x80,0x84,0xe0,0x04,0x10,0x97,0xe5,0x26,0xf3,0xff,0xeb,0x00,0x90,0x50,0xe2, -0xc6,0xff,0xff,0x1a,0x0c,0x30,0x97,0xe5,0xa3,0x34,0xa0,0xe1,0x0f,0x30,0x03,0xe2, -0x04,0x00,0x53,0xe3,0xc1,0xff,0xff,0x1a,0x32,0x73,0xa0,0xe3,0x0a,0xe0,0x94,0xe7, -0x28,0xc6,0x97,0xe5,0x09,0x30,0xa0,0xe1,0x10,0x00,0x80,0xe2,0x08,0x10,0xa0,0xe3, -0xbc,0x90,0x8e,0xe5,0x01,0x20,0xa0,0xe3,0x22,0xc0,0xcc,0xe3,0x28,0xc6,0x87,0xe5, -0x14,0xf3,0xff,0xeb,0x00,0x30,0x50,0xe2,0x48,0xfc,0xff,0x1a,0x03,0x10,0xa0,0xe1, -0x10,0x00,0x80,0xe2,0x02,0xf1,0xff,0xeb,0x00,0x30,0x50,0xe2,0x43,0xfc,0xff,0x1a, -0x00,0xe0,0x98,0xe5,0x37,0x00,0x80,0xe2,0x28,0xc5,0x1f,0xe5,0x01,0x20,0xa0,0xe3, -0x34,0x10,0x8e,0xe2,0x04,0xc6,0x87,0xe5,0x00,0x16,0x87,0xe5,0x04,0x10,0x9e,0xe5, -0x04,0xf3,0xff,0xeb,0x00,0x30,0x50,0xe2,0x38,0xfc,0xff,0x1a,0x01,0x20,0xa0,0xe3, -0x03,0x10,0xa0,0xe1,0x33,0x00,0x80,0xe2,0x02,0x30,0xa0,0xe1,0xfd,0xf2,0xff,0xeb, -0x00,0x30,0x50,0xe2,0x31,0xfc,0xff,0x1a,0x03,0x10,0xa0,0xe1,0x33,0x00,0x80,0xe2, -0xeb,0xf0,0xff,0xeb,0x00,0x30,0x50,0xe2,0x2c,0xfc,0xff,0x1a,0x00,0x70,0x98,0xe5, -0x02,0x30,0xa0,0xe3,0x1c,0x30,0x87,0xe5,0x63,0x04,0x00,0xeb,0x20,0x00,0x87,0xe5, -0xe5,0xf9,0xff,0xeb,0x02,0x00,0x50,0xe3,0xfc,0xff,0xff,0x0a,0x01,0x00,0x50,0xe3, -0x8e,0xff,0xff,0x1a,0x05,0x30,0x94,0xe7,0x34,0x20,0xd3,0xe5,0x04,0x10,0x93,0xe5, -0x0f,0x20,0x02,0xe2,0x00,0x00,0x52,0xe3,0x27,0x20,0xc3,0xe5,0x39,0x02,0xc3,0x15, -0x01,0x20,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0x37,0x00,0xa0,0xe3,0xe1,0xf2,0xff,0xeb, -0x00,0x30,0x50,0xe2,0x15,0xfc,0xff,0x1a,0x05,0x30,0x94,0xe7,0x08,0x00,0x93,0xe5, -0x01,0x00,0x50,0xe3,0x02,0x00,0xa0,0x03,0x00,0x00,0xa0,0x13,0x0c,0xf6,0xff,0xeb, -0x00,0x30,0x50,0xe2,0x0d,0xfc,0xff,0x1a,0x05,0x80,0x94,0xe7,0x32,0x73,0xa0,0xe3, -0x05,0x90,0x84,0xe0,0x08,0x00,0x98,0xe5,0x7a,0xf0,0xff,0xeb,0x8e,0xf0,0xff,0xeb, -0x28,0x36,0x97,0xe5,0x04,0x30,0xc3,0xe3,0x28,0x36,0x87,0xe5,0x25,0x30,0xd8,0xe5, -0x00,0x00,0x53,0xe3,0x83,0x00,0x00,0x1a,0x01,0x00,0xa0,0xe3,0x06,0x60,0x84,0xe0, -0x03,0xf1,0xff,0xeb,0x05,0x30,0x94,0xe7,0x00,0x20,0xa0,0xe3,0x28,0x20,0x83,0xe5, -0x9e,0xf8,0xff,0xeb,0x05,0x70,0x94,0xe7,0x08,0xc0,0x96,0xe5,0xed,0xfb,0xff,0xea, -0x06,0x00,0x84,0xe0,0x19,0xc0,0xa0,0xe3,0x37,0xc2,0xc3,0xe5,0x08,0x00,0x90,0xe5, -0x00,0x00,0x50,0xe3,0x1a,0x00,0x80,0x02,0x37,0x02,0xc3,0x05,0x6e,0xff,0xff,0xea, -0x6c,0x06,0x1f,0xe5,0xea,0xf5,0xff,0xeb,0x00,0x00,0x50,0xe3,0x07,0x00,0x00,0x1a, -0x01,0x00,0x80,0xe2,0xee,0xf0,0xff,0xeb,0xf0,0xf9,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x02,0x00,0x00,0x1a,0xed,0x30,0xd7,0xe5,0x00,0x00,0x53,0xe3,0xbb,0xfd,0xff,0x1a, -0x05,0x30,0x94,0xe7,0x00,0x20,0xa0,0xe3,0x39,0x22,0xc3,0xe5,0x66,0xf0,0xff,0xeb, -0xb6,0xfd,0xff,0xea,0x00,0x00,0x52,0xe3,0x02,0x90,0xa0,0xe1,0xa9,0xfd,0xff,0x0a, -0x02,0x04,0xa0,0xe1,0xee,0x07,0x80,0xe3,0x03,0x08,0x80,0xe3,0xd4,0xf5,0xff,0xeb, -0x00,0x80,0x50,0xe2,0xc3,0xfd,0xff,0x1a,0xa2,0xfd,0xff,0xea,0x22,0x22,0xa0,0xe1, -0x88,0xfd,0xff,0xea,0x00,0x00,0x53,0xe3,0x3e,0x22,0xd7,0x15,0x3d,0x22,0xd7,0x05, -0x96,0xfd,0xff,0xea,0x06,0x10,0x84,0xe0,0x19,0xc0,0xa0,0xe3,0x37,0xc2,0xc3,0xe5, -0x08,0x10,0x91,0xe5,0x00,0x00,0x51,0xe3,0x1a,0x10,0x81,0x02,0x37,0x12,0xc3,0x05, -0x1c,0xfd,0xff,0xea,0x3f,0x12,0xd7,0xe5,0x06,0x30,0x84,0xe0,0x08,0x20,0x93,0xe5, -0x06,0x00,0xa0,0xe3,0x08,0x30,0xa0,0xe1,0x07,0x10,0xc1,0xe3,0x01,0x10,0x81,0xe3, -0x01,0x00,0x52,0xe3,0x01,0x14,0xa0,0xe1,0x01,0x20,0xa0,0x03,0x08,0x20,0xa0,0x13, -0x3b,0x16,0x81,0xe3,0x03,0x18,0x81,0xe3,0x82,0xf2,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xed,0xfe,0xff,0x1a,0x05,0x10,0x94,0xe7,0x0d,0x00,0xa0,0xe3,0x01,0x20,0xa0,0xe3, -0x08,0x30,0xa0,0xe1,0x04,0x10,0x91,0xe5,0x7a,0xf2,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xe5,0xfe,0xff,0x1a,0x05,0x30,0x94,0xe7,0x0c,0x20,0x93,0xe5,0xa2,0x1b,0xa0,0xe1, -0xa2,0x23,0x81,0xe1,0x01,0x00,0x12,0xe3,0x01,0x20,0xa0,0x03,0x0b,0x80,0xa0,0x13, -0x2c,0x20,0x83,0x05,0x8d,0xfd,0xff,0x0a,0x92,0xfd,0xff,0xea,0x03,0x10,0xd7,0xe5, -0x00,0xe0,0xa0,0xe3,0x37,0x92,0xd7,0xe5,0x39,0xe2,0xc7,0xe5,0x6b,0x0f,0x81,0xe2, -0x24,0xb0,0xc7,0xe5,0x25,0xe0,0xc7,0xe5,0x03,0x00,0x80,0xe2,0xc4,0x0d,0x00,0xeb, -0x09,0x00,0x50,0xe1,0x00,0x30,0xa0,0xd3,0x5a,0xfd,0xff,0xda,0x6b,0x0f,0x89,0xe2, -0x09,0x10,0xa0,0xe1,0x03,0x00,0x80,0xe2,0xbd,0x0d,0x00,0xeb,0x00,0x30,0xa0,0xe3, -0x03,0x00,0xc7,0xe5,0x53,0xfd,0xff,0xea,0x27,0x80,0xd7,0xe5,0x03,0x00,0x58,0xe3, -0x01,0x90,0xa0,0x81,0x1b,0xfd,0xff,0x9a,0x6b,0x0f,0x89,0xe2,0x09,0x10,0xa0,0xe1, -0x03,0x00,0x80,0xe2,0x89,0x90,0xa0,0xe1,0xa8,0x0d,0x00,0xeb,0x34,0x00,0x50,0xe3, -0x26,0x00,0x00,0x9a,0x24,0x30,0xd7,0xe5,0x83,0x30,0xa0,0xe1,0x24,0x30,0xc7,0xe5, -0xf4,0xff,0xff,0xea,0x25,0x30,0xd7,0xe5,0x00,0x00,0x53,0xe3,0x3e,0x92,0xd7,0x15, -0x3d,0x92,0xd7,0x05,0x28,0xfd,0xff,0xea,0x02,0x00,0xa0,0xe3,0x80,0xf0,0xff,0xeb, -0x05,0x30,0x94,0xe7,0x01,0x16,0xa0,0xe3,0x40,0x08,0x1f,0xe5,0x01,0x20,0xd3,0xe5, -0x34,0x30,0x83,0xe2,0x11,0x22,0xa0,0xe1,0x22,0x2a,0xa0,0xe1,0x17,0x2a,0x82,0xe3, -0x04,0x26,0x87,0xe5,0x00,0x36,0x87,0xe5,0x6d,0xf5,0xff,0xeb,0x00,0x00,0x50,0xe3, -0x09,0x00,0x00,0x1a,0x00,0x70,0x99,0xe5,0x02,0x30,0xa0,0xe3,0x1c,0x30,0x87,0xe5, -0xa5,0x03,0x00,0xeb,0x20,0x00,0x87,0xe5,0x27,0xf9,0xff,0xeb,0x02,0x00,0x50,0xe3, -0xfc,0xff,0xff,0x0a,0x01,0x00,0x50,0xe3,0x62,0xff,0xff,0x0a,0x05,0x30,0x94,0xe7, -0x00,0x20,0xa0,0xe3,0x39,0x22,0xc3,0xe5,0xe7,0xef,0xff,0xeb,0x5d,0xff,0xff,0xea, -0x37,0x32,0xd7,0xe5,0x00,0x00,0x53,0xe1,0x01,0x30,0xa0,0x33,0x25,0x30,0xc7,0x35, -0xf3,0xfc,0xff,0xea,0x74,0x21,0x90,0xe5,0x07,0x32,0xa0,0xe3,0xf0,0x40,0x2d,0xe9, -0x1c,0xd0,0x4d,0xe2,0x18,0xc0,0x8d,0xe2,0x00,0x50,0xa0,0xe3,0x00,0x40,0xa0,0xe1, -0x01,0x60,0xa0,0xe1,0x04,0x50,0x2c,0xe5,0xc4,0x28,0x83,0xe5,0x78,0x21,0x90,0xe5, -0x14,0x05,0x9f,0xe5,0x14,0x75,0x9f,0xe5,0xc8,0x28,0x83,0xe5,0x7c,0x21,0x94,0xe5, -0xe4,0x28,0x83,0xe5,0x80,0x21,0x94,0xe5,0xcc,0x28,0x83,0xe5,0x84,0x21,0x94,0xe5, -0xe8,0x28,0x83,0xe5,0x88,0x21,0x94,0xe5,0xd0,0x28,0x83,0xe5,0x8c,0x21,0x94,0xe5, -0xd4,0x28,0x83,0xe5,0x90,0x21,0x94,0xe5,0xd8,0x28,0x83,0xe5,0x04,0xe0,0x94,0xe5, -0x0c,0x10,0x84,0xe2,0x0e,0x00,0x91,0xe8,0x00,0xe0,0x8d,0xe5,0x08,0xe0,0x94,0xe5, -0x08,0xc0,0x8d,0xe5,0x04,0xe0,0x8d,0xe5,0xa1,0xe8,0xff,0xeb,0x79,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0xcf,0xe8,0xff,0xeb,0x60,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3, -0xcc,0xe8,0xff,0xeb,0x02,0x20,0xa0,0xe3,0x79,0x00,0xa0,0xe3,0x06,0x10,0xa0,0xe3, -0x51,0xe8,0xff,0xeb,0x05,0x10,0xa0,0xe1,0x39,0x00,0xa0,0xe3,0x8f,0xef,0xff,0xeb, -0x05,0x10,0xa0,0xe1,0x20,0x00,0xa0,0xe3,0x8c,0xef,0xff,0xeb,0xf0,0x30,0x94,0xe5, -0x10,0x30,0x87,0xe5,0x64,0x31,0x94,0xe5,0xd0,0x36,0x87,0xe5,0x68,0x31,0x94,0xe5, -0xd4,0x36,0x87,0xe5,0x6c,0x31,0x94,0xe5,0xd8,0x36,0x87,0xe5,0x18,0x00,0x94,0xe5, -0x01,0x00,0x80,0xe2,0x61,0x03,0x00,0xeb,0x05,0x20,0xa0,0xe1,0x79,0x00,0xa0,0xe3, -0x06,0x10,0xa0,0xe3,0x3c,0xe8,0xff,0xeb,0x1c,0x10,0x94,0xe5,0x05,0x20,0xa0,0xe1, -0x79,0x00,0xa0,0xe3,0x06,0x11,0x41,0xe2,0x81,0x10,0xa0,0xe1,0x36,0xe8,0xff,0xeb, -0xf0,0x30,0x94,0xe5,0x10,0x34,0x87,0xe5,0xf4,0x30,0x94,0xe5,0x14,0x34,0x87,0xe5, -0x20,0x31,0x94,0xe5,0xdc,0x36,0x87,0xe5,0x20,0x30,0x94,0xe5,0xa8,0x36,0x87,0xe5, -0x24,0x30,0x94,0xe5,0x02,0x31,0x83,0xe3,0xa4,0x36,0x87,0xe5,0x28,0x00,0x94,0xe5, -0x01,0x00,0x80,0xe2,0x49,0x03,0x00,0xeb,0x04,0x31,0x94,0xe5,0x05,0x00,0x56,0xe1, -0x01,0x50,0xa0,0xe3,0xb8,0x36,0x87,0xe5,0x08,0x31,0x94,0xe5,0x08,0x34,0x87,0xe5, -0xc8,0x30,0x94,0xe5,0x04,0x35,0x87,0xe5,0x30,0x30,0x94,0xe5,0x2c,0x34,0x87,0xe5, -0x34,0x30,0x94,0xe5,0x30,0x34,0x87,0xe5,0x38,0x30,0x94,0xe5,0x34,0x34,0x87,0xe5, -0x3c,0x30,0x94,0xe5,0x38,0x34,0x87,0xe5,0x40,0x30,0x94,0xe5,0x3c,0x34,0x87,0xe5, -0x44,0x30,0x94,0xe5,0x40,0x34,0x87,0xe5,0x48,0x30,0x94,0xe5,0x44,0x34,0x87,0xe5, -0x4c,0x30,0x94,0xe5,0x48,0x34,0x87,0xe5,0x50,0x30,0x94,0xe5,0x4c,0x34,0x87,0xe5, -0x54,0x30,0x94,0xe5,0x50,0x34,0x87,0xe5,0x58,0x30,0x94,0xe5,0x54,0x34,0x87,0xe5, -0x5c,0x30,0x94,0xe5,0x58,0x34,0x87,0xe5,0x60,0x30,0x94,0xe5,0x5c,0x34,0x87,0xe5, -0x64,0x30,0x94,0xe5,0x60,0x34,0x87,0xe5,0x68,0x30,0x94,0xe5,0x64,0x34,0x87,0xe5, -0x6c,0x30,0x94,0xe5,0x68,0x34,0x87,0xe5,0x70,0x30,0x94,0xe5,0x6c,0x34,0x87,0xe5, -0x74,0x30,0x94,0xe5,0x70,0x34,0x87,0xe5,0x78,0x30,0x94,0xe5,0x74,0x34,0x87,0xe5, -0x7c,0x30,0x94,0xe5,0x78,0x34,0x87,0xe5,0x80,0x30,0x94,0xe5,0x7c,0x34,0x87,0xe5, -0x84,0x30,0x94,0xe5,0x80,0x34,0x87,0xe5,0x88,0x30,0x94,0xe5,0x84,0x34,0x87,0xe5, -0x8c,0x30,0x94,0xe5,0x88,0x34,0x87,0xe5,0x90,0x30,0x94,0xe5,0x8c,0x34,0x87,0xe5, -0x94,0x30,0x94,0xe5,0x90,0x34,0x87,0xe5,0x98,0x30,0x94,0xe5,0x94,0x34,0x87,0xe5, -0x9c,0x30,0x94,0xe5,0x98,0x34,0x87,0xe5,0xa0,0x30,0x94,0xe5,0x9c,0x34,0x87,0xe5, -0xa4,0x30,0x94,0xe5,0xa0,0x34,0x87,0xe5,0xa8,0x30,0x94,0xe5,0xa4,0x34,0x87,0xe5, -0xac,0x30,0x94,0xe5,0xa8,0x34,0x87,0xe5,0x24,0x31,0x94,0xe5,0xb0,0x34,0x87,0xe5, -0x28,0x31,0x94,0xe5,0xb4,0x34,0x87,0xe5,0xb0,0x30,0x94,0xe5,0xac,0x34,0x87,0xe5, -0xcc,0x30,0x94,0xe5,0x14,0x35,0x87,0xe5,0xb4,0x30,0x94,0xe5,0xf4,0x34,0x87,0xe5, -0x10,0x31,0x94,0xe5,0x03,0x31,0x83,0xe3,0xbc,0x36,0x87,0xe5,0xb8,0x30,0x94,0xe5, -0xf8,0x34,0x87,0xe5,0xbc,0x30,0x94,0xe5,0xfc,0x34,0x87,0xe5,0xc0,0x30,0x94,0xe5, -0x0c,0x35,0x87,0xe5,0xc4,0x30,0x94,0xe5,0x10,0x35,0x87,0xe5,0xd0,0x30,0x94,0xe5, -0x00,0x35,0x87,0xe5,0x14,0x31,0x94,0xe5,0xc0,0x36,0x87,0xe5,0x18,0x31,0x94,0xe5, -0xc4,0x36,0x87,0xe5,0x28,0x54,0x87,0xe5,0x41,0x00,0x00,0x1a,0x00,0x30,0x94,0xe5, -0x05,0x00,0x53,0xe1,0x03,0x00,0x53,0x13,0x56,0x00,0x00,0x0a,0x4c,0x52,0x9f,0xe5, -0x01,0x60,0xa0,0xe3,0x24,0x64,0x85,0xe5,0x2c,0x00,0x94,0xe5,0x06,0x00,0x80,0xe0, -0xda,0x02,0x00,0xeb,0x00,0x30,0x94,0xe5,0xdc,0x64,0x85,0xe5,0x02,0x00,0x53,0xe3, -0x04,0x00,0x53,0x13,0x47,0x00,0x00,0x0a,0x01,0x20,0x43,0xe2,0x03,0x00,0x52,0xe3, -0x02,0xf1,0x8f,0x90,0x1c,0x00,0x00,0xea,0x49,0x00,0x00,0xea,0x5b,0x00,0x00,0xea, -0x64,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0x00,0x52,0x9f,0xe5,0x01,0x30,0xa0,0xe3, -0xd8,0x34,0x85,0xe5,0xe8,0x30,0x94,0xe5,0xe8,0x34,0x85,0xe5,0xec,0x00,0x94,0xe5, -0x01,0x00,0x80,0xe2,0xc5,0x02,0x00,0xeb,0x3c,0x31,0x94,0xe5,0xe8,0x34,0x85,0xe5, -0x44,0x01,0x94,0xe5,0x01,0x00,0x80,0xe2,0xc0,0x02,0x00,0xeb,0x40,0x31,0x94,0xe5, -0xe8,0x34,0x85,0xe5,0x44,0x01,0x94,0xe5,0x01,0x00,0x80,0xe2,0xbb,0x02,0x00,0xeb, -0xdc,0x20,0x94,0xe5,0x00,0x30,0x94,0xe5,0xe8,0x24,0x85,0xe5,0xe0,0x20,0x94,0xe5, -0xe8,0x24,0x85,0xe5,0xe4,0x20,0x94,0xe5,0xe8,0x24,0x85,0xe5,0x04,0x00,0x53,0xe3, -0x1c,0x00,0x00,0x0a,0x94,0x31,0x9f,0xe5,0x01,0x20,0xa0,0xe3,0x28,0x24,0x83,0xe5, -0x02,0x21,0xa0,0xe3,0x20,0x24,0x83,0xe5,0x00,0x21,0x94,0xe5,0x0c,0x24,0x83,0xe5, -0xf8,0x20,0x94,0xe5,0x0c,0x20,0x83,0xe5,0xfc,0x20,0x94,0xe5,0x0c,0x21,0x83,0xe5, -0x6c,0x31,0x9f,0xe5,0x0c,0x21,0x94,0xe5,0xe0,0x20,0x83,0xe5,0x1c,0xd0,0x8d,0xe2, -0xf0,0x80,0xbd,0xe8,0x24,0x54,0x87,0xe5,0x2c,0x00,0x94,0xe5,0x01,0x00,0x80,0xe2, -0x9e,0x02,0x00,0xeb,0xdc,0x54,0x87,0xe5,0x1c,0x01,0x94,0xe5,0x01,0x00,0x80,0xe2, -0x9a,0x02,0x00,0xeb,0x00,0x30,0x94,0xe5,0x38,0x21,0x9f,0xe5,0x04,0x00,0x53,0xe3, -0xd4,0x24,0x87,0xe5,0xe2,0xff,0xff,0x1a,0x2c,0x21,0x94,0xe5,0x1c,0x31,0x9f,0xe5, -0xe0,0x26,0x83,0xe5,0x30,0x21,0x94,0xe5,0xe4,0x26,0x83,0xe5,0x34,0x21,0x94,0xe5, -0xe8,0x26,0x83,0xe5,0xda,0xff,0xff,0xea,0xc9,0x00,0xa0,0xe3,0x8b,0x02,0x00,0xeb, -0x00,0x30,0x94,0xe5,0xb3,0xff,0xff,0xea,0xc9,0x00,0xa0,0xe3,0x87,0x02,0x00,0xeb, -0xa5,0xff,0xff,0xea,0xe4,0x50,0x9f,0xe5,0x01,0x60,0xa0,0xe3,0xd8,0x64,0x85,0xe5, -0xd8,0x30,0x94,0xe5,0xd0,0x34,0x85,0xe5,0x38,0x31,0x94,0xe5,0xcc,0x34,0x85,0xe5, -0x48,0x01,0x94,0xe5,0x06,0x00,0x80,0xe0,0x7c,0x02,0x00,0xeb,0x00,0x30,0x94,0xe5, -0xd8,0x64,0x85,0xe5,0xd4,0x64,0x85,0xe5,0xd4,0x64,0x85,0xe5,0x04,0x00,0x53,0xe3, -0xd4,0x20,0x94,0xe5,0xcc,0x24,0x85,0xe5,0xc1,0xff,0xff,0x1a,0xdd,0xff,0xff,0xea, -0x98,0x30,0x9f,0xe5,0x01,0x20,0xa0,0xe3,0xd8,0x24,0x83,0xe5,0xd4,0x24,0x83,0xe5, -0xd4,0x24,0x83,0xe5,0xd4,0x20,0x94,0xe5,0xcc,0x24,0x83,0xe5,0xd8,0x20,0x94,0xe5, -0xd0,0x24,0x83,0xe5,0xb6,0xff,0xff,0xea,0x70,0x50,0x9f,0xe5,0x02,0x00,0xa0,0xe3, -0x66,0x02,0x00,0xeb,0x01,0x30,0xa0,0xe3,0xd8,0x34,0x85,0xe5,0x4c,0x21,0x94,0xe5, -0xd0,0x24,0x85,0xe5,0x50,0x21,0x94,0xe5,0xd0,0x24,0x85,0xe5,0x54,0x21,0x94,0xe5, -0xd0,0x24,0x85,0xe5,0x58,0x21,0x94,0xe5,0xcc,0x24,0x85,0xe5,0xd8,0x34,0x85,0xe5, -0xd4,0x34,0x85,0xe5,0xd4,0x34,0x85,0xe5,0xd4,0x30,0x94,0xe5,0xcc,0x34,0x85,0xe5, -0x60,0x01,0x94,0xe5,0x01,0x00,0x80,0xe2,0x54,0x02,0x00,0xeb,0x5c,0x21,0x94,0xe5, -0x00,0x30,0x94,0xe5,0xd0,0x24,0x85,0xe5,0xd8,0x20,0x94,0xe5,0x04,0x00,0x53,0xe3, -0xd0,0x24,0x85,0xe5,0x9a,0xff,0xff,0x1a,0xb6,0xff,0xff,0xea,0x9c,0x00,0x90,0x00, -0x00,0xf0,0x00,0x70,0x00,0xc0,0x00,0x60,0x01,0x08,0x00,0x00,0x70,0x21,0x90,0xe5, -0x00,0x10,0xa0,0xe3,0x04,0x30,0x9f,0xe5,0xe8,0x24,0x83,0xe5,0xa4,0xfe,0xff,0xea, -0x00,0xe0,0x00,0x70,0x08,0x40,0x2d,0xe9,0x0c,0x30,0x9f,0xe5,0x0c,0x00,0x93,0xe5, -0x49,0x02,0x00,0xeb,0x0a,0x00,0x80,0xe2,0x08,0x80,0xbd,0xe8,0x00,0xf0,0x00,0x70, -0x88,0x30,0x9f,0xe5,0x02,0x00,0x10,0xe3,0x84,0x20,0x9f,0xe5,0x00,0xc0,0xa0,0xe3, -0xf0,0x07,0x2d,0xe9,0x03,0x50,0xa0,0xe3,0x03,0x30,0x8f,0xe0,0x74,0x80,0x9f,0xe5, -0x00,0x60,0xa0,0x03,0x01,0x60,0xa0,0x13,0x01,0x40,0xa0,0xe3,0x68,0x70,0x9f,0xe5, -0x04,0x00,0x00,0xe0,0x02,0x20,0x93,0xe7,0x08,0x90,0x83,0xe0,0x08,0x50,0x83,0xe7, -0x07,0xa0,0x83,0xe0,0x07,0x60,0xc3,0xe7,0x02,0x39,0xa0,0xe3,0x04,0x40,0x89,0xe5, -0xb0,0x30,0x82,0xe5,0x02,0x3b,0xa0,0xe3,0x01,0x00,0xca,0xe5,0xa0,0x00,0x82,0xe5, -0xa4,0x60,0x82,0xe5,0xac,0x40,0x82,0xe5,0xa8,0x50,0x82,0xe5,0xb4,0x30,0x82,0xe5, -0xb8,0xc0,0x82,0xe5,0xbc,0xc0,0x82,0xe5,0xc0,0xc0,0x82,0xe5,0xc4,0xc0,0x82,0xe5, -0xc8,0x40,0x82,0xe5,0x00,0x90,0x81,0xe5,0xf0,0x07,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x78,0x62,0x00,0x00,0x40,0x00,0x00,0x00,0xf0,0x10,0x00,0x00,0xec,0x10,0x00,0x00, -0x04,0x20,0x90,0xe5,0x38,0x30,0x9f,0xe5,0x00,0x00,0x90,0xe5,0x01,0x20,0x42,0xe2, -0x7e,0x00,0x52,0xe3,0x03,0x30,0x8f,0xe0,0x00,0x20,0xa0,0x83,0x02,0x00,0xa0,0x81, -0x03,0x00,0x00,0x8a,0x03,0x00,0x50,0xe3,0x00,0x00,0xa0,0x83,0x01,0x00,0xa0,0x93, -0x00,0x20,0xa0,0xe1,0x0c,0x10,0x9f,0xe5,0x01,0x30,0x93,0xe7,0xc8,0x20,0x83,0xe5, -0x1e,0xff,0x2f,0xe1,0xdc,0x61,0x00,0x00,0x40,0x00,0x00,0x00,0x2c,0x30,0x9f,0xe5, -0x0f,0x00,0xa0,0xe3,0x00,0x00,0x81,0xe5,0x24,0x10,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x01,0x10,0x93,0xe7,0x0b,0x30,0xa0,0xe3,0x00,0x30,0x82,0xe5,0x02,0x39,0xa0,0xe3, -0xb0,0x30,0x81,0xe5,0x02,0x3b,0xa0,0xe3,0xb4,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x94,0x61,0x00,0x00,0x40,0x00,0x00,0x00,0x70,0x40,0x2d,0xe9,0x01,0x10,0xa0,0xe3, -0x00,0x50,0xa0,0xe1,0x2a,0x00,0xa0,0xe3,0x0c,0xee,0xff,0xeb,0x04,0x10,0x95,0xe5, -0xd8,0x40,0x9f,0xe5,0xd8,0x60,0x9f,0xe5,0x06,0x11,0x41,0xe2,0x00,0x20,0x95,0xe5, -0x04,0x40,0x8f,0xe0,0xcc,0x00,0x9f,0xe5,0x81,0x10,0xa0,0xe1,0xc2,0xe6,0xff,0xeb, -0x06,0x30,0x94,0xe7,0x01,0x10,0xa0,0xe3,0x04,0x20,0x95,0xe5,0xb4,0x00,0x9f,0xe5, -0xac,0x20,0x83,0xe5,0x00,0x20,0x95,0xe5,0xa8,0x20,0x83,0xe5,0x31,0xe7,0xff,0xeb, -0x2a,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0xf8,0xed,0xff,0xeb,0x2a,0x00,0xa0,0xe3, -0x00,0x10,0xa0,0xe3,0xf5,0xed,0xff,0xeb,0x8c,0x10,0x9f,0xe5,0x8c,0x20,0x9f,0xe5, -0x00,0x00,0x91,0xe5,0x02,0x30,0xd4,0xe7,0x02,0x20,0x84,0xe0,0x01,0x10,0xd2,0xe5, -0x02,0x02,0xc0,0xe3,0x00,0x00,0x53,0xe3,0x73,0x00,0xc0,0xe3,0x01,0x02,0xc0,0x13, -0x01,0x02,0x80,0x03,0x00,0x00,0x51,0xe3,0x01,0x21,0x80,0x13,0x01,0x21,0xc0,0x03, -0x00,0x00,0x53,0xe3,0x50,0x30,0x9f,0xe5,0x00,0x20,0x83,0xe5,0x07,0x00,0x00,0x0a, -0x00,0x00,0x51,0xe3,0x01,0x00,0xa0,0xe3,0x04,0x10,0xa0,0x03,0x01,0x10,0xa0,0x13, -0x6d,0xeb,0xff,0xeb,0x06,0x30,0x94,0xe7,0xc4,0x00,0x83,0xe5,0x70,0x80,0xbd,0xe8, -0x00,0x00,0x51,0xe3,0x01,0x00,0xa0,0xe3,0x03,0x10,0xa0,0x03,0x02,0x10,0xa0,0x13, -0x65,0xeb,0xff,0xeb,0x06,0x30,0x94,0xe7,0xc4,0x00,0x83,0xe5,0x70,0x80,0xbd,0xe8, -0x40,0x61,0x00,0x00,0x40,0x00,0x00,0x00,0x6a,0x00,0xd0,0x01,0x00,0x90,0x00,0x70, -0xec,0x10,0x00,0x00,0x50,0x30,0x9f,0xe5,0x80,0xc7,0xa0,0xe1,0x30,0x00,0x2d,0xe9, -0x48,0x40,0x9f,0xe5,0x0d,0xc2,0x8c,0xe2,0x03,0x30,0x8f,0xe0,0x81,0xc5,0x8c,0xe0, -0x04,0x40,0x93,0xe7,0x00,0x30,0xa0,0xe3,0xb8,0x50,0x94,0xe5,0xc0,0x10,0x84,0xe5, -0xbc,0x00,0x84,0xe5,0x01,0x10,0x85,0xe2,0xb8,0x10,0x84,0xe5,0xbc,0x10,0x93,0xe1, -0xb3,0x10,0x82,0xe1,0x02,0x30,0x83,0xe2,0x02,0x0b,0x53,0xe3,0xfa,0xff,0xff,0x1a, -0x00,0x00,0xa0,0xe3,0x30,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x48,0x60,0x00,0x00, -0x40,0x00,0x00,0x00,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x10,0x40,0x2d,0xe9, -0x2a,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0xb0,0xed,0xff,0xeb,0x08,0x00,0x9f,0xe5, -0x00,0x10,0xa0,0xe3,0x10,0x40,0xbd,0xe8,0xe2,0xe6,0xff,0xea,0x6a,0x00,0xd0,0x01, -0x64,0x00,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0x60,0x30,0x9f,0xe5,0xf0,0x00,0x2d,0xe9, -0x02,0x60,0xa0,0xe3,0x00,0x00,0x8f,0xe0,0x54,0x70,0x9f,0xe5,0x03,0x50,0xa0,0xe3, -0x01,0x40,0xa0,0xe3,0x03,0x30,0x90,0xe7,0x07,0xc0,0x80,0xe0,0x07,0x50,0x80,0xe7, -0x04,0x60,0xcc,0xe5,0x05,0x20,0xcc,0xe5,0xa4,0x60,0x83,0xe5,0xa0,0x50,0x83,0xe5, -0xa8,0x20,0x83,0xe5,0xac,0x20,0x83,0xe5,0xb0,0x20,0x83,0xe5,0xb4,0x20,0x83,0xe5, -0xb8,0x40,0x83,0xe5,0xbc,0x20,0x83,0xe5,0xc0,0x20,0x83,0xe5,0xc4,0x40,0x83,0xe5, -0x00,0xc0,0x81,0xe5,0xf0,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0xbc,0x5f,0x00,0x00, -0x40,0x00,0x00,0x00,0xf8,0x10,0x00,0x00,0xd4,0x20,0xd0,0xe1,0x34,0x30,0x9f,0xe5, -0x00,0x00,0x90,0xe5,0x00,0x00,0x52,0xe3,0x00,0x20,0xa0,0xd3,0x03,0x30,0x8f,0xe0, -0x02,0x00,0xa0,0xd1,0x03,0x00,0x00,0xda,0x03,0x00,0x50,0xe3,0x00,0x00,0xa0,0x83, -0x01,0x00,0xa0,0x93,0x00,0x20,0xa0,0xe1,0x0c,0x10,0x9f,0xe5,0x01,0x30,0x93,0xe7, -0xc4,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x44,0x5f,0x00,0x00,0x40,0x00,0x00,0x00, -0x0f,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x0b,0x30,0xa0,0xe3,0x00,0x30,0x82,0xe5, -0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0x00,0x60,0xa0,0xe1,0x00,0x50,0xa0,0xe3, -0x01,0x20,0xa0,0xe1,0x2b,0x00,0xa0,0xe3,0x04,0x50,0x81,0xe5,0x01,0x10,0xa0,0xe3, -0x05,0xc0,0xd6,0xe5,0xa8,0x30,0x9f,0xe5,0xa8,0xe0,0x9f,0xe5,0x00,0xc0,0xc2,0xe5, -0xa4,0xc0,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x0e,0x20,0x83,0xe7,0x0c,0x40,0x93,0xe7, -0x04,0xc0,0xd6,0xe5,0xa4,0xc0,0x84,0xe5,0x00,0x30,0x96,0xe5,0xa0,0x30,0x84,0xe5, -0x05,0x30,0xd6,0xe5,0xa8,0x30,0x84,0xe5,0x60,0xed,0xff,0xeb,0x22,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x5d,0xed,0xff,0xeb,0x04,0x10,0xd6,0xe5,0x00,0x20,0x96,0xe5, -0x68,0x00,0x9f,0xe5,0x01,0x10,0x41,0xe2,0x81,0x10,0xa0,0xe1,0x16,0xe6,0xff,0xeb, -0x58,0x00,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0x8a,0xe6,0xff,0xeb,0x62,0x00,0xa0,0xe3, -0x01,0x10,0xa0,0xe3,0x87,0xe6,0xff,0xeb,0x05,0x10,0xa0,0xe1,0x2b,0x00,0xa0,0xe3, -0x4e,0xed,0xff,0xeb,0x05,0x10,0xa0,0xe1,0x22,0x00,0xa0,0xe3,0x4b,0xed,0xff,0xeb, -0x01,0x10,0xa0,0xe3,0x02,0x00,0xa0,0xe3,0xd7,0xea,0xff,0xeb,0x05,0x00,0x50,0xe1, -0xbc,0x00,0x84,0xe5,0x18,0x20,0x9f,0x05,0x18,0x30,0x9f,0x05,0x80,0x23,0x83,0x05, -0x70,0x80,0xbd,0xe8,0xcc,0x5e,0x00,0x00,0x00,0x11,0x00,0x00,0x40,0x00,0x00,0x00, -0x6b,0x00,0x14,0x01,0x20,0x30,0x01,0x00,0x00,0xc0,0x00,0x70,0xf0,0x4f,0x2d,0xe9, -0x02,0xa0,0xa0,0xe1,0xbc,0x42,0x9f,0xe5,0x80,0x87,0xa0,0xe1,0x14,0xd0,0x4d,0xe2, -0xb4,0x52,0x9f,0xe5,0x81,0x85,0x88,0xe0,0x04,0x40,0x8f,0xe0,0xac,0x62,0x9f,0xe5, -0x05,0x30,0x94,0xe7,0x06,0x70,0x94,0xe7,0xac,0x20,0x93,0xe5,0xb0,0x00,0x83,0xe5, -0xb4,0x10,0x83,0xe5,0x01,0x20,0x82,0xe2,0xac,0x20,0x83,0xe5,0x02,0x01,0x00,0xeb, -0x06,0x30,0x94,0xe7,0x04,0x00,0x87,0xe5,0x00,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3, -0x94,0x00,0x00,0x0a,0x02,0x70,0xa0,0xe3,0x05,0xb0,0xa0,0xe3,0x00,0x30,0xa0,0xe3, -0x0b,0x20,0xa0,0xe3,0x08,0x20,0xcd,0xe5,0x0c,0x30,0xcd,0xe5,0x0d,0x30,0xcd,0xe5, -0x0e,0x30,0xcd,0xe5,0x0f,0x30,0xcd,0xe5,0x54,0x32,0x9f,0xe5,0x28,0x18,0xa0,0xe1, -0x28,0x24,0xa0,0xe1,0x0b,0x80,0xcd,0xe5,0x09,0x10,0xcd,0xe5,0x0a,0x20,0xcd,0xe5, -0x03,0x20,0xa0,0xe1,0x80,0x13,0x93,0xe5,0x02,0x1a,0xc1,0xe3,0x80,0x13,0x83,0xe5, -0x03,0x12,0xa0,0xe3,0x84,0x13,0x83,0xe5,0x84,0x33,0x92,0xe5,0x20,0x92,0x9f,0xe5, -0x03,0x02,0x13,0xe3,0xfb,0xff,0xff,0x1a,0xe3,0x00,0x00,0xeb,0x80,0x83,0x99,0xe5, -0x09,0x20,0xa0,0xe1,0x04,0x00,0x8d,0xe5,0x0c,0x30,0x8d,0xe2,0x1f,0x80,0xc8,0xe3, -0x02,0x89,0x88,0xe3,0x07,0x80,0x88,0xe3,0x80,0x83,0x89,0xe5,0x04,0x90,0xa0,0xe1, -0x84,0x13,0x92,0xe5,0x01,0x05,0x11,0xe3,0x73,0x00,0x00,0x1a,0x02,0xc0,0x53,0xe5, -0x01,0x70,0x57,0xe2,0x03,0x40,0x53,0xe5,0x04,0x00,0x53,0xe5,0x01,0x10,0x53,0xe5, -0x04,0x30,0x83,0xe2,0x0c,0xc8,0xa0,0xe1,0x04,0xc4,0x8c,0xe1,0x00,0xc0,0x8c,0xe1, -0x01,0x1c,0x8c,0xe1,0x90,0x13,0x82,0xe5,0xf0,0xff,0xff,0x1a,0x09,0x40,0xa0,0xe1, -0x01,0x20,0x4b,0xe2,0xa8,0x31,0x9f,0xe5,0x02,0x28,0xa0,0xe1,0xa4,0xb1,0x9f,0xe5, -0x22,0x28,0xa0,0xe1,0x03,0x90,0xa0,0xe1,0x01,0x26,0x82,0xe3,0x02,0x11,0x82,0xe3, -0x8c,0x23,0x83,0xe5,0x8c,0x13,0x83,0xe5,0x05,0x30,0xa0,0xe1,0x06,0x50,0xa0,0xe1, -0x04,0x60,0x9d,0xe5,0x84,0x23,0x99,0xe5,0x74,0x71,0x9f,0xe5,0x00,0x00,0x52,0xe3, -0x26,0x00,0x00,0xba,0x03,0x50,0xa0,0xe1,0x64,0x31,0x9f,0xe5,0x02,0x89,0xc8,0xe3, -0x00,0x10,0xa0,0xe3,0x60,0x21,0x9f,0xe5,0x01,0x00,0xa0,0xe1,0x84,0xc3,0x93,0xe5, -0x84,0xc3,0x83,0xe5,0x80,0x83,0x83,0xe5,0x84,0xc3,0x93,0xe5,0x84,0xc3,0x83,0xe5, -0x80,0x63,0x93,0xe5,0x05,0xc0,0x94,0xe7,0x1f,0x60,0xc6,0xe3,0x01,0x49,0x86,0xe3, -0x07,0x40,0x84,0xe3,0x80,0x43,0x83,0xe5,0x02,0x41,0xa0,0xe3,0xc0,0x10,0x8c,0xe5, -0x28,0xc1,0x9f,0xe5,0x00,0x40,0x8c,0xe5,0x00,0x10,0x82,0xe5,0x01,0x13,0xa0,0xe3, -0x14,0x10,0x82,0xe5,0x18,0x11,0x9f,0xe5,0x1c,0x10,0x82,0xe5,0x14,0x11,0x9f,0xe5, -0x10,0xa0,0x82,0xe5,0x18,0x10,0x82,0xe5,0x0c,0x11,0x9f,0xe5,0x00,0x10,0x82,0xe5, -0x04,0x10,0x81,0xe0,0x00,0x10,0x82,0xe5,0x00,0x21,0x9f,0xe5,0x8c,0x23,0x83,0xe5, -0x04,0x20,0x82,0xe0,0x8c,0x23,0x83,0xe5,0x14,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x06,0x00,0xa0,0xe1,0x00,0x30,0x8d,0xe5,0x93,0x00,0x00,0xeb,0x0b,0x00,0x50,0xe1, -0x00,0x30,0x9d,0xe5,0xce,0xff,0xff,0x9a,0x05,0x60,0xa0,0xe1,0x03,0x50,0xa0,0xe1, -0x84,0x33,0x97,0xe5,0x00,0x00,0x53,0xe3,0xce,0xff,0xff,0xaa,0x07,0x10,0xa0,0xe1, -0x03,0x32,0xa0,0xe3,0x84,0x33,0x87,0xe5,0x84,0x33,0x91,0xe5,0x90,0x20,0x9f,0xe5, -0x03,0x32,0x13,0xe2,0xfb,0xff,0xff,0x1a,0x84,0x03,0x92,0xe5,0x02,0x89,0xc8,0xe3, -0x05,0x70,0x94,0xe7,0x03,0xc0,0xa0,0xe3,0x06,0x40,0x94,0xe7,0x84,0x03,0x82,0xe5, -0x0c,0x00,0xa0,0xe1,0x80,0x83,0x82,0xe5,0x80,0x83,0x92,0xe5,0x68,0x10,0x9f,0xe5, -0x02,0x5a,0x88,0xe3,0x80,0x53,0x82,0xe5,0x84,0x53,0x92,0xe5,0xc0,0xc0,0x87,0xe5, -0x6c,0xc0,0x9f,0xe5,0x84,0x53,0x82,0xe5,0x80,0xc3,0x82,0xe5,0x4c,0x20,0x9f,0xe5, -0x00,0x30,0x82,0xe5,0x01,0x21,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x04,0x20,0x81,0xe5, -0x04,0x30,0x84,0xe5,0xd3,0xff,0xff,0xea,0x03,0x30,0xa0,0xe3,0x01,0x70,0xa0,0xe3, -0x04,0xb0,0xa0,0xe3,0x08,0x30,0xcd,0xe5,0x6e,0xff,0xff,0xea,0x09,0x40,0xa0,0xe1, -0x07,0xb1,0x4b,0xe0,0x95,0xff,0xff,0xea,0xf8,0x5d,0x00,0x00,0x40,0x00,0x00,0x00, -0x00,0x11,0x00,0x00,0x00,0xc0,0x00,0x70,0x40,0x0d,0x03,0x00,0x00,0xb0,0x00,0x60, -0x00,0xa0,0x00,0x60,0x00,0x00,0x01,0x20,0xa0,0xc3,0x00,0x70,0xfc,0x07,0x2b,0x08, -0xff,0x07,0x10,0x00,0x20,0x30,0x01,0x00,0xcc,0x20,0x9f,0xe5,0x10,0x40,0x2d,0xe9, -0xc8,0x40,0x9f,0xe5,0x84,0x33,0x92,0xe5,0x04,0x40,0x8f,0xe0,0x00,0x00,0x53,0xe3, -0x13,0x00,0x00,0xba,0xb8,0x10,0x9f,0xe5,0x04,0x30,0x91,0xe5,0x00,0x00,0x53,0xe3, -0x0f,0x00,0x00,0xba,0x84,0xc3,0x92,0xe5,0x00,0x00,0xa0,0xe3,0x01,0x30,0xa0,0xe3, -0x84,0xc3,0x82,0xe5,0x9c,0xc0,0x9f,0xe5,0x80,0xc3,0x82,0xe5,0x98,0x20,0x9f,0xe5, -0x00,0x00,0x82,0xe5,0x01,0x21,0xa0,0xe3,0x00,0x00,0x81,0xe5,0x04,0x20,0x81,0xe5, -0x88,0x20,0x9f,0xe5,0x03,0x00,0xa0,0xe1,0x02,0x20,0x94,0xe7,0xb8,0x30,0x82,0xe5, -0x10,0x80,0xbd,0xe8,0x78,0x30,0x9f,0xe5,0x03,0x30,0x94,0xe7,0x04,0x00,0x93,0xe5, -0x39,0x00,0x00,0xeb,0x6c,0x30,0x9f,0xe5,0x03,0x00,0x50,0xe1,0x02,0x30,0xa0,0x93, -0xf2,0xff,0xff,0x9a,0x40,0x20,0x9f,0xe5,0x00,0x00,0xa0,0xe3,0x40,0x10,0x9f,0xe5, -0x03,0x30,0xa0,0xe3,0x84,0xc3,0x92,0xe5,0x84,0xc3,0x82,0xe5,0x34,0xc0,0x9f,0xe5, -0x80,0xc3,0x82,0xe5,0x30,0x20,0x9f,0xe5,0x00,0x00,0x82,0xe5,0x01,0x21,0xa0,0xe3, -0x00,0x00,0x81,0xe5,0x03,0x00,0xa0,0xe1,0x04,0x20,0x81,0xe5,0x1c,0x20,0x9f,0xe5, -0x02,0x20,0x94,0xe7,0xb8,0x30,0x82,0xe5,0x10,0x80,0xbd,0xe8,0x00,0xc0,0x00,0x70, -0x08,0x5b,0x00,0x00,0x00,0xb0,0x00,0x60,0x20,0x30,0x01,0x00,0x00,0xa0,0x00,0x60, -0x40,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x40,0x0d,0x03,0x00,0x44,0x30,0x9f,0xe5, -0x2b,0x00,0xa0,0xe3,0x40,0x20,0x9f,0xe5,0x01,0x10,0xa0,0xe3,0x10,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe3,0x03,0x30,0x8f,0xe0,0x02,0x40,0x83,0xe7,0x37,0xec,0xff,0xeb, -0x22,0x00,0xa0,0xe3,0x01,0x10,0xa0,0xe3,0x34,0xec,0xff,0xeb,0x04,0x10,0xa0,0xe1, -0x18,0x00,0x9f,0xe5,0x67,0xe5,0xff,0xeb,0x62,0x00,0xa0,0xe3,0x04,0x10,0xa0,0xe1, -0x10,0x40,0xbd,0xe8,0x63,0xe5,0xff,0xea,0x0c,0x5a,0x00,0x00,0x00,0x11,0x00,0x00, -0x6b,0x00,0x14,0x01,0x80,0x08,0x00,0xea,0xaa,0x08,0x00,0xea,0x04,0x30,0x9f,0xe5, -0x10,0x00,0x93,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x50,0x00,0x60,0x10,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0xf8,0xff,0xff,0xeb,0x00,0x00,0x64,0xe0,0x10,0x80,0xbd,0xe8, -0x38,0x40,0x2d,0xe9,0x00,0x40,0xa0,0xe1,0xf3,0xff,0xff,0xeb,0x00,0x00,0x54,0xe3, -0x00,0x50,0xa0,0xe1,0x38,0x80,0xbd,0x08,0xef,0xff,0xff,0xeb,0x00,0x00,0x65,0xe0, -0x04,0x00,0x50,0xe1,0xfb,0xff,0xff,0x3a,0x38,0x80,0xbd,0xe8,0x01,0x00,0x50,0xe3, -0x00,0x30,0xa0,0xe1,0x05,0x00,0x00,0x9a,0x00,0x00,0xa0,0xe3,0xa3,0x30,0xa0,0xe1, -0x01,0x00,0x80,0xe2,0x01,0x00,0x53,0xe3,0xfb,0xff,0xff,0x8a,0x1e,0xff,0x2f,0xe1, -0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x06,0x09,0x00,0xea,0x17,0x09,0x00,0xea, -0x88,0x08,0x00,0xea,0xc1,0x08,0x00,0xea,0x5b,0x08,0x00,0xea,0x04,0x10,0xa0,0xe3, -0x01,0x20,0xa0,0xe3,0x02,0x30,0xa0,0xe3,0xbf,0x04,0x00,0xea,0xd9,0x04,0x00,0xea, -0x3c,0x01,0x00,0xea,0x01,0x30,0xa0,0xe3,0x00,0x30,0x80,0xe5,0x00,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x10,0x40,0x2d,0xe9,0x14,0x40,0x9f,0xe5,0x35,0x03,0x00,0xeb, -0x10,0x30,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x03,0x30,0x94,0xe7,0x00,0x00,0x83,0xe5, -0x10,0x80,0xbd,0xe8,0xfc,0x58,0x00,0x00,0x50,0x00,0x00,0x00,0x10,0x30,0x9f,0xe5, -0x10,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x00,0x93,0xe5, -0x29,0x03,0x00,0xea,0xdc,0x58,0x00,0x00,0x50,0x00,0x00,0x00,0x51,0x01,0x00,0xea, -0x70,0x40,0x2d,0xe9,0x23,0x03,0x00,0xeb,0x00,0x50,0xa0,0xe1,0xd5,0x04,0x00,0xeb, -0x00,0x40,0xa0,0xe1,0x01,0x60,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x1e,0x03,0x00,0xeb, -0x04,0x00,0xa0,0xe1,0x06,0x10,0xa0,0xe1,0x70,0x80,0xbd,0xe8,0x08,0x40,0x2d,0xe9, -0xf2,0xff,0xff,0xeb,0xfa,0x2f,0xa0,0xe3,0x00,0x30,0xa0,0xe3,0xaf,0x09,0x00,0xeb, -0x08,0x80,0xbd,0xe8,0xf8,0x40,0x2d,0xe9,0x00,0x70,0xa0,0xe1,0x00,0x60,0xa0,0xe3, -0xea,0xff,0xff,0xeb,0x06,0x00,0x57,0xe1,0x00,0x40,0xa0,0xe1,0x01,0x50,0xa0,0xe1, -0xf8,0x80,0xbd,0x08,0xe5,0xff,0xff,0xeb,0x00,0x20,0xa0,0xe1,0x01,0x30,0xa0,0xe1, -0x04,0x20,0x52,0xe0,0x05,0x30,0xc3,0xe0,0x03,0x00,0x56,0xe1,0xf8,0x80,0xbd,0x18, -0x02,0x00,0x57,0xe1,0xf6,0xff,0xff,0x8a,0xf8,0x80,0xbd,0xe8,0x08,0x40,0x2d,0xe9, -0x02,0x03,0x00,0xeb,0x01,0x03,0x00,0xeb,0xfc,0xff,0xff,0xea,0x10,0x40,0x2d,0xe9, -0x08,0xd0,0x4d,0xe2,0x50,0x40,0x9f,0xe5,0x61,0x04,0x00,0xeb,0x05,0x02,0x00,0xeb, -0x61,0x04,0x00,0xeb,0x44,0x00,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x00,0x00,0x84,0xe0, -0x39,0x02,0x00,0xeb,0x38,0x30,0x9f,0xe5,0x38,0x00,0x9f,0xe5,0x03,0x10,0x94,0xe7, -0x00,0x00,0x84,0xe0,0x34,0x02,0x00,0xeb,0xed,0x02,0x00,0xeb,0x00,0x00,0xa0,0xe3, -0x08,0x10,0x8d,0xe2,0x04,0x00,0x21,0xe5,0x59,0x9c,0xff,0xeb,0xe9,0x02,0x00,0xeb, -0xea,0x02,0x00,0xeb,0xe9,0x02,0x00,0xeb,0xfc,0xff,0xff,0xea,0x08,0x58,0x00,0x00, -0xe0,0xf2,0xff,0xff,0x0c,0x11,0x00,0x00,0x10,0xf3,0xff,0xff,0x00,0x00,0x52,0xe3, -0x06,0x00,0x00,0x1a,0x04,0x30,0x91,0xe5,0x08,0x10,0x80,0xe5,0x04,0x30,0x80,0xe5, -0x04,0x30,0x91,0xe5,0x04,0x00,0x81,0xe5,0x08,0x00,0x83,0xe5,0x1e,0xff,0x2f,0xe1, -0x14,0x30,0x91,0xe5,0x0c,0x20,0x81,0xe2,0x0c,0x00,0x80,0xe9,0x14,0x30,0x91,0xe5, -0x14,0x00,0x81,0xe5,0x04,0x00,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0x04,0x30,0x90,0xe5, -0x0c,0x00,0x80,0xe2,0x00,0x00,0x53,0xe1,0x08,0x00,0x00,0x0a,0x08,0x10,0x93,0xe5, -0x00,0x20,0xa0,0xe3,0x01,0x10,0x93,0xe8,0x04,0xc0,0x81,0xe5,0x04,0xc0,0x93,0xe5, -0x04,0x20,0x83,0xe5,0x08,0x10,0x8c,0xe5,0x08,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x08,0x20,0x90,0xe5,0x00,0x30,0xa0,0xe3, -0x04,0x10,0x90,0xe5,0x04,0x10,0x82,0xe5,0x04,0x10,0x90,0xe5,0x04,0x30,0x80,0xe5, -0x08,0x20,0x81,0xe5,0x08,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x30,0xa0,0xe3, -0x00,0x20,0xa0,0xe1,0x0c,0x30,0xa2,0xe5,0x00,0x30,0x80,0xe5,0x0c,0x00,0x80,0xe9, -0x14,0x00,0x80,0xe5,0x10,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0xf8,0x4f,0x2d,0xe9, -0xd0,0x40,0x9f,0xe5,0xd0,0x60,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x61,0x04,0x00,0xeb, -0x06,0x30,0x94,0xe7,0x00,0x70,0xa0,0xe1,0x01,0x80,0xa0,0xe1,0x04,0xa0,0x93,0xe5, -0x0c,0x30,0x83,0xe2,0x03,0x00,0x5a,0xe1,0xf8,0x8f,0xbd,0x08,0xac,0xb0,0x9f,0xe5, -0x00,0x50,0xa0,0xe3,0x06,0x00,0x00,0xea,0x02,0x00,0x51,0xe1,0x04,0xa0,0x9a,0x85, -0x0c,0x00,0x00,0x9a,0x06,0x30,0x94,0xe7,0x0c,0x30,0x83,0xe2,0x03,0x00,0x5a,0xe1, -0x1f,0x00,0x00,0x0a,0x00,0x90,0x9a,0xe5,0x0a,0x00,0xa0,0xe1,0x88,0x30,0x89,0xe2, -0x0c,0x00,0x93,0xe8,0x90,0x10,0x99,0xe5,0x02,0x20,0x57,0xe0,0x03,0x30,0xc8,0xe0, -0x03,0x00,0x55,0xe1,0xef,0xff,0xff,0x0a,0x04,0xa0,0x9a,0xe5,0xcd,0xff,0xff,0xeb, -0x9c,0x30,0x99,0xe5,0x01,0x20,0xa0,0xe3,0x94,0x20,0xc9,0xe5,0x00,0x20,0xa0,0xe3, -0x98,0x00,0x89,0xe2,0x90,0x50,0x89,0xe5,0x00,0x00,0x53,0xe3,0x00,0x30,0xa0,0xe3, -0x88,0x20,0x89,0xe5,0x8c,0x30,0x89,0xe5,0xc2,0xff,0xff,0x1b,0x02,0x30,0xa0,0xe3, -0xa4,0x00,0x89,0xe2,0x08,0x30,0x89,0xe5,0x00,0x20,0xa0,0xe3,0x0b,0x10,0x94,0xe7, -0x9d,0xff,0xff,0xeb,0x06,0x30,0x94,0xe7,0x0c,0x30,0x83,0xe2,0x03,0x00,0x5a,0xe1, -0xdf,0xff,0xff,0x1a,0xf8,0x8f,0xbd,0xe8,0xe8,0x56,0x00,0x00,0x38,0x00,0x00,0x00, -0x94,0x00,0x00,0x00,0xf8,0x40,0x2d,0xe9,0x08,0x41,0x9f,0xe5,0x08,0x51,0x9f,0xe5, -0x04,0x40,0x8f,0xe0,0x04,0x61,0x9f,0xe5,0x05,0x20,0x94,0xe7,0x06,0x30,0x94,0xe7, -0x00,0x00,0x92,0xe5,0x03,0x00,0x50,0xe1,0x08,0x00,0x00,0x0a,0x08,0x30,0x90,0xe5, -0x01,0x30,0x43,0xe2,0x03,0x00,0x53,0xe3,0x03,0xf1,0x8f,0x90,0x0e,0x00,0x00,0xea, -0x02,0x00,0x00,0xea,0x26,0x00,0x00,0xea,0x2b,0x00,0x00,0xea,0x0b,0x00,0x00,0xea, -0xcc,0x70,0x9f,0xe5,0xb0,0xff,0xff,0xeb,0x07,0x00,0x94,0xe7,0x8e,0xff,0xff,0xeb, -0x00,0x00,0x50,0xe3,0x10,0x00,0x00,0x0a,0xb8,0x30,0x9f,0xe5,0x00,0x20,0xa0,0xe3, -0x03,0x20,0x84,0xe7,0x05,0x30,0x94,0xe7,0x00,0x00,0x83,0xe5,0xf8,0x80,0xbd,0xe8, -0xa4,0x30,0x9f,0xe5,0xa4,0x00,0x80,0xe2,0x94,0x70,0x9f,0xe5,0x01,0x20,0xa0,0xe3, -0x03,0x10,0x94,0xe7,0x70,0xff,0xff,0xeb,0x9f,0xff,0xff,0xeb,0x07,0x00,0x94,0xe7, -0x7d,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3,0xee,0xff,0xff,0x1a,0x74,0x30,0x9f,0xe5, -0x03,0x20,0x94,0xe7,0x01,0x20,0x82,0xe2,0x95,0x00,0x52,0xe3,0x03,0x20,0x84,0xe7, -0x06,0x00,0x94,0x97,0xea,0xff,0xff,0x9a,0x03,0x00,0x84,0xe7,0x02,0x20,0xa0,0xe3, -0x58,0x30,0x9f,0xe5,0x06,0x00,0x94,0xe7,0x03,0x30,0x94,0xe7,0x00,0x20,0x83,0xe5, -0xe3,0xff,0xff,0xea,0x38,0x70,0x9f,0xe5,0xa4,0x00,0x80,0xe2,0x01,0x20,0xa0,0xe3, -0x07,0x10,0x94,0xe7,0x58,0xff,0xff,0xeb,0xd5,0xff,0xff,0xea,0x30,0x30,0x9f,0xe5, -0xa4,0x00,0x80,0xe2,0x01,0x20,0xa0,0xe3,0x14,0x70,0x9f,0xe5,0x03,0x10,0x94,0xe7, -0x51,0xff,0xff,0xeb,0xce,0xff,0xff,0xea,0x00,0x56,0x00,0x00,0x48,0x00,0x00,0x00, -0x4c,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0x08,0x11,0x00,0x00,0x38,0x00,0x00,0x00, -0x74,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x70,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1, -0x30,0x40,0x9f,0xe5,0x27,0x02,0x00,0xeb,0x2c,0x30,0x9f,0xe5,0x04,0x40,0x8f,0xe0, -0x01,0x00,0x55,0xe3,0x03,0x30,0x94,0xe7,0x00,0x00,0x93,0xe5,0x08,0x50,0x80,0xe5, -0x01,0x00,0x00,0x0a,0x70,0x40,0xbd,0xe8,0x26,0x02,0x00,0xea,0x1c,0x00,0x80,0xe2, -0xf5,0xfe,0xff,0xeb,0xfa,0xff,0xff,0xea,0xc4,0x54,0x00,0x00,0x48,0x00,0x00,0x00, -0x70,0x40,0x2d,0xe9,0x54,0x50,0x9f,0xe5,0x54,0x60,0x9f,0xe5,0x05,0x50,0x8f,0xe0, -0x06,0x30,0x95,0xe7,0x00,0x30,0x93,0xe5,0x80,0x20,0x93,0xe5,0x00,0x00,0x52,0xe3, -0x0b,0x00,0x00,0x0a,0x00,0x40,0xa0,0xe3,0x1c,0x10,0x84,0xe2,0x18,0x20,0x84,0xe2, -0x01,0x01,0x93,0xe7,0x01,0x40,0x84,0xe2,0x0f,0xe0,0xa0,0xe1,0x02,0xf1,0x93,0xe7, -0x06,0x30,0x95,0xe7,0x00,0x30,0x93,0xe5,0x80,0x20,0x93,0xe5,0x04,0x00,0x52,0xe1, -0xf4,0xff,0xff,0x8a,0x01,0x00,0xa0,0xe3,0x70,0x40,0xbd,0xe8,0xd5,0xff,0xff,0xea, -0x84,0x54,0x00,0x00,0x48,0x00,0x00,0x00,0x70,0x40,0x2d,0xe9,0x00,0x60,0xa0,0xe1, -0x5c,0x40,0x9f,0xe5,0xfb,0x01,0x00,0xeb,0x58,0x30,0x9f,0xe5,0x04,0x40,0x8f,0xe0, -0x03,0x40,0x94,0xe7,0x04,0x30,0xa0,0xe3,0x00,0x50,0x94,0xe5,0x08,0x30,0x85,0xe5, -0xa8,0x03,0x00,0xeb,0xfa,0x2f,0xa0,0xe3,0x00,0x30,0x94,0xe5,0x92,0x06,0x06,0xe0, -0x88,0x00,0x85,0xe5,0x8c,0x10,0x85,0xe5,0x90,0x60,0x83,0xe5,0xf5,0x01,0x00,0xeb, -0x00,0x30,0x94,0xe5,0x00,0x20,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x10,0xa0,0xe3, -0x90,0x20,0x83,0xe5,0x88,0x00,0x83,0xe5,0x8c,0x10,0x83,0xe5,0x94,0x20,0xc3,0xe5, -0x70,0x80,0xbd,0xe8,0x14,0x54,0x00,0x00,0x48,0x00,0x00,0x00,0x38,0x40,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0x04,0x00,0x80,0xe2,0x01,0x50,0xa0,0xe1,0x22,0xff,0xff,0xeb, -0x00,0x30,0xa0,0xe3,0x01,0x20,0xa0,0xe3,0x00,0x50,0x84,0xe5,0x1c,0x20,0x84,0xe5, -0x24,0x30,0x84,0xe5,0x20,0x30,0x84,0xe5,0x28,0x30,0x84,0xe5,0x2c,0x30,0x84,0xe5, -0x30,0x30,0x84,0xe5,0x38,0x80,0xbd,0xe8,0xf0,0x47,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0xb4,0x60,0x9f,0xe5,0x75,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x06,0x60,0x8f,0xe0, -0x00,0x50,0xa0,0x13,0x25,0x00,0x00,0x0a,0x00,0x80,0x94,0xe5,0x00,0x00,0x58,0xe3, -0x09,0x00,0x00,0x0a,0x01,0x80,0x88,0xe2,0x00,0x80,0x84,0xe5,0x79,0x03,0x00,0xeb, -0x24,0x00,0x84,0xe5,0x69,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0xf0,0x87,0xbd,0x18, -0x05,0x00,0xa0,0xe1,0xf0,0x47,0xbd,0xe8,0xbf,0x01,0x00,0xea,0x04,0x00,0x84,0xe2, -0xe9,0xfe,0xff,0xeb,0x00,0x70,0x50,0xe2,0x00,0x80,0x94,0x05,0xf0,0xff,0xff,0x0a, -0xa4,0xa0,0x87,0xe2,0x0a,0x00,0xa0,0xe1,0xf2,0xfe,0xff,0xeb,0x02,0x30,0xa0,0xe3, -0x0a,0x00,0xa0,0xe1,0x08,0x30,0x87,0xe5,0x08,0x20,0xa0,0xe1,0x3c,0x30,0x9f,0xe5, -0x03,0x60,0x96,0xe7,0x06,0x10,0xa0,0xe1,0x04,0x70,0x96,0xe5,0xca,0xfe,0xff,0xeb, -0x52,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0xe3,0xff,0xff,0x0a,0x0c,0x60,0x86,0xe2, -0x06,0x00,0x57,0xe1,0xe0,0xff,0xff,0x1a,0x2d,0xff,0xff,0xeb,0xde,0xff,0xff,0xea, -0xa4,0x01,0x00,0xeb,0x00,0x50,0xa0,0xe1,0xd6,0xff,0xff,0xea,0x64,0x53,0x00,0x00, -0x94,0x00,0x00,0x00,0x30,0x48,0x2d,0xe9,0x00,0x10,0xa0,0xe3,0x00,0x40,0xa0,0xe1, -0x1c,0x00,0x80,0xe2,0x01,0x50,0xa0,0xe1,0x00,0xb0,0xa0,0xe3,0xb6,0xff,0xff,0xeb, -0x00,0xc0,0xa0,0xe3,0x50,0x00,0x84,0xe2,0x88,0xb0,0x84,0xe5,0x8c,0xc0,0x84,0xe5, -0x05,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x98,0x40,0x84,0xe5,0x9c,0x50,0x84,0xe5, -0xa0,0x50,0x84,0xe5,0xa4,0x40,0x84,0xe5,0xa8,0x50,0x84,0xe5,0xac,0x50,0x84,0xe5, -0x90,0x50,0x84,0xe5,0x94,0x50,0xc4,0xe5,0x80,0x50,0x84,0xe5,0x45,0xfe,0xff,0xeb, -0x60,0x00,0x84,0xe2,0x05,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x41,0xfe,0xff,0xeb, -0x70,0x00,0x84,0xe2,0x05,0x10,0xa0,0xe1,0x10,0x20,0xa0,0xe3,0x3d,0xfe,0xff,0xeb, -0x01,0x30,0xa0,0xe3,0x08,0x30,0x84,0xe5,0x30,0x88,0xbd,0xe8,0xf0,0x47,0x2d,0xe9, -0x01,0x70,0xa0,0xe3,0xdc,0x40,0x9f,0xe5,0x00,0x60,0xa0,0xe3,0x02,0x80,0xa0,0xe3, -0xd4,0x30,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0xd0,0x20,0x9f,0xe5,0xd0,0xa0,0x9f,0xe5, -0x03,0x30,0x94,0xe7,0x02,0x00,0x94,0xe7,0x00,0x70,0x83,0xe5,0xb6,0xfe,0xff,0xeb, -0xc0,0x30,0x9f,0xe5,0x03,0x00,0x94,0xe7,0xb3,0xfe,0xff,0xeb,0xb8,0x30,0x9f,0xe5, -0x03,0x00,0x94,0xe7,0xb0,0xfe,0xff,0xeb,0xb0,0x30,0x9f,0xe5,0x03,0x50,0x94,0xe7, -0x05,0x00,0xa0,0xe1,0xc6,0xff,0xff,0xeb,0xa4,0x10,0x9f,0xe5,0x02,0x2c,0xa0,0xe3, -0x06,0x30,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x0c,0x70,0x85,0xe5,0x01,0xc0,0x94,0xe7, -0x90,0x10,0x9f,0xe5,0x10,0x60,0x85,0xe5,0x14,0xc0,0x85,0xe5,0x01,0x10,0x94,0xe7, -0x18,0x60,0x85,0xe5,0x08,0x80,0x85,0xe5,0xb0,0xa0,0x85,0xe5,0x46,0x06,0x00,0xeb, -0x74,0x30,0x9f,0xe5,0x03,0x50,0x94,0xe7,0x05,0x00,0xa0,0xe1,0xb4,0xff,0xff,0xeb, -0x68,0x10,0x9f,0xe5,0x07,0x30,0xa0,0xe1,0x05,0x00,0xa0,0xe1,0x02,0x2b,0xa0,0xe3, -0x0c,0x60,0x85,0xe5,0x01,0x70,0x94,0xe7,0x54,0x10,0x9f,0xe5,0x10,0x60,0x85,0xe5, -0x14,0x70,0x85,0xe5,0x01,0xc0,0x94,0xe7,0x48,0x10,0x9f,0xe5,0x18,0x60,0x85,0xe5, -0x08,0x80,0x85,0xe5,0x01,0x10,0x94,0xe7,0xb0,0xa0,0x85,0xe5,0x00,0x50,0x8c,0xe5, -0xf0,0x47,0xbd,0xe8,0x30,0x06,0x00,0xea,0x0c,0x52,0x00,0x00,0x74,0x00,0x00,0x00, -0x94,0x00,0x00,0x00,0xad,0xfb,0xca,0xde,0x1c,0x00,0x00,0x00,0x38,0x00,0x00,0x00, -0x4c,0x00,0x00,0x00,0x8c,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x7c,0x00,0x00,0x00, -0x84,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x10,0x40,0x2d,0xe9, -0x92,0x02,0x00,0xeb,0x9d,0x02,0x00,0xeb,0x10,0x40,0xbd,0xe8,0xb2,0xff,0xff,0xea, -0x10,0x40,0x2d,0xe9,0x18,0x40,0x9f,0xe5,0x13,0xfe,0xff,0xeb,0x14,0x30,0x9f,0xe5, -0x04,0x40,0x8f,0xe0,0x03,0x00,0x84,0xe7,0x09,0x02,0x00,0xeb,0x10,0x40,0xbd,0xe8, -0x90,0x02,0x00,0xea,0xe0,0x50,0x00,0x00,0x0c,0x11,0x00,0x00,0x08,0x40,0x2d,0xe9, -0x24,0x01,0x00,0xeb,0xec,0xff,0xff,0xeb,0x00,0x00,0xa0,0xe3,0x08,0x80,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x56,0x34,0x12,0xef,0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x00,0x10,0xa0,0xe1, -0x04,0x00,0xa0,0xe3,0xf9,0xff,0xff,0xea,0x18,0x00,0xa0,0xe3,0x00,0x10,0x9f,0xe5, -0xf6,0xff,0xff,0xea,0x25,0x00,0x02,0x00,0x38,0x40,0x2d,0xe9,0x5c,0x40,0x9f,0xe5, -0xc3,0x07,0x00,0xeb,0x01,0x00,0x50,0xe3,0x04,0x40,0x8f,0xe0,0x0f,0x00,0x00,0x0a, -0x05,0x00,0x00,0x2a,0x48,0x50,0x9f,0xe5,0x05,0x00,0x84,0xe0,0x00,0x00,0xa0,0xe1, -0x0f,0xe0,0xa0,0xe1,0x05,0xf0,0x94,0xe7,0x38,0x80,0xbd,0xe8,0x03,0x00,0x40,0xe2, -0x04,0x00,0x50,0xe3,0xf6,0xff,0xff,0x8a,0x24,0x50,0x9f,0xe5,0x05,0x00,0x84,0xe0, -0x1a,0x09,0x00,0xeb,0x0f,0xe0,0xa0,0xe1,0x05,0xf0,0x94,0xe7,0x38,0x80,0xbd,0xe8, -0x0c,0x50,0x9f,0xe5,0x0f,0xe0,0xa0,0xe1,0x05,0xf0,0x94,0xe7,0x38,0x80,0xbd,0xe8, -0xe8,0x4f,0x00,0x00,0xd8,0x03,0x00,0x00,0x18,0xc0,0x9f,0xe5,0x08,0x40,0x2d,0xe9, -0x14,0xe0,0x9f,0xe5,0x0c,0xc0,0x8f,0xe0,0x0e,0xc0,0x8c,0xe0,0x0f,0xe0,0xa0,0xe1, -0x0c,0xf0,0x9c,0xe5,0x08,0x80,0xbd,0xe8,0x7c,0x4f,0x00,0x00,0xd8,0x03,0x00,0x00, -0x30,0x40,0x2d,0xe9,0x41,0xdf,0x4d,0xe2,0x00,0x20,0xa0,0xe1,0x01,0x30,0xa0,0xe1, -0x0d,0x00,0xa0,0xe1,0x01,0x1c,0xa0,0xe3,0x24,0x40,0x9f,0xe5,0x0d,0x50,0xa0,0xe1, -0xec,0xff,0xff,0xeb,0x1c,0x30,0x9f,0xe5,0x0d,0x00,0xa0,0xe1,0x04,0x40,0x8f,0xe0, -0x03,0x40,0x84,0xe0,0x0f,0xe0,0xa0,0xe1,0x14,0xf0,0x94,0xe5,0x41,0xdf,0x8d,0xe2, -0x30,0x80,0xbd,0xe8,0x34,0x4f,0x00,0x00,0xd8,0x03,0x00,0x00,0x0f,0x00,0x2d,0xe9, -0x04,0xe0,0x2d,0xe5,0x0c,0xd0,0x4d,0xe2,0x14,0x30,0x8d,0xe2,0x03,0x10,0xa0,0xe1, -0x10,0x00,0x9d,0xe5,0x04,0x30,0x8d,0xe5,0xe4,0xff,0xff,0xeb,0x0c,0xd0,0x8d,0xe2, -0x04,0xe0,0x9d,0xe4,0x10,0xd0,0x8d,0xe2,0x1e,0xff,0x2f,0xe1,0x10,0x30,0x9f,0xe5, -0x10,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x00,0x93,0xe5, -0x1e,0xff,0x2f,0xe1,0xdc,0x4e,0x00,0x00,0x90,0x00,0x00,0x00,0x10,0x30,0x9f,0xe5, -0x10,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x04,0x00,0x93,0xe5, -0x1e,0xff,0x2f,0xe1,0xbc,0x4e,0x00,0x00,0x90,0x00,0x00,0x00,0x54,0x30,0x9f,0xe5, -0x54,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x30,0x93,0xe5, -0x03,0x00,0x53,0xe3,0x07,0x00,0x00,0x0a,0x01,0x21,0xa0,0xe3,0x02,0x31,0xa0,0xe3, -0x08,0x20,0x80,0xe5,0x34,0x20,0x9f,0xe5,0x00,0x30,0x80,0xe5,0x0c,0x30,0x80,0xe5, -0x04,0x20,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x01,0x31,0xa0,0xe3,0x00,0x20,0xa0,0xe3, -0x04,0x30,0x80,0xe5,0x08,0x30,0x80,0xe5,0x10,0x30,0x9f,0xe5,0x00,0x20,0x80,0xe5, -0x0c,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x9c,0x4e,0x00,0x00,0x44,0x00,0x00,0x00, -0x00,0x00,0xf0,0xff,0x24,0x30,0x9f,0xe5,0x24,0x20,0x9f,0xe5,0x10,0x40,0x2d,0xe9, -0x03,0x30,0x8f,0xe0,0x02,0x40,0x93,0xe7,0x03,0x30,0xa0,0xe3,0x00,0x30,0x84,0xe5, -0x94,0x05,0x00,0xeb,0x01,0x30,0xa0,0xe3,0x00,0x30,0x84,0xe5,0x10,0x80,0xbd,0xe8, -0x30,0x4e,0x00,0x00,0x74,0x00,0x00,0x00,0x5c,0x30,0x9f,0xe5,0x10,0x40,0x2d,0xe9, -0x58,0x40,0x9f,0xe5,0x00,0x30,0x93,0xe5,0x04,0x40,0x8f,0xe0,0x02,0x00,0x13,0xe3, -0x10,0x80,0xbd,0x08,0x48,0x30,0x9f,0xe5,0x08,0x20,0x93,0xe5,0x03,0x21,0xc2,0xe3, -0x08,0x20,0x83,0xe5,0x01,0x21,0xa0,0xe3,0x0c,0x20,0x83,0xe5,0xf0,0xfd,0xff,0xeb, -0x30,0x30,0x9f,0xe5,0x03,0x30,0x94,0xe7,0x00,0x30,0x93,0xe5,0x02,0x00,0x53,0xe3, -0x03,0x00,0x00,0x0a,0x20,0x20,0x9f,0xe5,0x14,0x30,0x9f,0xe5,0x08,0x20,0x83,0xe5, -0x10,0x80,0xbd,0xe8,0xda,0xff,0xff,0xeb,0xf9,0xff,0xff,0xea,0x00,0x40,0x00,0x60, -0xf8,0x4d,0x00,0x00,0x00,0x50,0x00,0x60,0x74,0x00,0x00,0x00,0x88,0x13,0x00,0xc0, -0x0c,0x30,0x9f,0xe5,0x0c,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x00,0x93,0xe7, -0x1e,0xff,0x2f,0xe1,0x88,0x4d,0x00,0x00,0x18,0x11,0x00,0x00,0x00,0x00,0x50,0xe3, -0x1e,0xff,0x2f,0x01,0x2c,0x10,0x9f,0xe5,0x05,0x20,0xa0,0xe3,0x10,0x30,0xa0,0xe3, -0x00,0xc0,0xa0,0xe3,0x00,0x00,0x11,0xe1,0x30,0x03,0xa0,0x01,0x03,0xc0,0x8c,0x00, -0xa3,0x30,0xa0,0xe1,0x01,0x20,0x52,0xe2,0x31,0x13,0xa0,0xe1,0xf8,0xff,0xff,0x1a, -0x01,0x00,0x8c,0xe2,0x1e,0xff,0x2f,0xe1,0xff,0xff,0x00,0x00,0xf0,0x40,0x2d,0xe9, -0x0c,0xd0,0x4d,0xe2,0xe4,0x60,0x9f,0xe5,0xe4,0x70,0x9f,0xe5,0x06,0x60,0x8f,0xe0, -0x07,0x30,0x96,0xe7,0x00,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0x2f,0x00,0x00,0x0a, -0xd0,0x50,0x9f,0xe5,0x00,0x40,0xa0,0xe3,0x05,0x50,0x86,0xe0,0x04,0x50,0x45,0xe2, -0x04,0x00,0x00,0xea,0x07,0x30,0x96,0xe7,0x01,0x40,0x84,0xe2,0x00,0x30,0x93,0xe5, -0x04,0x00,0x53,0xe1,0x25,0x00,0x00,0x9a,0x04,0x30,0xb5,0xe5,0x00,0x30,0x93,0xe5, -0x04,0x30,0x8d,0xe5,0x04,0x00,0x9d,0xe5,0xd7,0xff,0xff,0xeb,0x00,0x00,0x50,0xe3, -0xf3,0xff,0xff,0x0a,0x84,0x02,0x90,0xe0,0x1c,0x00,0x00,0x0a,0x88,0xc0,0x9f,0xe5, -0x01,0x00,0x40,0xe2,0x0c,0x20,0x86,0xe0,0x06,0x30,0xd2,0xe5,0x03,0x00,0x50,0xe1, -0x00,0x30,0xa0,0x03,0x08,0x00,0x00,0x0a,0x01,0x30,0xa0,0xe3,0x02,0x00,0x00,0xea, -0x01,0x30,0x83,0xe2,0x20,0x00,0x53,0xe3,0x12,0x00,0x00,0x0a,0x1a,0x10,0xd2,0xe5, -0x14,0x20,0x82,0xe2,0x01,0x00,0x50,0xe1,0xf8,0xff,0xff,0x1a,0x03,0x31,0x83,0xe0, -0x0c,0xc0,0x86,0xe0,0x44,0x40,0x9f,0xe5,0x01,0x20,0xa0,0xe3,0x03,0xc1,0x8c,0xe0, -0x0c,0x30,0x9c,0xe5,0x04,0x20,0x86,0xe7,0x00,0x00,0x53,0xe3,0x10,0x00,0x9c,0x15, -0x0f,0xe0,0xa0,0x11,0x13,0xff,0x2f,0x11,0x00,0x30,0xa0,0xe3,0x04,0x30,0x86,0xe7, -0x0c,0xd0,0x8d,0xe2,0xf0,0x80,0xbd,0xe8,0x00,0x30,0xe0,0xe3,0xee,0xff,0xff,0xea, -0x24,0x4d,0x00,0x00,0x0c,0x00,0x00,0x00,0x2c,0xf3,0xff,0xff,0x78,0x04,0x00,0x00, -0x18,0x11,0x00,0x00,0x8b,0x04,0x00,0xea,0x80,0x04,0x00,0xea,0x84,0x04,0x00,0xea, -0x08,0x20,0x9f,0xe5,0x08,0x30,0x9f,0xe5,0x04,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0x08,0x00,0x80,0x00,0x70,0x00,0x60,0xd3,0x04,0x00,0xea,0xcc,0x30,0x9f,0xe5, -0x00,0x20,0xa0,0xe1,0xc8,0x00,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x00,0x00,0x93,0xe7, -0x00,0x00,0xd0,0xe5,0x00,0x00,0x50,0xe3,0x1b,0x00,0x00,0x1a,0xb4,0x00,0x9f,0xe5, -0x00,0x30,0x93,0xe7,0x00,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3,0x16,0x00,0x00,0x1a, -0xa4,0x30,0x9f,0xe5,0x02,0xc1,0xa0,0xe3,0x03,0x00,0xa0,0xe1,0x58,0xc0,0x83,0xe5, -0x5c,0x30,0x90,0xe5,0x00,0x00,0x53,0xe3,0xfc,0xff,0xff,0xba,0x03,0x38,0xa0,0xe1, -0x88,0x00,0x9f,0xe5,0x23,0x38,0xa0,0xe1,0x00,0x00,0x53,0xe1,0x0f,0x00,0x00,0x9a, -0x19,0x0e,0x53,0xe3,0x08,0x00,0x00,0x9a,0x74,0x00,0x9f,0xe5,0x00,0x00,0x53,0xe1, -0x10,0x00,0x00,0x8a,0x04,0x30,0xa0,0xe3,0x01,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5, -0x5f,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe3, -0x0c,0x30,0xa0,0xe3,0x00,0x00,0x82,0xe5,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0x30,0xa0,0xe3,0x02,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5,0x0b,0x30,0xa0,0xe3, -0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x30,0xa0,0xe3,0x03,0x00,0xa0,0xe3, -0x00,0x30,0x82,0xe5,0x19,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0xf8,0x4b,0x00,0x00,0x60,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x60,0x00,0x60, -0x72,0x01,0x00,0x00,0x4d,0x02,0x00,0x00,0x8c,0x30,0x9f,0xe5,0x00,0x00,0xa0,0xe3, -0x88,0x20,0x9f,0xe5,0x88,0x10,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x04,0xe0,0x2d,0xe5, -0x02,0x20,0x93,0xe7,0x0c,0xd0,0x4d,0xe2,0x01,0x30,0x83,0xe0,0x00,0x10,0xa0,0xe3, -0x03,0x00,0x83,0xe8,0x00,0x30,0x92,0xe5,0x03,0x00,0x53,0xe3,0x12,0x00,0x00,0x8a, -0x04,0x00,0x8d,0xe2,0x0d,0x10,0xa0,0xe1,0xb3,0xff,0xff,0xeb,0x54,0x20,0x9f,0xe5, -0x20,0x10,0xa0,0xe3,0x50,0x30,0x9f,0xe5,0x20,0x13,0x82,0xe5,0x04,0x20,0x9d,0xe5, -0x00,0x10,0xdd,0xe5,0x02,0x2c,0xa0,0xe1,0x22,0x28,0x81,0xe1,0x14,0x20,0x83,0xe5, -0x38,0x20,0x9f,0xe5,0x08,0x20,0x83,0xe5,0x4c,0x20,0x93,0xe5,0x10,0x20,0x82,0xe3, -0x4c,0x20,0x83,0xe5,0x0c,0xd0,0x8d,0xe2,0x00,0x80,0xbd,0xe8,0x04,0x00,0x8d,0xe2, -0x0d,0x10,0xa0,0xe1,0x5d,0x03,0x00,0xeb,0xeb,0xff,0xff,0xea,0x08,0x4b,0x00,0x00, -0x44,0x00,0x00,0x00,0x10,0x11,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x50,0x00,0x60, -0x88,0x13,0x00,0xc0,0x24,0x30,0x9f,0xe5,0x04,0x30,0x93,0xe5,0x01,0x00,0x13,0xe3, -0x1c,0x30,0x9f,0x15,0x00,0x20,0xe0,0x13,0x28,0x20,0x83,0x15,0x28,0x21,0x83,0x15, -0x02,0x20,0xa0,0xe3,0x08,0x30,0x9f,0xe5,0x24,0x20,0x83,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0x60,0x00,0x60,0x00,0x40,0x00,0x60,0x50,0x30,0x9f,0xe5,0x50,0x20,0x9f,0xe5, -0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x30,0x93,0xe5,0x03,0x00,0x53,0xe3, -0x00,0x00,0x00,0x0a,0x97,0x01,0x00,0xea,0x38,0x10,0x9f,0xe5,0x00,0x00,0xa0,0xe3, -0x34,0x20,0x9f,0xe5,0x01,0x39,0xa0,0xe3,0x40,0x00,0x81,0xe5,0x3f,0x0d,0xa0,0xe3, -0x44,0x00,0x81,0xe5,0x00,0x10,0x92,0xe5,0x07,0x10,0x81,0xe3,0x00,0x10,0x82,0xe5, -0x10,0x20,0xd3,0xe4,0x06,0x0a,0x53,0xe3,0xfc,0xff,0xff,0x1a,0x1e,0xff,0x2f,0xe1, -0x30,0x4a,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0xf0,0x00,0xf0,0x00,0xc0,0x00,0x60, -0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x5c,0x30,0x9f,0xe5,0x5c,0x20,0x9f,0xe5, -0x03,0x30,0x8f,0xe0,0x02,0x30,0x83,0xe0,0x06,0x10,0xd3,0xe5,0x00,0x00,0x51,0xe1, -0x0f,0x00,0x00,0x0a,0x01,0x20,0xa0,0xe3,0x02,0xc0,0xa0,0xe1,0x02,0x00,0x00,0xea, -0x20,0x00,0x52,0xe3,0x02,0xc0,0xa0,0xe1,0x07,0x00,0x00,0x0a,0x1a,0x10,0xd3,0xe5, -0x01,0x20,0x82,0xe2,0x14,0x30,0x83,0xe2,0x00,0x00,0x51,0xe1,0xf7,0xff,0xff,0x1a, -0x02,0x01,0x8c,0xe2,0x01,0x04,0x80,0xe0,0x1e,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x02,0x01,0xa0,0xe3,0xf9,0xff,0xff,0xea,0xc0,0x49,0x00,0x00, -0x78,0x04,0x00,0x00,0xf0,0x47,0x2d,0xe9,0x01,0x40,0xa0,0xe1,0x02,0xa0,0xa0,0xe1, -0x8c,0x50,0x9f,0xe5,0xdf,0xff,0xff,0xeb,0x00,0x70,0xa0,0xe1,0x05,0x50,0x8f,0xe0, -0x27,0x74,0xa0,0xe1,0xd9,0xff,0xff,0xeb,0xff,0x80,0x07,0xe2,0x01,0x30,0xa0,0xe3, -0x1f,0x70,0x07,0xe2,0x00,0x60,0xa0,0xe1,0x13,0x77,0xa0,0xe1,0xa8,0x82,0xa0,0xe1, -0xbe,0x03,0x00,0xeb,0x00,0x00,0x54,0xe3,0x0b,0x00,0x00,0x0a,0x54,0x30,0x9f,0xe5, -0x06,0x61,0x86,0xe0,0x50,0x20,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x08,0x31,0x93,0xe7, -0x02,0x50,0x85,0xe0,0x06,0x61,0x85,0xe0,0x0c,0x40,0x86,0xe5,0x10,0xa0,0x86,0xe5, -0x00,0x70,0x83,0xe5,0xf0,0x47,0xbd,0xe8,0xb5,0x03,0x00,0xea,0x2c,0x30,0x9f,0xe5, -0x06,0x61,0x86,0xe0,0x20,0x20,0x9f,0xe5,0x03,0x30,0x85,0xe0,0x08,0x31,0x93,0xe7, -0x02,0x50,0x85,0xe0,0x06,0x61,0x85,0xe0,0x0c,0x40,0x86,0xe5,0x00,0x70,0x83,0xe5, -0xf3,0xff,0xff,0xea,0x44,0x49,0x00,0x00,0x54,0xf3,0xff,0xff,0x78,0x04,0x00,0x00, -0x40,0xf3,0xff,0xff,0xf0,0x41,0x2d,0xe9,0xc0,0x41,0x9f,0xe5,0xc0,0x21,0x9f,0xe5, -0xc0,0x31,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0xbc,0x71,0x9f,0xe5,0x02,0x10,0x94,0xe7, -0x03,0x30,0x94,0xe7,0xb4,0x61,0x9f,0xe5,0xb4,0x51,0x9f,0xe5,0x04,0x20,0x43,0xe2, -0x01,0x30,0x63,0xe0,0x23,0x01,0x82,0xe0,0x87,0x03,0x00,0xeb,0x07,0x32,0xa0,0xe3, -0x07,0xc0,0x94,0xe7,0x04,0xe8,0x93,0xe5,0x00,0x30,0xa0,0xe3,0x06,0x00,0x94,0xe7, -0x05,0x10,0x94,0xe7,0x00,0x30,0xcc,0xe5,0x2e,0x24,0xa0,0xe1,0x2e,0x82,0xa0,0xe1, -0x00,0x30,0xc0,0xe5,0xff,0x20,0x02,0xe2,0x00,0x30,0xc1,0xe5,0x30,0x00,0x52,0xe3, -0x0f,0x80,0x08,0xe2,0x47,0x00,0x00,0x0a,0x35,0x00,0x52,0xe3,0x3c,0x00,0x00,0x0a, -0x20,0x00,0x52,0xe3,0x25,0x00,0x00,0x0a,0x58,0x21,0x9f,0xe5,0x02,0x30,0x94,0xe7, -0x00,0x30,0x93,0xe5,0x00,0x00,0x53,0xe3,0x02,0x00,0x94,0x17,0x28,0x00,0x00,0x1a, -0x07,0x32,0xa0,0xe3,0x40,0x21,0x9f,0xe5,0x60,0x38,0x93,0xe5,0x00,0x00,0x58,0xe3, -0x38,0x01,0x9f,0xe5,0x02,0x10,0x94,0xe7,0x03,0x28,0xa0,0xe1,0x00,0x00,0x94,0xe7, -0x23,0x38,0xa0,0xe1,0x22,0x28,0xa0,0xe1,0x00,0x30,0x80,0xe5,0x00,0x20,0x81,0xe5, -0x08,0x00,0x00,0x1a,0x00,0x00,0x52,0xe3,0x38,0x00,0x00,0x0a,0x0f,0x08,0x1e,0xe3, -0x07,0x30,0x94,0x07,0x01,0x20,0xa0,0x03,0x06,0x30,0x94,0x17,0x01,0x20,0xa0,0x13, -0x00,0x20,0xc3,0x05,0x00,0x20,0xc3,0x15,0xf4,0x30,0x9f,0xe5,0x03,0x00,0x94,0xe7, -0x41,0xfe,0xff,0xeb,0x4e,0xff,0xff,0xeb,0x5a,0xff,0xff,0xeb,0x07,0x32,0xa0,0xe3, -0x24,0x20,0x93,0xe5,0xc0,0x20,0x82,0xe3,0x24,0x20,0x83,0xe5,0xf0,0x81,0xbd,0xe8, -0xd0,0x30,0x9f,0xe5,0x03,0x00,0xa0,0xe3,0xb8,0x20,0x9f,0xe5,0x03,0x10,0x94,0xe7, -0x02,0x30,0x94,0xe7,0x00,0x00,0x81,0xe5,0x04,0x10,0xa0,0xe3,0x03,0x00,0xa0,0xe1, -0x00,0x10,0x83,0xe5,0xb0,0x20,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0x00,0xc0,0xe0,0xe3, -0x02,0x20,0x84,0xe0,0x04,0x20,0x42,0xe2,0x04,0x10,0xb2,0xe5,0x01,0x30,0x83,0xe2, -0x00,0xc0,0x81,0xe5,0x00,0x10,0x90,0xe5,0x03,0x00,0x51,0xe1,0xf9,0xff,0xff,0x8a, -0xca,0xff,0xff,0xea,0x7c,0x10,0x9f,0xe5,0x05,0x30,0xa0,0xe3,0x64,0x20,0x9f,0xe5, -0x01,0x00,0x94,0xe7,0x02,0x10,0x94,0xe7,0x00,0x30,0x80,0xe5,0x00,0x30,0x81,0xe5, -0x01,0x00,0xa0,0xe1,0xea,0xff,0xff,0xea,0x58,0x30,0x9f,0xe5,0x04,0x00,0xa0,0xe3, -0x40,0x20,0x9f,0xe5,0x03,0x10,0x94,0xe7,0x02,0x30,0x94,0xe7,0x00,0x00,0x81,0xe5, -0x05,0x10,0xa0,0xe3,0x00,0x10,0x83,0xe5,0x03,0x00,0xa0,0xe1,0xe0,0xff,0xff,0xea, -0x05,0x30,0x94,0xe7,0x01,0x20,0xa0,0xe3,0x00,0x20,0xc3,0xe5,0xc9,0xff,0xff,0xea, -0x9c,0x48,0x00,0x00,0x5c,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x24,0x00,0x00,0x00, -0x60,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x54,0x00,0x00,0x00, -0x28,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x40,0xf3,0xff,0xff, -0x14,0x30,0x9f,0xe5,0x01,0x00,0xa0,0xe3,0x10,0x10,0x9f,0xe5,0x00,0x20,0xa0,0xe3, -0x03,0x30,0x8f,0xe0,0x01,0x10,0x93,0xe7,0x4d,0xff,0xff,0xea,0xa0,0x46,0x00,0x00, -0x78,0x00,0x00,0x00,0xdb,0xfe,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1, -0x44,0x10,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0x40,0x00,0x9f,0xe5,0x40,0x30,0x9f,0xe5, -0x01,0x10,0x8f,0xe0,0x10,0x40,0x2d,0xe9,0x00,0xc0,0x91,0xe7,0x03,0x30,0x91,0xe7, -0x30,0x00,0x9f,0xe5,0x0b,0x30,0x83,0xe2,0x00,0x40,0x91,0xe7,0x07,0x30,0xc3,0xe3, -0x0c,0xc0,0x63,0xe0,0x03,0x00,0xa0,0xe1,0x0c,0x10,0xa0,0xe1,0x08,0x10,0x84,0xe8, -0xba,0x07,0x00,0xeb,0x08,0x00,0x84,0xe5,0x10,0x80,0xbd,0xe8,0x70,0x46,0x00,0x00, -0x14,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0xf8,0x40,0x2d,0xe9, -0x00,0x00,0x51,0xe3,0x54,0x40,0x9f,0xe5,0x01,0x70,0xa0,0x11,0x04,0x70,0xa0,0x03, -0x02,0x00,0x53,0xe3,0x00,0x60,0xa0,0xe1,0x04,0x40,0x8f,0xe0,0x00,0x40,0xa0,0x13, -0x01,0x00,0x00,0x0a,0x04,0x00,0xa0,0xe1,0xf8,0x80,0xbd,0xe8,0xf3,0x02,0x00,0xeb, -0x2c,0x30,0x9f,0xe5,0x00,0x50,0xa0,0xe1,0x07,0x10,0xa0,0xe1,0x06,0x20,0xa0,0xe1, -0x03,0x30,0x94,0xe7,0x08,0x00,0x93,0xe5,0x42,0x0c,0x00,0xeb,0x00,0x40,0xa0,0xe1, -0x05,0x00,0xa0,0xe1,0xee,0x02,0x00,0xeb,0x04,0x00,0xa0,0xe1,0xf8,0x80,0xbd,0xe8, -0x08,0x46,0x00,0x00,0x3c,0x00,0x00,0x00,0x50,0x30,0x9f,0xe5,0x70,0x40,0x2d,0xe9, -0x00,0x60,0x50,0xe2,0x03,0x30,0x8f,0xe0,0x70,0x80,0xbd,0x08,0x40,0x20,0x9f,0xe5, -0x02,0x40,0x93,0xe7,0x00,0x30,0x94,0xe5,0x03,0x00,0x56,0xe1,0x70,0x80,0xbd,0x38, -0x04,0x20,0x94,0xe5,0x02,0x30,0x83,0xe0,0x03,0x00,0x56,0xe1,0x70,0x80,0xbd,0x88, -0xd6,0x02,0x00,0xeb,0x06,0x10,0xa0,0xe1,0x00,0x50,0xa0,0xe1,0x08,0x00,0x94,0xe5, -0x8a,0x0a,0x00,0xeb,0x05,0x00,0xa0,0xe1,0x70,0x40,0xbd,0xe8,0xd4,0x02,0x00,0xea, -0xac,0x45,0x00,0x00,0x3c,0x00,0x00,0x00,0x5c,0x20,0x9f,0xe5,0x5c,0x00,0x9f,0xe5, -0x5c,0x10,0x9f,0xe5,0x02,0x20,0x8f,0xe0,0x10,0x08,0x2d,0xe9,0x00,0x30,0x82,0xe0, -0x10,0x10,0x91,0xe5,0x18,0x00,0x93,0xe8,0x03,0x00,0x51,0xe1,0x03,0x00,0x00,0x2a, -0x00,0xb0,0xa0,0xe3,0x01,0xc0,0xa0,0xe3,0x0b,0x30,0x93,0xe0,0x0c,0x40,0xa4,0xe0, -0x00,0xb0,0xa0,0xe3,0x00,0xc0,0xe0,0xe3,0x0b,0x30,0x03,0xe0,0x00,0x20,0x82,0xe0, -0x01,0x30,0x83,0xe1,0x0c,0x40,0x04,0xe0,0x18,0x00,0x82,0xe8,0x03,0x00,0xa0,0xe1, -0x04,0x10,0xa0,0xe1,0x10,0x08,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x4c,0x45,0x00,0x00, -0x10,0x11,0x00,0x00,0x00,0x50,0x00,0x60,0x4c,0x30,0x9f,0xe5,0x4c,0x20,0x9f,0xe5, -0x10,0x40,0x2d,0xe9,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x30,0x93,0xe5, -0x03,0x00,0x53,0xe3,0x01,0x00,0x00,0x0a,0x10,0x40,0xbd,0xe8,0x7d,0x00,0x00,0xea, -0xa6,0x02,0x00,0xeb,0x28,0x30,0x9f,0xe5,0x28,0x20,0x9f,0xe5,0x44,0x10,0x93,0xe5, -0x06,0x10,0x81,0xe3,0x44,0x10,0x83,0xe5,0x00,0x30,0x92,0xe5,0x02,0x09,0x13,0xe3, -0xfc,0xff,0xff,0x1a,0x10,0x40,0xbd,0xe8,0xa1,0x02,0x00,0xea,0xdc,0x44,0x00,0x00, -0x44,0x00,0x00,0x00,0x00,0xf0,0x00,0xf0,0x00,0xc0,0x00,0x60,0xe5,0xff,0xff,0xea, -0xfd,0xff,0xff,0xea,0x88,0xc0,0x9f,0xe5,0xf0,0x41,0x2d,0xe9,0x00,0x40,0xa0,0xe1, -0x80,0x50,0x9f,0xe5,0x02,0x70,0xa0,0xe1,0x0c,0xc0,0x8f,0xe0,0x18,0x60,0x9d,0xe5, -0x05,0x50,0x9c,0xe7,0x00,0xc0,0x95,0xe5,0x03,0x00,0x5c,0xe3,0x02,0x00,0x00,0x0a, -0x18,0x60,0x8d,0xe5,0xf0,0x41,0xbd,0xe8,0x85,0x00,0x00,0xea,0x00,0x00,0x52,0xe3, -0x02,0x00,0x00,0x0a,0x00,0x40,0x86,0xe5,0x00,0x00,0xa0,0xe3,0xf0,0x81,0xbd,0xe8, -0x51,0xfd,0xff,0xeb,0x00,0x80,0xa0,0xe1,0x57,0xfd,0xff,0xeb,0x00,0x70,0xa0,0xe1, -0x4d,0xfd,0xff,0xeb,0x04,0x30,0x68,0xe0,0x07,0x00,0x60,0xe0,0x00,0x00,0x53,0xe1, -0xf3,0xff,0xff,0x2a,0x00,0x30,0x95,0xe5,0x00,0x00,0xa0,0xe3,0x03,0x00,0x53,0xe3, -0x02,0x31,0xa0,0x03,0x00,0x30,0xa0,0x13,0x03,0x40,0x84,0xe0,0x00,0x40,0x86,0xe5, -0xf0,0x81,0xbd,0xe8,0x68,0x44,0x00,0x00,0x44,0x00,0x00,0x00,0x1c,0x30,0x9f,0xe5, -0x1c,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7,0x00,0x30,0x93,0xe5, -0x04,0x30,0x43,0xe2,0x01,0x00,0x53,0xe3,0x1e,0xff,0x2f,0x81,0xdc,0x00,0x00,0xea, -0xdc,0x43,0x00,0x00,0x44,0x00,0x00,0x00,0xf8,0x45,0x2d,0xe9,0x01,0x50,0xa0,0xe3, -0xc4,0x40,0x9f,0xe5,0x00,0xa0,0xe0,0xe3,0x02,0x70,0xa0,0xe3,0x05,0x80,0xa0,0xe1, -0xb8,0x00,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x00,0x00,0x84,0xe0,0x9c,0xfa,0xff,0xeb, -0xac,0xc0,0x9f,0xe5,0x00,0x20,0xa0,0xe3,0xa8,0x30,0x9f,0xe5,0x02,0x00,0xa0,0xe1, -0x0c,0x10,0xa0,0xe1,0xb0,0x50,0x8c,0xe5,0x0e,0x50,0xa0,0xe3,0xa0,0x50,0x8c,0xe5, -0x18,0xc2,0xa0,0xe1,0x01,0x20,0x82,0xe2,0x20,0x00,0x52,0xe3,0x00,0xa0,0x83,0xe5, -0x01,0x60,0xa0,0xe3,0x04,0x00,0x83,0xe5,0x74,0x50,0x9f,0xe5,0x08,0x00,0x83,0xe5, -0x10,0x30,0x83,0xe2,0xa4,0xc0,0x81,0xe5,0xb0,0x70,0x81,0xe5,0xf3,0xff,0xff,0x1a, -0x64,0x30,0x9f,0xe5,0x05,0x10,0xa0,0xe1,0x03,0x20,0x94,0xe7,0x5c,0x30,0x9f,0xe5, -0x00,0x24,0x85,0xe5,0x03,0x30,0x94,0xe7,0x04,0x34,0x85,0xe5,0x0f,0x30,0xa0,0xe3, -0x08,0x34,0x85,0xe5,0x02,0x30,0xa0,0xe3,0xa4,0x60,0x85,0xe5,0xb0,0x30,0x85,0xe5, -0xf1,0x3e,0x83,0xe2,0x44,0x60,0x85,0xe5,0x28,0x30,0x85,0xe5,0x48,0x30,0x91,0xe5, -0x1c,0x20,0x9f,0xe5,0x01,0x00,0x13,0xe3,0xfb,0xff,0xff,0x0a,0x44,0x30,0x82,0xe5, -0x1c,0x30,0x9f,0xe5,0x00,0x30,0x82,0xe5,0xf8,0x85,0xbd,0xe8,0x9c,0x43,0x00,0x00, -0x1c,0x11,0x00,0x00,0x00,0x00,0x04,0x50,0x00,0x04,0x04,0x50,0x98,0x00,0x00,0x00, -0x5c,0x00,0x00,0x00,0x01,0x40,0x00,0x00,0x70,0x40,0x2d,0xe9,0x70,0x40,0x9f,0xe5, -0x70,0x50,0x9f,0xe5,0x04,0x40,0x8f,0xe0,0x05,0x00,0x94,0xe7,0x68,0xfa,0xff,0xeb, -0x64,0x20,0x9f,0xe5,0x01,0xc0,0xa0,0xe3,0x60,0x10,0x9f,0xe5,0x60,0x30,0x9f,0xe5, -0x02,0x00,0x94,0xe7,0x01,0x60,0x94,0xe7,0x58,0x20,0x9f,0xe5,0x03,0x10,0xa0,0xe1, -0x00,0xc0,0x83,0xe5,0x44,0xc0,0x83,0xe5,0x00,0x20,0x86,0xe5,0x28,0x20,0x83,0xe5, -0x48,0x30,0x91,0xe5,0x38,0x20,0x9f,0xe5,0x01,0x00,0x13,0xe3,0x00,0x30,0x80,0xe5, -0xfa,0xff,0xff,0x0a,0x05,0x00,0x94,0xe7,0x44,0x30,0x82,0xe5,0x28,0x30,0x9f,0xe5, -0x00,0x30,0x82,0xe5,0x24,0x30,0x9f,0xe5,0x00,0x30,0x82,0xe5,0x70,0x40,0xbd,0xe8, -0x59,0xfa,0xff,0xea,0xbc,0x42,0x00,0x00,0x1c,0x11,0x00,0x00,0x2c,0x00,0x00,0x00, -0x9c,0x00,0x00,0x00,0x00,0x00,0x04,0x50,0x13,0x0f,0x00,0x00,0x01,0x80,0x00,0x00, -0x01,0x40,0x00,0x00,0x01,0x00,0x52,0xe3,0x00,0x20,0xa0,0x13,0x01,0x20,0xa0,0x03, -0x1f,0x00,0x51,0xe3,0xf8,0x4f,0x2d,0xe9,0x00,0x20,0xa0,0x93,0xa0,0x51,0x9f,0xe5, -0x00,0x00,0x52,0xe3,0x00,0x60,0xa0,0xe1,0x05,0x50,0x8f,0xe0,0x3b,0x00,0x00,0x0a, -0x00,0x30,0x81,0xe0,0x1f,0x40,0x80,0xe2,0x20,0x70,0x43,0xe2,0x1f,0x40,0xc4,0xe3, -0x1f,0x70,0xc7,0xe3,0x07,0x00,0x54,0xe1,0x34,0x00,0x00,0x8a,0x01,0x01,0x53,0xe3, -0x00,0x20,0xa0,0x93,0x01,0x20,0xa0,0x83,0x00,0x00,0x50,0xe3,0x00,0x20,0xa0,0xb3, -0x00,0x00,0x52,0xe3,0x4f,0x00,0x00,0x1a,0x58,0x81,0x9f,0xe5,0x20,0x90,0x87,0xe2, -0x08,0x00,0x95,0xe7,0x2a,0xfa,0xff,0xeb,0x4c,0x31,0x9f,0xe5,0x00,0x10,0xe0,0xe3, -0x00,0x20,0xa0,0xe3,0x00,0xc0,0x93,0xe5,0x02,0xa2,0xa0,0xe1,0x04,0x00,0x93,0xe5, -0x08,0xb0,0x93,0xe5,0x10,0x30,0x83,0xe2,0x09,0x00,0x5c,0xe1,0x20,0xe0,0x80,0xe2, -0x22,0x00,0x00,0x0a,0x0e,0x00,0x54,0xe1,0x2f,0x00,0x00,0x0a,0x00,0x00,0x5c,0xe1, -0x00,0x00,0xa0,0x93,0x01,0x00,0xa0,0x83,0x01,0x00,0x71,0xe3,0x00,0x00,0xa0,0x13, -0x00,0x00,0x50,0xe3,0x02,0x10,0xa0,0x11,0x01,0x20,0x82,0xe2,0x20,0x00,0x52,0xe3, -0xeb,0xff,0xff,0x1a,0x01,0x00,0x71,0xe3,0x0e,0x00,0x00,0x0a,0xec,0x30,0x9f,0xe5, -0x01,0x00,0xa0,0xe3,0xe8,0x20,0x9f,0xe5,0x10,0x01,0xa0,0xe1,0x0f,0xc0,0xa0,0xe3, -0x03,0x30,0x81,0xe0,0x03,0x32,0xa0,0xe1,0x00,0x40,0x83,0xe5,0xd4,0x30,0x9f,0xe5, -0x01,0x72,0x83,0xe7,0x04,0x30,0x83,0xe2,0x01,0xc2,0x83,0xe7,0x02,0x30,0xa0,0xe3, -0xa4,0x00,0x82,0xe5,0xb0,0x30,0x82,0xe5,0x08,0x00,0x95,0xe7,0x0a,0xfa,0xff,0xeb, -0x28,0x30,0x9d,0xe5,0x00,0x00,0xa0,0xe3,0x00,0x60,0x83,0xe5,0xf8,0x8f,0xbd,0xe8, -0x98,0x30,0x9f,0xe5,0x01,0xc0,0xa0,0xe3,0x94,0x10,0x9f,0xe5,0x1c,0xc2,0xa0,0xe1, -0x03,0x30,0x82,0xe0,0x03,0x32,0xa0,0xe1,0x00,0x40,0x83,0xe5,0x84,0x30,0x9f,0xe5, -0x03,0x00,0x8a,0xe7,0x04,0x30,0x83,0xe2,0x03,0xb0,0x8a,0xe7,0x02,0x30,0xa0,0xe3, -0xa4,0xc0,0x81,0xe5,0xb0,0x30,0x81,0xe5,0xea,0xff,0xff,0xea,0x5c,0x30,0x9f,0xe5, -0x01,0x00,0xa0,0xe3,0x58,0x10,0x9f,0xe5,0x10,0x02,0xa0,0xe1,0x03,0x30,0x82,0xe0, -0x03,0x32,0xa0,0xe1,0x00,0xc0,0x83,0xe5,0x48,0x30,0x9f,0xe5,0x03,0x70,0x8a,0xe7, -0x04,0x30,0x83,0xe2,0x03,0xb0,0x8a,0xe7,0x02,0x30,0xa0,0xe3,0xa4,0x00,0x81,0xe5, -0xb0,0x30,0x81,0xe5,0xdb,0xff,0xff,0xea,0x00,0x20,0xa0,0xe1,0x28,0x10,0x9f,0xe5, -0x28,0x00,0x9f,0xe5,0x01,0x10,0x85,0xe0,0x00,0x00,0x85,0xe0,0x56,0xfc,0xff,0xeb, -0xa8,0xff,0xff,0xea,0x08,0x42,0x00,0x00,0x1c,0x11,0x00,0x00,0x00,0x08,0x04,0x50, -0x40,0x40,0x00,0x05,0x00,0x00,0x04,0x50,0x04,0x04,0x04,0x50,0x94,0xf3,0xff,0xff, -0x68,0xf3,0xff,0xff,0xf0,0x4f,0x2d,0xe9,0x01,0x50,0x80,0xe0,0x20,0x50,0x45,0xe2, -0x1f,0x00,0x80,0xe2,0x1f,0x40,0xc0,0xe3,0x1f,0x50,0xc5,0xe3,0xf0,0x62,0x9f,0xe5, -0x04,0x00,0x55,0xe1,0x1f,0x00,0x51,0x23,0x1c,0xd0,0x4d,0xe2,0x06,0x60,0x8f,0xe0, -0x01,0x00,0x00,0x8a,0x1c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0xd4,0xb2,0x9f,0xe5, -0x0b,0x00,0x96,0xe7,0xbe,0xf9,0xff,0xeb,0xcc,0x22,0x9f,0xe5,0x00,0x00,0xe0,0xe3, -0x00,0x10,0xa0,0xe3,0x0d,0x00,0x00,0xea,0x02,0x00,0x00,0x9a,0x03,0x00,0x55,0xe1, -0x18,0x00,0x00,0x0a,0x53,0x00,0x00,0x3a,0x03,0x00,0x5c,0xe1,0x00,0xc0,0xa0,0x93, -0x01,0xc0,0xa0,0x83,0x01,0x00,0x70,0xe3,0x00,0xc0,0xa0,0x13,0x00,0x00,0x5c,0xe3, -0x01,0x00,0xa0,0x11,0x01,0x10,0x81,0xe2,0x20,0x00,0x51,0xe3,0x45,0x00,0x00,0x0a, -0x00,0xc0,0x92,0xe5,0x04,0x30,0x92,0xe5,0x08,0x70,0x92,0xe5,0x10,0x20,0x82,0xe2, -0x0c,0x00,0x54,0xe1,0xeb,0xff,0xff,0x1a,0x03,0x00,0x55,0xe1,0x83,0x00,0x00,0x0a, -0xec,0xff,0xff,0x2a,0x00,0x20,0xa0,0xe3,0x20,0xc0,0x85,0xe2,0x0c,0x30,0x8d,0xe5, -0x08,0x20,0x8d,0xe5,0x03,0x00,0x00,0xea,0x20,0x30,0x44,0xe2,0x00,0x90,0xa0,0xe3, -0x0c,0x30,0x8d,0xe5,0x08,0x90,0x8d,0xe5,0x20,0x00,0x51,0xe3,0x31,0x00,0x00,0x0a, -0x05,0x00,0x54,0xe1,0x0d,0x00,0x00,0x8a,0x30,0x22,0x9f,0xe5,0x01,0x90,0xa0,0xe3, -0x03,0xa0,0xa0,0xe3,0x02,0x80,0xa0,0xe1,0x44,0x90,0x82,0xe5,0x20,0x40,0x82,0xe5, -0x28,0xa0,0x82,0xe5,0x48,0x30,0x92,0xe5,0x01,0x00,0x13,0xe3,0xfc,0xff,0xff,0x0a, -0x20,0x40,0x84,0xe2,0x44,0x30,0x88,0xe5,0x04,0x00,0x55,0xe1,0xf5,0xff,0xff,0x2a, -0xfc,0x31,0x9f,0xe5,0x01,0x80,0xa0,0xe3,0x08,0x90,0x9d,0xe5,0x18,0x41,0xa0,0xe1, -0x01,0xa0,0x90,0xe2,0x01,0xa0,0xa0,0x13,0xe0,0x21,0x9f,0xe5,0x03,0x30,0x81,0xe0, -0x04,0x40,0x8d,0xe5,0x03,0x32,0xa0,0xe1,0x0a,0x00,0x19,0xe1,0xd4,0x51,0x9f,0xe5, -0x02,0xa0,0xa0,0xe3,0x00,0xc0,0x83,0xe5,0x04,0x90,0x9d,0xe5,0x0c,0x30,0x9d,0xe5, -0xc4,0x41,0x9f,0xe5,0x01,0x32,0x85,0xe7,0x01,0x72,0x84,0xe7,0xa4,0x90,0x82,0xe5, -0xb0,0xa0,0x82,0xe5,0x0b,0x00,0x00,0x0a,0xa4,0x31,0x9f,0xe5,0x18,0x80,0xa0,0xe1, -0x10,0x10,0x9d,0xe5,0x03,0x30,0x80,0xe0,0x03,0x32,0xa0,0xe1,0x00,0x10,0x83,0xe5, -0x14,0x30,0x9d,0xe5,0x00,0x32,0x85,0xe7,0x0f,0x30,0xa0,0xe3,0x00,0x32,0x84,0xe7, -0xa4,0x80,0x82,0xe5,0xb0,0xa0,0x82,0xe5,0x0b,0x00,0x96,0xe7,0x1c,0xd0,0x8d,0xe2, -0xf0,0x4f,0xbd,0xe8,0x6c,0xf9,0xff,0xea,0x01,0x00,0x70,0xe3,0x08,0x00,0x8d,0xe5, -0x07,0x00,0x00,0x0a,0x20,0x20,0x85,0xe2,0x20,0x90,0x44,0xe2,0x01,0xa0,0xa0,0xe3, -0x10,0x20,0x8d,0xe5,0x0c,0x90,0x8d,0xe5,0x14,0x30,0x8d,0xe5,0x08,0xa0,0x8d,0xe5, -0xbc,0xff,0xff,0xea,0x01,0x00,0x81,0xe2,0x1f,0x00,0x50,0xe3,0x18,0x00,0x00,0xca, -0x38,0x21,0x9f,0xe5,0x38,0x81,0x9f,0xe5,0x02,0x20,0x81,0xe0,0x02,0x22,0xa0,0xe1, -0x00,0xa0,0x92,0xe5,0x2c,0x21,0x9f,0xe5,0x00,0x22,0x92,0xe7,0x00,0x82,0x98,0xe7, -0x0a,0x00,0x52,0xe1,0x2f,0x00,0x00,0x3a,0x1c,0x21,0x9f,0xe5,0x04,0x90,0xa0,0xe1, -0x02,0x20,0x81,0xe0,0x02,0x22,0xa0,0xe1,0x05,0x00,0x00,0xea,0x00,0x80,0x92,0xe5, -0x04,0x40,0x92,0xe5,0x08,0xa0,0x92,0xe5,0x10,0x20,0x82,0xe2,0x04,0x00,0x58,0xe1, -0x23,0x00,0x00,0x8a,0x01,0x00,0x80,0xe2,0x1f,0x00,0x50,0xe3,0xf6,0xff,0xff,0xda, -0x09,0x40,0xa0,0xe1,0x20,0x90,0x85,0xe2,0x20,0xa0,0x44,0xe2,0x10,0x90,0x8d,0xe5, -0x0c,0xa0,0x8d,0xe5,0x10,0x90,0x9d,0xe5,0x09,0x00,0x53,0xe1,0x23,0x00,0x00,0x3a, -0xa8,0x00,0x9f,0xe5,0x09,0x80,0xa0,0xe1,0x03,0x90,0xa0,0xe3,0x01,0xa0,0xa0,0xe3, -0x44,0xa0,0x80,0xe5,0x20,0x80,0x80,0xe5,0x28,0x90,0x80,0xe5,0x48,0x20,0x90,0xe5, -0x01,0x00,0x12,0xe3,0xfc,0xff,0xff,0x0a,0x20,0x80,0x88,0xe2,0x7c,0xa0,0x9f,0xe5, -0x03,0x00,0x58,0xe1,0x44,0x20,0x8a,0xe5,0xf3,0xff,0xff,0x9a,0x01,0x20,0xa0,0xe3, -0x08,0x00,0x9d,0xe5,0x14,0x30,0x8d,0xe5,0x08,0x20,0x8d,0xe5,0x85,0xff,0xff,0xea, -0x00,0x70,0xa0,0xe3,0x00,0xc0,0xe0,0xe3,0x0c,0x70,0x8d,0xe5,0x08,0x70,0x8d,0xe5, -0x80,0xff,0xff,0xea,0x09,0x40,0xa0,0xe1,0x01,0x00,0x70,0xe3,0x20,0xa0,0x85,0xe2, -0x20,0x20,0x44,0xe2,0x14,0x30,0x8d,0x15,0x01,0x30,0xa0,0x13,0x10,0xa0,0x8d,0xe5, -0x0c,0x20,0x8d,0xe5,0x08,0x30,0x8d,0x15,0xd9,0xff,0xff,0x0a,0x75,0xff,0xff,0xea, -0x01,0x90,0xa0,0xe3,0x08,0x00,0x9d,0xe5,0x14,0x30,0x8d,0xe5,0x08,0x90,0x8d,0xe5, -0x70,0xff,0xff,0xea,0x24,0x40,0x00,0x00,0x1c,0x11,0x00,0x00,0x00,0x08,0x04,0x50, -0x00,0x00,0x04,0x50,0x40,0x40,0x00,0x05,0x04,0x04,0x04,0x50,0x08,0x04,0x04,0x50, -0x81,0x40,0x00,0x05,0x08,0x08,0x04,0x50,0x04,0x08,0x04,0x50,0x82,0x40,0x00,0x05, -0x58,0x31,0x9f,0xe5,0x00,0x20,0xa0,0xe1,0x54,0x01,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x00,0x00,0x93,0xe7,0x00,0x00,0xd0,0xe5,0x00,0x00,0x50,0xe3,0x1d,0x00,0x00,0x1a, -0x40,0x01,0x9f,0xe5,0x00,0x30,0x93,0xe7,0x00,0x30,0xd3,0xe5,0x00,0x00,0x53,0xe3, -0x18,0x00,0x00,0x1a,0x30,0x31,0x9f,0xe5,0x03,0x00,0xa0,0xe1,0x50,0xc0,0x93,0xe5, -0x02,0xc1,0xa0,0xe3,0x58,0xc0,0x83,0xe5,0x5c,0x30,0x90,0xe5,0x00,0x00,0x53,0xe3, -0xfc,0xff,0xff,0xba,0x03,0x38,0xa0,0xe1,0x10,0x01,0x9f,0xe5,0x23,0x38,0xa0,0xe1, -0x00,0x00,0x53,0xe1,0x10,0x00,0x00,0x9a,0x19,0x0e,0x53,0xe3,0x09,0x00,0x00,0x9a, -0x81,0x0f,0x53,0xe3,0x12,0x00,0x00,0x9a,0xf4,0x00,0x9f,0xe5,0x00,0x00,0x53,0xe1, -0x15,0x00,0x00,0x8a,0x04,0x00,0xa0,0xe3,0x5f,0x30,0xa0,0xe3,0x00,0x00,0x82,0xe5, -0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe3,0x0c,0x30,0xa0,0xe3, -0x00,0x00,0x82,0xe5,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x30,0xa0,0xe3, -0x08,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5,0x0b,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5, -0x1e,0xff,0x2f,0xe1,0x04,0x30,0xa0,0xe3,0x01,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5, -0x53,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x94,0x00,0x9f,0xe5, -0x00,0x00,0x53,0xe1,0x05,0x00,0x00,0x8a,0x00,0x30,0xa0,0xe3,0x0c,0x00,0xa0,0xe3, -0x00,0x30,0x82,0xe5,0x19,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x74,0x00,0x9f,0xe5,0x00,0x00,0x53,0xe1,0x05,0x00,0x00,0x8a,0x04,0x30,0xa0,0xe3, -0x05,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5,0xbf,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5, -0x1e,0xff,0x2f,0xe1,0x54,0x00,0x9f,0xe5,0x00,0x00,0x53,0xe1,0x05,0x00,0x00,0x8a, -0x00,0x30,0xa0,0xe3,0x09,0x00,0xa0,0xe3,0x00,0x30,0x82,0xe5,0x2f,0x30,0xa0,0xe3, -0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0x30,0xa0,0xe3,0x0c,0x00,0xa0,0xe3, -0x00,0x30,0x82,0xe5,0x19,0x30,0xa0,0xe3,0x00,0x30,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x04,0x3d,0x00,0x00,0x60,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x60,0x00,0x60, -0x72,0x01,0x00,0x00,0x4d,0x02,0x00,0x00,0x1d,0x03,0x00,0x00,0x97,0x04,0x00,0x00, -0xbc,0x05,0x00,0x00,0x94,0xf8,0xff,0xea,0x97,0xf8,0xff,0xea,0x97,0xf8,0xff,0xea, -0x60,0x20,0x9f,0xe5,0x60,0x30,0x9f,0xe5,0x60,0x10,0x9f,0xe5,0x02,0x20,0x8f,0xe0, -0x03,0x30,0x92,0xe7,0x01,0x00,0x92,0xe7,0x00,0x20,0x63,0xe0,0x00,0xc0,0xa0,0xe1, -0x0f,0x00,0x52,0xe3,0x08,0x00,0x00,0x9a,0x00,0x20,0xa0,0xe3,0x00,0x20,0x83,0xe5, -0x04,0x20,0x83,0xe5,0x08,0x20,0x83,0xe5,0x0c,0x20,0x83,0xe5,0x10,0x30,0x83,0xe2, -0x0c,0x10,0x63,0xe0,0x0f,0x00,0x51,0xe3,0xf7,0xff,0xff,0x8a,0x03,0x00,0x50,0xe1, -0x1e,0xff,0x2f,0x91,0x00,0x20,0xa0,0xe3,0x01,0x20,0xc3,0xe4,0x03,0x00,0x50,0xe1, -0xfc,0xff,0xff,0x8a,0x1e,0xff,0x2f,0xe1,0x74,0x3b,0x00,0x00,0x30,0x00,0x00,0x00, -0x68,0x00,0x00,0x00,0x64,0x00,0x9f,0xe5,0x64,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5, -0x60,0x00,0x9f,0xe5,0x60,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5,0x5c,0x00,0x9f,0xe5, -0x54,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5,0x54,0x00,0x9f,0xe5,0x48,0x10,0x9f,0xe5, -0x00,0x10,0x80,0xe5,0x4c,0x00,0x9f,0xe5,0x4c,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5, -0x48,0x00,0x9f,0xe5,0x30,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5,0x40,0x00,0x9f,0xe5, -0x40,0x10,0x9f,0xe5,0x00,0x10,0x80,0xe5,0x10,0x00,0xa0,0xe3,0x38,0x10,0x9f,0xe5, -0x00,0x20,0x91,0xe5,0x00,0x20,0x82,0xe1,0x00,0x20,0x81,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0xf2,0x00,0x60,0x00,0x80,0x00,0x40,0x04,0xf2,0x00,0x60,0xcc,0x46,0x02,0x40, -0x0c,0xf2,0x00,0x60,0x10,0xf2,0x00,0x60,0x18,0xf2,0x00,0x60,0x88,0x46,0x02,0x40, -0x1c,0xf2,0x00,0x60,0x08,0xf2,0x00,0x60,0xd4,0x46,0x02,0x40,0x00,0xc0,0x00,0x60, -0x06,0x32,0xa0,0xe3,0x00,0x20,0x93,0xe5,0x08,0x30,0x9f,0xe5,0x03,0x00,0x52,0xe1, -0x1e,0xff,0x2f,0x01,0x98,0xdc,0xff,0xea,0x55,0x55,0x55,0x55,0x0e,0x30,0xa0,0xe1, -0xd3,0xf0,0x2f,0xe3,0x00,0xd0,0xa0,0xe1,0xd7,0xf0,0x2f,0xe3,0x00,0xd0,0xa0,0xe1, -0xdb,0xf0,0x2f,0xe3,0x00,0xd0,0xa0,0xe1,0xd2,0xf0,0x2f,0xe3,0x00,0xd0,0xa0,0xe1, -0xdf,0xf0,0x2f,0xe3,0x13,0xff,0x2f,0xe1,0x00,0x00,0x0f,0xe1,0x1e,0xff,0x2f,0xe1, -0x00,0x00,0x0f,0xe1,0x80,0x30,0x80,0xe3,0x03,0xf0,0x2f,0xe1,0x80,0x00,0x00,0xe2, -0x1e,0xff,0x2f,0xe1,0x00,0x30,0x0f,0xe1,0x80,0x30,0xc3,0xe3,0x00,0x00,0x83,0xe1, -0x00,0xf0,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0x00,0x30,0x0f,0xe1,0x80,0x30,0xc3,0xe3, -0x03,0xf0,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0xdf,0xf0,0x2f,0xe3,0xff,0xcf,0x2d,0xe9, -0xd2,0xf0,0x2f,0xe3,0x04,0x00,0x4e,0xe2,0x00,0x10,0x4f,0xe1,0x24,0x20,0x9f,0xe5, -0x00,0xe0,0x82,0xe5,0xdf,0xf0,0x2f,0xe3,0x34,0x00,0x8d,0xe5,0x02,0x10,0x2d,0xe9, -0x2e,0x00,0x00,0xeb,0x20,0xfb,0xff,0xeb,0x35,0x00,0x00,0xeb,0x02,0x10,0xbd,0xe8, -0x01,0xf0,0x2f,0xe1,0xff,0xcf,0xbd,0xe8,0x90,0xfe,0x02,0x40,0xfe,0xff,0xff,0xea, -0x1e,0xff,0x2f,0xe1,0xdf,0xf0,0x2f,0xe3,0x0f,0x50,0x2d,0xe9,0x0d,0x10,0xa0,0xe1, -0xd3,0xf0,0x2f,0xe3,0x0e,0x30,0xa0,0xe1,0x00,0x00,0x4f,0xe1,0xdf,0xf0,0x2f,0xe3, -0x09,0x00,0x2d,0xe9,0xd3,0xf0,0x2f,0xe3,0x20,0x00,0x10,0xe3,0xb2,0x00,0x5e,0x11, -0xff,0x0c,0xc0,0x13,0x04,0x00,0x1e,0x05,0xff,0x04,0xc0,0x03,0xab,0x00,0x50,0xe3, -0x0c,0x00,0x00,0x0a,0x50,0x20,0x9f,0xe5,0x02,0x00,0x50,0xe1,0x09,0x00,0x00,0x0a, -0xdf,0xf0,0x2f,0xe3,0xe9,0xff,0xff,0xeb,0x09,0x00,0xbd,0xe8,0xd3,0xf0,0x2f,0xe3, -0x00,0xf0,0x69,0xe1,0x03,0xe0,0xa0,0xe1,0xdf,0xf0,0x2f,0xe3,0x0f,0x50,0xbd,0xe8, -0xd3,0xf0,0x2f,0xe3,0x0e,0xf0,0xb0,0xe1,0xdf,0xf0,0x2f,0xe3,0x09,0x00,0xbd,0xe8, -0xd3,0xf0,0x2f,0xe3,0x00,0xf0,0x69,0xe1,0x03,0xe0,0xa0,0xe1,0xdf,0xf0,0x2f,0xe3, -0x0f,0x50,0xbd,0xe8,0xd3,0xf0,0x2f,0xe3,0x0e,0xf0,0xb0,0xe1,0x56,0x34,0x12,0x00, -0x14,0x30,0x9f,0xe5,0x14,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x30,0x93,0xe7, -0x00,0x30,0x93,0xe5,0x00,0xd0,0x83,0xe5,0x1e,0xff,0x2f,0xe1,0xf8,0x38,0x00,0x00, -0x48,0x00,0x00,0x00,0x18,0x30,0x9f,0xe5,0x18,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x02,0x30,0x93,0xe7,0x00,0x30,0x93,0xe5,0x00,0x00,0x93,0xe5,0x00,0xd0,0xa0,0xe1, -0x1e,0xff,0x2f,0xe1,0xd4,0x38,0x00,0x00,0x48,0x00,0x00,0x00,0xff,0xcf,0x2d,0xe9, -0x00,0x10,0x0f,0xe1,0x08,0x00,0x11,0xe3,0x00,0x00,0x00,0x1a,0xfe,0xff,0xff,0xea, -0x80,0x00,0x81,0xe3,0x00,0xf0,0x2f,0xe1,0x34,0xe0,0x8d,0xe5,0x02,0x10,0x2d,0xe9, -0xe2,0xff,0xff,0xeb,0x9e,0xf8,0xff,0xeb,0xe9,0xff,0xff,0xeb,0x02,0x10,0xbd,0xe8, -0x34,0xe0,0x9d,0xe5,0x01,0xf0,0x2f,0xe1,0xff,0xcf,0xbd,0xe8,0xf0,0x47,0x2d,0xe9, -0x02,0x61,0x81,0xe0,0x00,0x40,0xa0,0xe1,0x90,0x80,0x9f,0xe5,0x40,0x70,0x46,0xe2, -0x03,0xa0,0xa0,0xe1,0x01,0x50,0xa0,0xe1,0x8a,0xff,0xff,0xeb,0x40,0x20,0xa0,0xe3, -0x0f,0x90,0x80,0xe3,0x00,0x10,0xa0,0xe3,0x07,0x00,0xa0,0xe1,0xc1,0xf7,0xff,0xeb, -0x10,0x30,0x94,0xe5,0x08,0x80,0x8f,0xe0,0x64,0x20,0x9f,0xe5,0x80,0x90,0xc9,0xe3, -0x00,0x00,0x53,0xe3,0x14,0x30,0x94,0x05,0x00,0x00,0x5a,0xe3,0x02,0x20,0x98,0xe7, -0x3c,0x30,0x87,0xe5,0x18,0x30,0x94,0xe5,0x38,0x20,0x87,0xe5,0x40,0x90,0x06,0xe5, -0x08,0x30,0x87,0xe5,0x04,0x50,0x84,0xe5,0x00,0x70,0x84,0xe5,0xf0,0x87,0xbd,0x08, -0xc7,0xff,0xff,0xeb,0x10,0x30,0x94,0xe5,0x00,0x00,0x53,0xe3,0x03,0x00,0x00,0x0a, -0x18,0x00,0x94,0xe5,0x0f,0xe0,0xa0,0xe1,0x13,0xff,0x2f,0xe1,0xf0,0x87,0xbd,0xe8, -0x18,0x00,0x94,0xe5,0x0f,0xe0,0xa0,0xe1,0x14,0xf0,0x94,0xe5,0xf0,0x87,0xbd,0xe8, -0x3c,0x38,0x00,0x00,0x34,0x00,0x00,0x00,0xfe,0xff,0xff,0xea,0x03,0x30,0x10,0xe2, -0x01,0xc8,0xa0,0xe1,0x01,0x30,0xa0,0x13,0x02,0x20,0x80,0xe0,0x01,0xcc,0x8c,0xe1, -0x02,0x00,0x50,0xe1,0x00,0x30,0xa0,0x23,0x01,0x30,0x03,0x32,0x00,0x00,0x53,0xe3, -0x01,0xc0,0x8c,0xe1,0x30,0x00,0x2d,0xe9,0x00,0x30,0xa0,0xe1,0xff,0x50,0x01,0xe2, -0x01,0x14,0x8c,0xe1,0x11,0x00,0x00,0x0a,0x00,0xc0,0xa0,0xe1,0x01,0x50,0xcc,0xe4, -0x03,0x40,0x1c,0xe2,0x01,0x40,0xa0,0x13,0x0c,0x30,0xa0,0xe1,0x0c,0x00,0x52,0xe1, -0x00,0x40,0xa0,0x93,0x01,0x40,0x04,0x82,0x00,0x00,0x54,0xe3,0xf6,0xff,0xff,0x1a, -0x02,0xc0,0x63,0xe0,0x0f,0x00,0x5c,0xe3,0x0a,0x00,0x00,0x9a,0x00,0x10,0x83,0xe5, -0x04,0x10,0x83,0xe5,0x08,0x10,0x83,0xe5,0x0c,0x10,0x83,0xe5,0x10,0x30,0x83,0xe2, -0x02,0xc0,0x63,0xe0,0x0f,0x00,0x5c,0xe3,0xf7,0xff,0xff,0x8a,0x03,0x00,0x52,0xe1, -0x02,0x00,0x00,0x9a,0x01,0x50,0xc3,0xe4,0x03,0x00,0x52,0xe1,0xfc,0xff,0xff,0x8a, -0x30,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x03,0x00,0x11,0xe3,0x30,0x00,0x2d,0xe9, -0x00,0xc0,0xa0,0xe1,0x01,0x40,0xa0,0xe1,0x28,0x00,0x00,0x1a,0x03,0x00,0x10,0xe3, -0x26,0x00,0x00,0x1a,0x0f,0x00,0x52,0xe3,0x15,0x00,0x00,0x9a,0x01,0xc0,0xa0,0xe1, -0x00,0x30,0xa0,0xe1,0x02,0x40,0xa0,0xe1,0x00,0x50,0x9c,0xe5,0x10,0x40,0x44,0xe2, -0x0f,0x00,0x54,0xe3,0x00,0x50,0x83,0xe5,0x04,0x50,0x9c,0xe5,0x04,0x50,0x83,0xe5, -0x08,0x50,0x9c,0xe5,0x08,0x50,0x83,0xe5,0x0c,0x50,0x9c,0xe5,0x10,0xc0,0x8c,0xe2, -0x0c,0x50,0x83,0xe5,0x10,0x30,0x83,0xe2,0xf2,0xff,0xff,0x8a,0x10,0x20,0x42,0xe2, -0x0f,0x40,0xc2,0xe3,0x0f,0x20,0x02,0xe2,0x10,0x40,0x84,0xe2,0x04,0xc0,0x80,0xe0, -0x04,0x40,0x81,0xe0,0x03,0x00,0x52,0xe3,0x0c,0x00,0x00,0x9a,0x00,0x30,0xa0,0xe3, -0x03,0x10,0x94,0xe7,0x03,0x10,0x8c,0xe7,0x04,0x30,0x83,0xe2,0x02,0x10,0x63,0xe0, -0x03,0x00,0x51,0xe3,0xf9,0xff,0xff,0x8a,0x04,0x20,0x42,0xe2,0x03,0x30,0xc2,0xe3, -0x03,0x20,0x02,0xe2,0x04,0x30,0x83,0xe2,0x03,0xc0,0x8c,0xe0,0x03,0x40,0x84,0xe0, -0x00,0x00,0x52,0xe3,0x0c,0x00,0xa0,0x01,0x06,0x00,0x00,0x0a,0x00,0x30,0xa0,0xe3, -0x03,0x10,0xd4,0xe7,0x03,0x10,0xcc,0xe7,0x01,0x30,0x83,0xe2,0x03,0x00,0x52,0xe1, -0xfa,0xff,0xff,0x1a,0x02,0x00,0x8c,0xe0,0x30,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x02,0x20,0x80,0xe0,0x00,0x30,0xa0,0xe1,0x02,0x00,0x50,0xe1,0xf0,0x00,0x2d,0xe9, -0x00,0x00,0xa0,0x23,0x39,0x00,0x00,0x2a,0x03,0x00,0xa0,0xe1,0x00,0xc0,0xd1,0xe5, -0x01,0x40,0xd0,0xe4,0x00,0x00,0x52,0xe1,0x00,0x50,0xa0,0x83,0x01,0x50,0xa0,0x93, -0x04,0x00,0x6c,0xe0,0x0c,0x00,0x54,0xe1,0x05,0xc0,0xa0,0x01,0x01,0xc0,0x85,0x13, -0x00,0x00,0x5c,0xe3,0x05,0x30,0x83,0x02,0x1f,0x00,0x00,0x0a,0x2b,0x00,0x00,0xea, -0x03,0xc0,0x53,0xe5,0x02,0x00,0xd1,0xe5,0x00,0x50,0x5c,0xe0,0x01,0x50,0xa0,0x13, -0x0c,0x00,0x60,0xe0,0x06,0x00,0x52,0xe1,0x05,0x60,0xa0,0x81,0x01,0x60,0x85,0x93, -0x00,0x00,0x56,0xe3,0x21,0x00,0x00,0x1a,0x02,0xc0,0x53,0xe5,0x03,0x00,0xd1,0xe5, -0x00,0x50,0x5c,0xe0,0x01,0x50,0xa0,0x13,0x0c,0x00,0x60,0xe0,0x04,0x00,0x52,0xe1, -0x05,0x40,0xa0,0x81,0x01,0x40,0x85,0x93,0x00,0x00,0x54,0xe3,0x17,0x00,0x00,0x1a, -0x01,0xc0,0x53,0xe5,0x04,0x00,0xf1,0xe5,0x00,0x40,0x5c,0xe0,0x01,0x40,0xa0,0x13, -0x0c,0x00,0x60,0xe0,0x03,0x00,0x52,0xe1,0x04,0xc0,0xa0,0x81,0x01,0xc0,0x84,0x93, -0x04,0x30,0x83,0xe2,0x00,0x00,0x5c,0xe3,0x0c,0x00,0x00,0x1a,0x04,0xc0,0x53,0xe5, -0x03,0x70,0x43,0xe2,0x01,0x00,0xd1,0xe5,0x02,0x60,0x43,0xe2,0x01,0x40,0x43,0xe2, -0x00,0x50,0x5c,0xe0,0x01,0x50,0xa0,0x13,0x0c,0x00,0x60,0xe0,0x07,0x00,0x52,0xe1, -0x05,0xc0,0xa0,0x81,0x01,0xc0,0x85,0x93,0x00,0x00,0x5c,0xe3,0xd3,0xff,0xff,0x0a, -0xf0,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x00,0x00,0x52,0xe3,0x1e,0xff,0x2f,0x01, -0x00,0xc0,0xa0,0xe1,0x01,0x30,0xd1,0xe4,0x00,0x00,0x53,0xe3,0x01,0x30,0xcc,0xe4, -0x02,0x00,0x00,0x0a,0x01,0x20,0x52,0xe2,0xf9,0xff,0xff,0x1a,0x1e,0xff,0x2f,0xe1, -0x01,0x20,0x52,0xe2,0x1e,0xff,0x2f,0x01,0x03,0x10,0xa0,0xe1,0x03,0x10,0xcc,0xe7, -0x01,0x30,0x83,0xe2,0x02,0x00,0x53,0xe1,0xfb,0xff,0xff,0x1a,0x1e,0xff,0x2f,0xe1, -0x00,0x10,0xd0,0xe5,0x00,0x00,0x51,0xe3,0x06,0x00,0x00,0x0a,0x01,0x30,0x80,0xe2, -0x03,0x10,0xa0,0xe1,0x01,0x20,0xd3,0xe4,0x00,0x00,0x52,0xe3,0xfb,0xff,0xff,0x1a, -0x01,0x00,0x60,0xe0,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe1,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0x50,0xe1,0x04,0x40,0x2d,0xe5,0x00,0x10,0xa0,0x33,0x00,0x40,0xa0,0x23, -0x00,0x10,0x82,0x35,0x00,0x00,0x83,0x35,0x01,0x00,0x00,0x2a,0x12,0x00,0x00,0xea, -0x0c,0x40,0xa0,0xe1,0x81,0x10,0xb0,0xe1,0x01,0xc0,0x84,0xe2,0x10,0x00,0x00,0x4a, -0x01,0x00,0x50,0xe1,0xf9,0xff,0xff,0x2a,0xa1,0x10,0xa0,0xe1,0x04,0xc0,0xa0,0xe1, -0x00,0x40,0xa0,0xe3,0x84,0x40,0xa0,0xe1,0x01,0x00,0x50,0xe1,0x00,0x00,0x61,0x20, -0xa1,0x10,0xa0,0xe1,0x01,0x40,0x84,0x23,0x00,0x00,0x5c,0xe3,0x01,0xc0,0x4c,0xe2, -0xf7,0xff,0xff,0x1a,0x00,0x40,0x82,0xe5,0x00,0x00,0x83,0xe5,0x10,0x00,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0x00,0x00,0x51,0xe1,0xf0,0xff,0xff,0x9a,0xed,0xff,0xff,0xea, -0xf0,0x00,0x2d,0xe9,0xc0,0xcf,0x20,0xe0,0xc0,0xcf,0x4c,0xe0,0xc1,0x4f,0x21,0xe0, -0xc1,0x4f,0x44,0xe0,0x04,0x00,0x5c,0xe1,0x25,0x00,0x00,0x3a,0x84,0x40,0xb0,0xe1, -0x01,0x50,0xa0,0x53,0x03,0x00,0x00,0x5a,0x2a,0x00,0x00,0xea,0x84,0x40,0xb0,0xe1, -0x01,0x50,0x85,0xe2,0x22,0x00,0x00,0x4a,0x04,0x00,0x5c,0xe1,0xfa,0xff,0xff,0x2a, -0xa4,0x40,0xa0,0xe1,0x01,0x50,0x45,0xe2,0x00,0x60,0xa0,0xe3,0x86,0x60,0xa0,0xe1, -0x04,0x00,0x5c,0xe1,0x0c,0x70,0xa0,0xe1,0x01,0x60,0x86,0x23,0x0c,0x70,0x64,0x20, -0x00,0x00,0x55,0xe3,0xa4,0x40,0xa0,0xe1,0x01,0x50,0x45,0xe2,0x07,0xc0,0xa0,0xe1, -0xf5,0xff,0xff,0x1a,0x06,0x40,0xa0,0xe1,0x00,0x00,0x50,0xe3,0x00,0x40,0x82,0xe5, -0x04,0x00,0x00,0xba,0x00,0x00,0x51,0xe3,0x00,0x70,0x83,0xe5,0x05,0x00,0x00,0xba, -0xf0,0x00,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x00,0x00,0x51,0xe3,0x00,0x70,0x67,0xe2, -0x00,0x70,0x83,0xe5,0xf9,0xff,0xff,0xda,0x00,0x60,0x66,0xe2,0x00,0x60,0x82,0xe5, -0xf6,0xff,0xff,0xea,0x00,0x40,0xa0,0xe3,0x0c,0x70,0xa0,0xe1,0x04,0x60,0xa0,0xe1, -0xec,0xff,0xff,0xea,0x01,0x60,0x45,0xe2,0x04,0x00,0x5c,0xe1,0x06,0x50,0xa0,0x31, -0xa4,0x40,0xa0,0x31,0xdb,0xff,0xff,0xea,0x00,0x60,0xa0,0xe3,0x01,0x50,0xa0,0xe3, -0xf8,0xff,0xff,0xea,0x01,0x00,0x53,0xe1,0xf0,0x0f,0x2d,0xe9,0x20,0xa0,0x9d,0xe5, -0x24,0xb0,0x9d,0xe5,0x3b,0x00,0x00,0x8a,0x38,0x00,0x00,0x0a,0x02,0x60,0x92,0xe0, -0x00,0x40,0xa0,0xe3,0x03,0x70,0xa3,0xe0,0x01,0xc0,0x84,0xe2,0x00,0x00,0x57,0xe3, -0x06,0x20,0xa0,0xe1,0x07,0x30,0xa0,0xe1,0x0a,0x00,0x00,0xba,0x01,0x00,0x57,0xe1, -0x0d,0x00,0x00,0x8a,0x29,0x00,0x00,0x0a,0x0c,0x40,0xa0,0xe1,0x02,0x60,0x92,0xe0, -0x01,0xc0,0x84,0xe2,0x03,0x70,0xa3,0xe0,0x06,0x20,0xa0,0xe1,0x00,0x00,0x57,0xe3, -0x07,0x30,0xa0,0xe1,0xf4,0xff,0xff,0xaa,0x01,0x00,0x57,0xe1,0x02,0x00,0x00,0x8a, -0x04,0x00,0x00,0x1a,0x00,0x00,0x56,0xe1,0x02,0x00,0x00,0x9a,0xa7,0x30,0xb0,0xe1, -0x66,0x20,0xa0,0xe1,0x04,0xc0,0xa0,0xe1,0x00,0x40,0xa0,0xe3,0x00,0x50,0xa0,0xe3, -0x01,0x80,0xa0,0xe3,0x00,0x90,0xa0,0xe3,0x01,0x00,0x00,0xea,0xa3,0x30,0xb0,0xe1, -0x62,0x20,0xa0,0xe1,0x04,0x60,0x94,0xe0,0x05,0x70,0xa5,0xe0,0x01,0x00,0x53,0xe1, -0x06,0x40,0xa0,0xe1,0x07,0x50,0xa0,0xe1,0x06,0x00,0x00,0x8a,0x01,0x00,0x00,0x1a, -0x00,0x00,0x52,0xe1,0x03,0x00,0x00,0x8a,0x02,0x00,0x50,0xe0,0x03,0x10,0xc1,0xe0, -0x08,0x40,0x86,0xe1,0x09,0x50,0x87,0xe1,0x00,0x00,0x5c,0xe3,0x01,0xc0,0x4c,0xe2, -0xed,0xff,0xff,0x1a,0x30,0x00,0x8a,0xe8,0x03,0x00,0x8b,0xe8,0x09,0x00,0x00,0xea, -0x00,0x00,0x56,0xe1,0xe0,0xff,0xff,0x8a,0x0c,0x40,0xa0,0xe1,0xd2,0xff,0xff,0xea, -0x00,0x00,0x52,0xe1,0xc4,0xff,0xff,0x9a,0x00,0x30,0xa0,0xe3,0x00,0x40,0xa0,0xe3, -0x18,0x00,0x8a,0xe8,0x03,0x00,0x8b,0xe8,0xf0,0x0f,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x00,0x40,0x2d,0xe9,0x0c,0xd0,0x4d,0xe2,0x04,0x20,0x8d,0xe2,0x0d,0x30,0xa0,0xe1, -0x5a,0xff,0xff,0xeb,0x04,0x00,0x9d,0xe5,0x0c,0xd0,0x8d,0xe2,0x00,0x40,0xbd,0xe8, -0x1e,0xff,0x2f,0xe1,0x00,0x40,0x2d,0xe9,0x0c,0xd0,0x4d,0xe2,0x04,0x20,0x8d,0xe2, -0x0d,0x30,0xa0,0xe1,0x71,0xff,0xff,0xeb,0x04,0x00,0x9d,0xe5,0x0c,0xd0,0x8d,0xe2, -0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x00,0x40,0x2d,0xe9,0x0c,0xd0,0x4d,0xe2, -0x04,0x20,0x8d,0xe2,0x0d,0x30,0xa0,0xe1,0x48,0xff,0xff,0xeb,0x00,0x10,0x9d,0xe5, -0x04,0x00,0x9d,0xe5,0x0c,0xd0,0x8d,0xe2,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x00,0x40,0x2d,0xe9,0x1c,0xd0,0x4d,0xe2,0x10,0xc0,0x8d,0xe2,0x00,0xc0,0x8d,0xe5, -0x08,0xc0,0x8d,0xe2,0x04,0xc0,0x8d,0xe5,0x95,0xff,0xff,0xeb,0x08,0x20,0x9d,0xe5, -0x0c,0x30,0x9d,0xe5,0x10,0x00,0x9d,0xe5,0x14,0x10,0x9d,0xe5,0x1c,0xd0,0x8d,0xe2, -0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x0c,0x30,0x9f,0xe5,0x0c,0x20,0x9f,0xe5, -0x03,0x30,0x8f,0xe0,0x02,0x00,0x93,0xe7,0x1e,0xff,0x2f,0xe1,0x80,0x31,0x00,0x00, -0x20,0x00,0x00,0x00,0x0c,0x30,0x9f,0xe5,0x0c,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0, -0x02,0x00,0x93,0xe7,0x1e,0xff,0x2f,0xe1,0x64,0x31,0x00,0x00,0x70,0x00,0x00,0x00, -0x0c,0x30,0x9f,0xe5,0x0c,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x00,0x93,0xe7, -0x1e,0xff,0x2f,0xe1,0x48,0x31,0x00,0x00,0x18,0x00,0x00,0x00,0x0c,0x30,0x9f,0xe5, -0x0c,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x00,0x93,0xe7,0x1e,0xff,0x2f,0xe1, -0x2c,0x31,0x00,0x00,0x58,0x00,0x00,0x00,0x08,0x30,0x9f,0xe5,0x10,0x39,0x93,0xe5, -0x00,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70,0x08,0x30,0x9f,0xe5, -0x10,0x39,0x93,0xe5,0x00,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1,0x00,0xf0,0x00,0x70, -0x08,0x30,0x9f,0xe5,0x10,0x39,0x93,0xe5,0x00,0x30,0x80,0xe5,0x1e,0xff,0x2f,0xe1, -0x00,0xf0,0x00,0x70,0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0xf0,0x4f,0x2d,0xe9,0x01,0x10,0x51,0xe2, -0xd0,0x94,0x9f,0xe5,0x1c,0xd0,0x4d,0xe2,0x08,0x10,0x8d,0xe5,0x09,0x90,0x8f,0xe0, -0x04,0x90,0x8d,0xe5,0x85,0x00,0x00,0x0a,0x00,0x10,0xd2,0xe5,0x00,0x00,0x51,0xe3, -0x82,0x00,0x00,0x0a,0xb0,0xc4,0x9f,0xe5,0x00,0x50,0xa0,0xe1,0x01,0x40,0x82,0xe2, -0x08,0x60,0x9d,0xe5,0x20,0x80,0xa0,0xe3,0xa0,0x74,0x9f,0xe5,0x0c,0x00,0x89,0xe0, -0x0c,0xc0,0x8d,0xe5,0x14,0x00,0x8d,0xe5,0x03,0xb0,0xa0,0xe1,0x06,0x00,0x00,0xea, -0x00,0x60,0x56,0xe0,0x00,0x50,0x85,0xe0,0x76,0x00,0x00,0x0a,0x00,0x10,0xd4,0xe5, -0x00,0x00,0x51,0xe3,0x73,0x00,0x00,0x0a,0x01,0x40,0x84,0xe2,0x25,0x00,0x51,0xe3, -0x00,0x10,0xc5,0x15,0x01,0x00,0xa0,0x13,0xf4,0xff,0xff,0x1a,0x00,0x30,0xd4,0xe5, -0x30,0x00,0x53,0xe3,0x01,0x30,0xd4,0x05,0x01,0xa0,0x84,0x02,0x30,0x80,0xa0,0x03, -0x04,0xa0,0xa0,0x11,0x30,0x20,0x43,0xe2,0x09,0x00,0x52,0xe3,0x00,0x90,0xa0,0x83, -0x09,0x00,0x00,0x8a,0x01,0x20,0x8a,0xe2,0x00,0x90,0xa0,0xe3,0x09,0x91,0x89,0xe0, -0x02,0xa0,0xa0,0xe1,0x89,0x90,0x83,0xe0,0x01,0x30,0xd2,0xe4,0x30,0x90,0x49,0xe2, -0x30,0x10,0x43,0xe2,0x09,0x00,0x51,0xe3,0xf7,0xff,0xff,0x9a,0x25,0x30,0x43,0xe2, -0x01,0xa0,0x8a,0xe2,0x53,0x00,0x53,0xe3,0x03,0xf1,0x8f,0x90,0x55,0x00,0x00,0xea, -0xf4,0x00,0x00,0xea,0x53,0x00,0x00,0xea,0x52,0x00,0x00,0xea,0x51,0x00,0x00,0xea, -0x50,0x00,0x00,0xea,0x4f,0x00,0x00,0xea,0x4e,0x00,0x00,0xea,0x4d,0x00,0x00,0xea, -0x4c,0x00,0x00,0xea,0x4b,0x00,0x00,0xea,0x4a,0x00,0x00,0xea,0x49,0x00,0x00,0xea, -0x48,0x00,0x00,0xea,0x47,0x00,0x00,0xea,0x46,0x00,0x00,0xea,0x45,0x00,0x00,0xea, -0x44,0x00,0x00,0xea,0x43,0x00,0x00,0xea,0x42,0x00,0x00,0xea,0x41,0x00,0x00,0xea, -0x40,0x00,0x00,0xea,0x3f,0x00,0x00,0xea,0x3e,0x00,0x00,0xea,0x3d,0x00,0x00,0xea, -0x3c,0x00,0x00,0xea,0x3b,0x00,0x00,0xea,0x3a,0x00,0x00,0xea,0x39,0x00,0x00,0xea, -0x38,0x00,0x00,0xea,0x37,0x00,0x00,0xea,0xd0,0x00,0x00,0xea,0x97,0x00,0x00,0xea, -0x34,0x00,0x00,0xea,0x33,0x00,0x00,0xea,0x32,0x00,0x00,0xea,0x31,0x00,0x00,0xea, -0x92,0x00,0x00,0xea,0x2f,0x00,0x00,0xea,0x2e,0x00,0x00,0xea,0x2d,0x00,0x00,0xea, -0x2c,0x00,0x00,0xea,0x2b,0x00,0x00,0xea,0x2a,0x00,0x00,0xea,0x29,0x00,0x00,0xea, -0x28,0x00,0x00,0xea,0x27,0x00,0x00,0xea,0x77,0x00,0x00,0xea,0x25,0x00,0x00,0xea, -0x4d,0x00,0x00,0xea,0x23,0x00,0x00,0xea,0x22,0x00,0x00,0xea,0x27,0x00,0x00,0xea, -0x20,0x00,0x00,0xea,0x1f,0x00,0x00,0xea,0x1e,0x00,0x00,0xea,0x1d,0x00,0x00,0xea, -0x1c,0x00,0x00,0xea,0x1b,0x00,0x00,0xea,0x1a,0x00,0x00,0xea,0x19,0x00,0x00,0xea, -0x18,0x00,0x00,0xea,0x17,0x00,0x00,0xea,0xb0,0x00,0x00,0xea,0x77,0x00,0x00,0xea, -0x14,0x00,0x00,0xea,0x13,0x00,0x00,0xea,0x12,0x00,0x00,0xea,0x11,0x00,0x00,0xea, -0x72,0x00,0x00,0xea,0x0f,0x00,0x00,0xea,0x0e,0x00,0x00,0xea,0x0d,0x00,0x00,0xea, -0x0c,0x00,0x00,0xea,0x0b,0x00,0x00,0xea,0x0a,0x00,0x00,0xea,0x0f,0x00,0x00,0xea, -0x08,0x00,0x00,0xea,0x07,0x00,0x00,0xea,0x57,0x00,0x00,0xea,0x05,0x00,0x00,0xea, -0x2d,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea,0x07,0x00,0x00,0xea, -0x08,0x60,0x9d,0xe5,0x00,0x50,0xa0,0xe1,0x08,0x10,0x9d,0xe5,0x00,0x30,0xa0,0xe3, -0x00,0x30,0xc5,0xe5,0x01,0x00,0x66,0xe0,0x1c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8, -0x00,0x20,0x9b,0xe5,0x00,0x30,0xa0,0xe3,0x04,0xb0,0x8b,0xe2,0x02,0x10,0xa0,0xe1, -0x00,0x00,0x00,0xea,0x00,0x30,0xa0,0xe1,0x21,0x12,0xb0,0xe1,0x01,0x00,0x83,0xe2, -0xfb,0xff,0xff,0x1a,0x00,0x00,0x59,0xe1,0x09,0x10,0x60,0xa0,0x09,0x00,0xa0,0xa1, -0x00,0x00,0x56,0xe1,0x91,0x00,0x00,0x3a,0x00,0x00,0x51,0xe3,0x05,0xc0,0xa0,0x01, -0x05,0x00,0x00,0x0a,0x00,0xc0,0xa0,0xe3,0x0c,0x80,0xc5,0xe7,0x01,0xc0,0x8c,0xe2, -0x01,0x00,0x5c,0xe1,0xfb,0xff,0xff,0x1a,0x0c,0xc0,0x85,0xe0,0x0c,0x90,0x9d,0xe5, -0x04,0x10,0x9d,0xe5,0x09,0x10,0x81,0xe0,0x01,0x90,0xa0,0xe1,0x10,0x10,0x8d,0xe5, -0x0f,0x10,0x02,0xe2,0x22,0x22,0xa0,0xe1,0x01,0x10,0xd9,0xe7,0x03,0x10,0xcc,0xe7, -0x01,0x30,0x53,0xe2,0xf9,0xff,0xff,0x2a,0x6a,0x00,0x00,0xea,0x00,0x10,0x9b,0xe5, -0x04,0xb0,0x8b,0xe2,0x10,0xb0,0x8d,0xe5,0x00,0x30,0xa0,0xe3,0x01,0x20,0xa0,0xe1, -0x00,0x00,0x00,0xea,0x00,0x30,0xa0,0xe1,0x97,0x02,0x82,0xe0,0xa2,0x21,0xb0,0xe1, -0x01,0x00,0x83,0xe2,0xfa,0xff,0xff,0x1a,0x00,0x00,0x59,0xe1,0x09,0x20,0x60,0xa0, -0x09,0x00,0xa0,0xa1,0x00,0x00,0x56,0xe1,0x00,0x00,0xe0,0x33,0x14,0x00,0x00,0x3a, -0x00,0x00,0x52,0xe3,0x05,0x90,0xa0,0x01,0x05,0x00,0x00,0x0a,0x00,0x90,0xa0,0xe3, -0x09,0x80,0xc5,0xe7,0x01,0x90,0x89,0xe2,0x02,0x00,0x59,0xe1,0xfb,0xff,0xff,0x1a, -0x09,0x90,0x85,0xe0,0x04,0x20,0x9d,0xe5,0x0c,0xc0,0x9d,0xe5,0x0c,0xb0,0x82,0xe0, -0x97,0xc1,0x82,0xe0,0xa2,0x21,0xa0,0xe1,0x02,0xc1,0x82,0xe0,0x8c,0xc0,0x41,0xe0, -0x02,0x10,0xa0,0xe1,0x0c,0x20,0xdb,0xe7,0x03,0x20,0xc9,0xe7,0x01,0x30,0x53,0xe2, -0xf6,0xff,0xff,0x2a,0x10,0xb0,0x9d,0xe5,0x42,0x00,0x00,0xea,0x00,0x10,0x9b,0xe5, -0x04,0xb0,0x8b,0xe2,0x01,0x00,0xa0,0xe1,0x00,0x10,0x8d,0xe5,0xfa,0xf4,0xff,0xeb, -0x00,0x00,0x56,0xe1,0x00,0x90,0xa0,0xe1,0x00,0x10,0x9d,0xe5,0xa5,0xff,0xff,0x3a, -0x05,0x00,0xa0,0xe1,0x09,0x20,0xa0,0xe1,0xf2,0xf4,0xff,0xeb,0x00,0x00,0x59,0xe3, -0x0a,0x40,0xa0,0x01,0x28,0xff,0xff,0x0a,0x09,0x00,0xa0,0xe1,0x31,0x00,0x00,0xea, -0x00,0x10,0x9b,0xe5,0x00,0x20,0xa0,0xe3,0x04,0xb0,0x8b,0xe2,0x00,0x00,0x51,0xe3, -0x00,0x10,0x61,0xb2,0x00,0x30,0xe0,0xb3,0x01,0x30,0xa0,0xa3,0x01,0x00,0xa0,0xe1, -0x97,0xc0,0x80,0xe0,0xa0,0x01,0xb0,0xe1,0x01,0x20,0x82,0xe2,0xfb,0xff,0xff,0x1a, -0x01,0x00,0x73,0xe3,0x01,0x20,0x82,0x02,0x02,0x00,0x59,0xe1,0x02,0x90,0xa0,0xb1, -0x09,0xc0,0x62,0xa0,0x00,0xc0,0xa0,0xb3,0x09,0x00,0x56,0xe1,0x2f,0x00,0x00,0x3a, -0x01,0x00,0x73,0xe3,0x05,0x00,0xa0,0x01,0x2d,0x30,0xa0,0x03,0x01,0x30,0xc0,0x04, -0x01,0x20,0x42,0x02,0x05,0x00,0xa0,0x11,0x00,0x00,0x5c,0xe3,0x05,0x00,0x00,0x0a, -0x00,0x30,0xa0,0xe3,0x03,0x80,0xc0,0xe7,0x01,0x30,0x83,0xe2,0x0c,0x00,0x53,0xe1, -0xfb,0xff,0xff,0x1a,0x03,0x00,0x80,0xe0,0x00,0x00,0x52,0xe3,0xd9,0xff,0xff,0x0a, -0x10,0x50,0x8d,0xe5,0x01,0x30,0x42,0xe2,0x14,0x50,0x9d,0xe5,0x97,0xc1,0x82,0xe0, -0xa2,0x21,0xa0,0xe1,0x02,0xc1,0x82,0xe0,0x8c,0xc0,0x41,0xe0,0x02,0x10,0xa0,0xe1, -0x0c,0x20,0xd5,0xe7,0x03,0x20,0xc0,0xe7,0x01,0x30,0x53,0xe2,0xf6,0xff,0xff,0x2a, -0x10,0x50,0x9d,0xe5,0x09,0x00,0xa0,0xe1,0x00,0x00,0x50,0xe3,0x0a,0x40,0xa0,0xa1, -0x0b,0x00,0x00,0xba,0x02,0x00,0x70,0xe3,0xec,0xfe,0xff,0x1a,0xee,0xfe,0xff,0xea, -0x00,0x30,0x9b,0xe5,0x04,0xb0,0x8b,0xe2,0x00,0x30,0xc5,0xe5,0x0a,0x40,0xa0,0xe1, -0x01,0x00,0xa0,0xe3,0xe5,0xfe,0xff,0xea,0x25,0xc0,0xa0,0xe3,0x00,0xc0,0xc5,0xe5, -0xf9,0xff,0xff,0xea,0x01,0x00,0x70,0xe3,0xf1,0xff,0xff,0x1a,0x59,0xff,0xff,0xea, -0x00,0x00,0xe0,0xe3,0xeb,0xff,0xff,0xea,0xb4,0x30,0x00,0x00,0xa8,0xf3,0xff,0xff, -0xcd,0xcc,0xcc,0xcc,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1, -0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,0x01,0x00,0xa0,0xe3, -0x1e,0xff,0x2f,0xe1,0x9e,0xfe,0xff,0xea,0x9e,0xfe,0xff,0xea,0x9a,0xfe,0xff,0xea, -0x4c,0x30,0x9f,0xe5,0x78,0x20,0xa0,0xe3,0x48,0x10,0x9f,0xe5,0x30,0x40,0x2d,0xe9, -0x7c,0xd0,0x4d,0xe2,0x03,0x30,0x8f,0xe0,0x00,0x50,0xa0,0xe1,0x01,0x10,0x83,0xe0, -0x0d,0x00,0xa0,0xe1,0xff,0xfc,0xff,0xeb,0x14,0x06,0x00,0xeb,0x04,0x00,0x50,0xe3, -0x0d,0x40,0xa0,0xe1,0x01,0x00,0x00,0x0a,0x7c,0xd0,0x8d,0xe2,0x30,0x80,0xbd,0xe8, -0x05,0x00,0xa0,0xe1,0x0d,0x10,0xa0,0xe1,0x78,0x20,0xa0,0xe3,0x6b,0xf4,0xff,0xeb, -0xf8,0xff,0xff,0xea,0x2c,0x2b,0x00,0x00,0x88,0xff,0xff,0xff,0xf0,0x4f,0x2d,0xe9, -0x41,0x00,0x71,0xe3,0x7c,0x73,0x9f,0xe5,0x0c,0xd0,0x4d,0xe2,0x00,0x40,0xa0,0xe1, -0x07,0x70,0x8f,0xe0,0xaf,0x00,0x00,0x8a,0x18,0x60,0x90,0xe5,0x00,0x00,0x56,0xe3, -0xc9,0x00,0x00,0x0a,0x0c,0x90,0x90,0xe5,0x28,0x20,0x81,0xe2,0x09,0x00,0x52,0xe1, -0x44,0x00,0x00,0x2a,0x50,0x83,0x9f,0xe5,0x6e,0xaf,0x80,0xe2,0x0a,0x50,0xa0,0xe1, -0x08,0x30,0x87,0xe0,0x08,0xb0,0x93,0xe5,0x00,0x30,0x95,0xe5,0x03,0x00,0x56,0xe1, -0x03,0x00,0x00,0x3a,0x04,0x10,0x95,0xe5,0x01,0x30,0x83,0xe0,0x03,0x00,0x56,0xe1, -0x02,0x00,0x00,0x3a,0x08,0x50,0x95,0xe5,0x00,0x00,0x55,0xe3,0xf5,0xff,0xff,0x1a, -0x0c,0x10,0x95,0xe5,0x08,0x30,0x11,0xe2,0x32,0x00,0x00,0x1a,0x01,0x10,0x11,0xe2, -0x01,0x80,0xa0,0x01,0x30,0x00,0x00,0x0a,0x0b,0x00,0x89,0xe0,0x0b,0x10,0xa0,0xe1, -0x01,0x00,0x40,0xe2,0x04,0x30,0x8d,0xe5,0x00,0x00,0x62,0xe0,0x03,0xfe,0xff,0xeb, -0x01,0x00,0x40,0xe2,0x04,0x20,0x95,0xe5,0x90,0x0b,0x0b,0xe0,0x04,0x30,0x9d,0xe5, -0x02,0x00,0x5b,0xe1,0x03,0x80,0xa0,0x81,0x23,0x00,0x00,0x8a,0x00,0x30,0x95,0xe5, -0x02,0x10,0x83,0xe0,0x0a,0x00,0x53,0xe1,0x01,0x00,0x00,0x8a,0x01,0x00,0x5a,0xe1, -0x1c,0x00,0x00,0x3a,0x08,0xa0,0x9a,0xe5,0x00,0x00,0x5a,0xe3,0xf8,0xff,0xff,0x1a, -0x00,0x00,0x5b,0xe3,0x0b,0x80,0xa0,0x01,0x17,0x00,0x00,0x0a,0xac,0x01,0x94,0xe5, -0x07,0x10,0x16,0xe2,0x02,0x20,0x6b,0xe0,0x08,0xa0,0x61,0x12,0x04,0x20,0x85,0xe5, -0x08,0x70,0x87,0xe0,0x00,0x20,0x6b,0xe0,0x07,0xa0,0x0a,0x12,0xac,0x21,0x84,0xe5, -0x09,0x30,0x6b,0xe0,0x10,0x20,0x97,0xe5,0x03,0x30,0x6a,0xe0,0x0a,0x60,0x86,0xe0, -0x0c,0x30,0x84,0xe5,0x01,0x00,0x83,0xe3,0x03,0x10,0x86,0xe0,0x28,0x30,0xa0,0xe3, -0x18,0x60,0x84,0xe5,0x0b,0x80,0xa0,0xe1,0x04,0x00,0x86,0xe5,0x04,0x30,0x81,0xe5, -0x1c,0x20,0x84,0xe5,0x00,0x00,0x00,0xea,0x00,0x80,0xa0,0xe3,0xc0,0x31,0x94,0xe5, -0x00,0x00,0x53,0xe3,0x6e,0x5f,0x84,0x12,0x00,0x70,0xa0,0x13,0x01,0xb0,0xa0,0x13, -0x81,0x00,0x00,0x0a,0x0c,0xc0,0x93,0xe5,0x00,0x10,0x93,0xe5,0x04,0x00,0x93,0xe5, -0x09,0xc0,0x0c,0xe2,0x08,0x20,0x93,0xe5,0x01,0x00,0x5c,0xe3,0x0a,0x00,0x00,0x0a, -0x00,0x00,0x52,0xe3,0x03,0x50,0xa0,0xe1,0x4c,0x00,0x00,0x0a,0x02,0x30,0xa0,0xe1, -0x0c,0xc0,0x93,0xe5,0x00,0x10,0x93,0xe5,0x04,0x00,0x93,0xe5,0x09,0xc0,0x0c,0xe2, -0x08,0x20,0x93,0xe5,0x01,0x00,0x5c,0xe3,0xf4,0xff,0xff,0x1a,0x07,0xc0,0x11,0xe2, -0x08,0xc0,0x6c,0x12,0x07,0xc0,0x0c,0x12,0x0c,0xc0,0x81,0xe0,0x04,0xa0,0x9c,0xe5, -0x02,0x60,0x1a,0xe2,0xed,0xff,0xff,0x1a,0x03,0xa0,0xca,0xe3,0x28,0x90,0x40,0xe2, -0x0a,0xa0,0x8c,0xe0,0x09,0x10,0x81,0xe0,0x01,0x00,0x5a,0xe1,0xe7,0xff,0xff,0x3a, -0x14,0x30,0x94,0xe5,0x03,0x00,0x5c,0xe1,0x14,0x60,0x84,0x05,0x08,0x60,0x84,0x05, -0x2b,0x00,0x00,0x0a,0x0c,0x30,0x9c,0xe5,0x18,0xa0,0x9c,0xe5,0x03,0x00,0x5c,0xe1, -0x36,0x00,0x00,0x0a,0x08,0x10,0x9c,0xe5,0x10,0x60,0x94,0xe5,0x01,0x00,0x56,0xe1, -0x57,0x00,0x00,0x8a,0x0c,0x30,0x81,0xe5,0x08,0x10,0x83,0xe5,0x00,0x00,0x5a,0xe3, -0x1f,0x00,0x00,0x0a,0x1c,0x10,0x9c,0xe5,0x4a,0x60,0x81,0xe2,0x06,0x61,0x84,0xe0, -0x04,0x90,0x96,0xe5,0x09,0x00,0x5c,0xe1,0x3b,0x00,0x00,0x0a,0x10,0x10,0x94,0xe5, -0x0a,0x00,0x51,0xe1,0x4b,0x00,0x00,0x8a,0x10,0x60,0x9a,0xe5,0x06,0x00,0x5c,0xe1, -0x10,0x30,0x8a,0x05,0x14,0x30,0x8a,0x15,0x00,0x00,0x53,0xe3,0x10,0x00,0x00,0x0a, -0x03,0x00,0x51,0xe1,0x44,0x00,0x00,0x8a,0x10,0x60,0x9c,0xe5,0x18,0xa0,0x83,0xe5, -0x00,0x00,0x56,0xe3,0x03,0x00,0x00,0x0a,0x06,0x00,0x51,0xe1,0x3f,0x00,0x00,0x8a, -0x10,0x60,0x83,0xe5,0x18,0x30,0x86,0xe5,0x14,0xc0,0x9c,0xe5,0x00,0x00,0x5c,0xe3, -0x03,0x00,0x00,0x0a,0x0c,0x00,0x51,0xe1,0x39,0x00,0x00,0x8a,0x14,0xc0,0x83,0xe5, -0x18,0x30,0x8c,0xe5,0xac,0x31,0x94,0xe5,0x00,0x00,0x52,0xe3,0x00,0x70,0x87,0xe0, -0x03,0x00,0x60,0xe0,0xac,0x01,0x84,0xe5,0x08,0x20,0x85,0xe5,0xb2,0xff,0xff,0x1a, -0x08,0x00,0x97,0xe0,0x00,0x30,0xe0,0x03,0x1c,0x30,0x84,0x05,0x01,0x00,0xa0,0x13, -0x0c,0xd0,0x8d,0xe2,0xf0,0x8f,0xbd,0xe8,0x00,0x00,0xa0,0xe3,0xfb,0xff,0xff,0xea, -0x14,0x30,0x9c,0xe5,0x00,0x00,0x53,0xe3,0x14,0x10,0x8c,0x12,0x18,0x00,0x00,0x0a, -0x14,0x60,0x93,0xe5,0x00,0x00,0x56,0xe3,0x14,0x10,0x83,0x12,0x06,0x30,0xa0,0x11, -0xfa,0xff,0xff,0x1a,0x10,0x60,0x93,0xe5,0x00,0x00,0x56,0xe3,0x10,0x10,0x83,0x12, -0x06,0x30,0xa0,0x11,0xf5,0xff,0xff,0x1a,0x10,0x90,0x94,0xe5,0x01,0x00,0x59,0xe1, -0x10,0x00,0x00,0x8a,0x00,0x60,0x81,0xe5,0xbb,0xff,0xff,0xea,0x00,0x00,0x53,0xe3, -0x04,0x30,0x86,0xe5,0x10,0x10,0x94,0x15,0xc8,0xff,0xff,0x1a,0x04,0x30,0x94,0xe5, -0x1b,0x11,0xc3,0xe1,0x04,0x10,0x84,0xe5,0xd5,0xff,0xff,0xea,0x06,0x00,0xa0,0xe1, -0xde,0xff,0xff,0xea,0x10,0x30,0x9c,0xe5,0x00,0x00,0x53,0xe3,0x10,0x10,0x8c,0x12, -0xe2,0xff,0xff,0x1a,0xac,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0x03,0x70,0xa0,0xe1, -0xd2,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0xd0,0x2a,0x00,0x00,0xe8,0x12,0x00,0x00, -0xf8,0x45,0x2d,0xe9,0x00,0x80,0xa0,0xe1,0x6c,0x51,0x9f,0xe5,0x01,0x70,0xa0,0xe1, -0x68,0x61,0x9f,0xe5,0x05,0x50,0x8f,0xe0,0x06,0x30,0x85,0xe0,0x04,0x20,0x93,0xe5, -0x00,0x00,0x52,0xe3,0x12,0x00,0x00,0x1a,0x06,0x10,0x95,0xe7,0x05,0x20,0x82,0xe2, -0x01,0x07,0xa0,0xe3,0x14,0x20,0x83,0xe5,0x0c,0x00,0x83,0xe5,0x00,0x00,0x51,0xe3, -0x02,0x16,0xa0,0xe3,0x10,0x10,0x83,0xe5,0x04,0x00,0x00,0x1a,0x30,0x11,0x9f,0xe5, -0x30,0x01,0x9f,0xe5,0x01,0x10,0x85,0xe0,0x00,0x00,0x83,0xe5,0xb4,0x21,0x81,0xe5, -0x06,0x30,0x85,0xe0,0x01,0x2a,0xa0,0xe3,0x04,0x20,0x83,0xe5,0x0f,0x2a,0x82,0xe2, -0x08,0x20,0x83,0xe5,0x7e,0x0f,0x57,0xe3,0x02,0x00,0x00,0x8a,0x00,0x40,0xa0,0xe3, -0x04,0x00,0xa0,0xe1,0xf8,0x85,0xbd,0xe8,0x06,0x20,0x85,0xe0,0xf8,0x30,0x9f,0xe5, -0x04,0x20,0x92,0xe5,0x03,0x30,0x62,0xe0,0x03,0x00,0x57,0xe1,0xf6,0xff,0xff,0x2a, -0x07,0xa0,0x18,0xe2,0x00,0x10,0xa0,0xe3,0x08,0xa0,0x6a,0x12,0x1d,0x2e,0xa0,0xe3, -0x07,0xa0,0x0a,0x12,0x0a,0xa0,0x88,0xe0,0x08,0x40,0x8a,0xe2,0x04,0x00,0xa0,0xe1, -0xb1,0xfb,0xff,0xeb,0x06,0x30,0x85,0xe0,0x06,0x10,0x95,0xe7,0x14,0x20,0x93,0xe5, -0x2c,0x00,0x8a,0xe2,0xb4,0xc0,0x9f,0xe5,0x00,0x30,0xa0,0xe3,0x04,0x20,0x82,0xe3, -0x04,0xc0,0x8a,0xe5,0x10,0x80,0x84,0xe5,0xb8,0x81,0x84,0xe5,0xb0,0x71,0x84,0xe5, -0xac,0x71,0x84,0xe5,0xbc,0x71,0x84,0xe5,0x20,0x10,0x84,0xe5,0xb4,0x21,0x84,0xe5, -0x03,0x20,0x80,0xe0,0x08,0x30,0x83,0xe2,0x01,0x0c,0x53,0xe3,0x0c,0x20,0x82,0xe5, -0x08,0x20,0x82,0xe5,0xf9,0xff,0xff,0x1a,0x04,0x30,0x14,0xe5,0x07,0x00,0x88,0xe0, -0x06,0x50,0x85,0xe0,0x10,0x10,0x95,0xe5,0x03,0x30,0xc3,0xe3,0x08,0x30,0x43,0xe2, -0x03,0x30,0x84,0xe0,0x07,0x20,0x13,0xe2,0x00,0x00,0x63,0xe0,0x08,0x20,0x62,0x12, -0x28,0x00,0x40,0xe2,0x07,0x20,0x02,0x12,0x02,0x30,0x83,0xe0,0x00,0x20,0x62,0xe0, -0x01,0xc0,0x82,0xe3,0x18,0x30,0x84,0xe5,0x02,0x00,0x83,0xe0,0x0c,0x20,0x84,0xe5, -0x04,0xc0,0x83,0xe5,0x28,0x30,0xa0,0xe3,0x04,0x30,0x80,0xe5,0x08,0x30,0xa0,0xe3, -0x1c,0x10,0x84,0xe5,0xc4,0x31,0x84,0xe5,0xc0,0xff,0xff,0xea,0x3c,0x27,0x00,0x00, -0xe8,0x12,0x00,0x00,0x20,0x11,0x00,0x00,0x58,0x58,0x58,0x58,0x08,0xfe,0xff,0xff, -0xd3,0x01,0x00,0x00,0xf4,0x00,0x51,0xe3,0xf0,0x0f,0x2d,0xe9,0x00,0x30,0xa0,0xe1, -0x08,0xd0,0x4d,0xe2,0x57,0x00,0x00,0x8a,0x0a,0x00,0x51,0xe3,0x00,0x80,0x90,0xe5, -0x0b,0x20,0x81,0x82,0x10,0x20,0xa0,0x93,0x07,0x20,0xc2,0x83,0xa2,0x11,0xa0,0xe1, -0x38,0x01,0xa0,0xe1,0x03,0x00,0x10,0xe3,0x75,0x00,0x00,0x1a,0x08,0x40,0x93,0xe5, -0x04,0x00,0x52,0xe1,0x51,0x00,0x00,0x9a,0x00,0x00,0x50,0xe3,0xb3,0x00,0x00,0x0a, -0x01,0x70,0xa0,0xe3,0x24,0xc0,0x83,0xe2,0x17,0x51,0xa0,0xe1,0x15,0x57,0xa0,0xe1, -0x00,0x60,0x65,0xe2,0x05,0x50,0x86,0xe1,0x10,0x11,0x05,0xe0,0x00,0x00,0x61,0xe2, -0x01,0x10,0x00,0xe0,0x01,0x00,0x41,0xe2,0x20,0x16,0xa0,0xe1,0x10,0x10,0x01,0xe2, -0x30,0x01,0xa0,0xe1,0xa0,0x52,0xa0,0xe1,0x08,0x50,0x05,0xe2,0x30,0x05,0xa0,0xe1, -0x01,0x50,0x85,0xe0,0x20,0x11,0xa0,0xe1,0x04,0x10,0x01,0xe2,0x30,0x01,0xa0,0xe1, -0x01,0xa0,0x85,0xe0,0x30,0x17,0xa0,0xe1,0x02,0x10,0x01,0xe2,0x30,0x01,0xa0,0xe1, -0x01,0xa0,0x8a,0xe0,0x30,0x17,0xa0,0xe1,0x07,0x10,0x01,0xe0,0x01,0xa0,0x8a,0xe0, -0x30,0xa1,0x8a,0xe0,0x8a,0x11,0xa0,0xe1,0x01,0x60,0x8c,0xe0,0x08,0x00,0x96,0xe5, -0x08,0x50,0x90,0xe5,0x05,0x00,0x56,0xe1,0x17,0x7a,0xc8,0x01,0x00,0x70,0x83,0x05, -0x04,0x00,0x00,0x0a,0x10,0x70,0x93,0xe5,0x05,0x00,0x57,0xe1,0x08,0x50,0x86,0x95, -0x0c,0x60,0x85,0x95,0x84,0x01,0x00,0x8a,0x01,0x10,0x62,0xe0,0x00,0x00,0x54,0xe3, -0x02,0x50,0x80,0xe0,0x01,0x60,0x81,0xe3,0x03,0x20,0x82,0xe3,0x01,0x10,0x85,0xe7, -0x04,0x20,0x80,0xe5,0x04,0x60,0x85,0xe5,0x12,0x00,0x00,0x0a,0xa4,0x41,0xa0,0xe1, -0x00,0x60,0x93,0xe5,0x01,0x70,0xa0,0xe3,0x14,0x20,0x93,0xe5,0x17,0x74,0xa0,0xe1, -0x84,0xc1,0x8c,0xe0,0x06,0x00,0x17,0xe1,0x06,0x60,0x87,0x01,0x0c,0x40,0xa0,0x01, -0x00,0x60,0x83,0x05,0x03,0x00,0x00,0x0a,0x08,0x40,0x9c,0xe5,0x10,0x60,0x93,0xe5, -0x06,0x00,0x54,0xe1,0x83,0x00,0x00,0x3a,0x08,0x20,0x8c,0xe5,0x0c,0x20,0x84,0xe5, -0x08,0x40,0x82,0xe5,0x0c,0xc0,0x82,0xe5,0x08,0x10,0x83,0xe5,0x08,0x00,0x80,0xe2, -0x14,0x50,0x83,0xe5,0x12,0x00,0x00,0xea,0x41,0x00,0x71,0xe3,0x08,0x40,0x90,0x85, -0x00,0x20,0xe0,0x83,0x1b,0x00,0x00,0x9a,0x04,0x00,0x52,0xe1,0x66,0x00,0x00,0x8a, -0x04,0x10,0x62,0xe0,0x14,0x00,0x93,0xe5,0x0f,0x00,0x51,0xe3,0x0b,0x00,0x00,0x9a, -0x02,0xc0,0x80,0xe0,0x01,0x40,0x81,0xe3,0x03,0x20,0x82,0xe3,0x14,0xc0,0x83,0xe5, -0x08,0x10,0x83,0xe5,0x04,0x40,0x8c,0xe5,0x01,0x10,0x8c,0xe7,0x04,0x20,0x80,0xe5, -0x08,0x00,0x80,0xe2,0x08,0xd0,0x8d,0xe2,0xf0,0x0f,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, -0x04,0x20,0x80,0xe0,0x00,0x10,0xa0,0xe3,0x03,0x40,0x84,0xe3,0x08,0x10,0x83,0xe5, -0x14,0x10,0x83,0xe5,0x04,0x40,0x80,0xe5,0x04,0x30,0x92,0xe5,0x01,0x30,0x83,0xe3, -0x04,0x30,0x82,0xe5,0xf1,0xff,0xff,0xea,0x04,0x50,0x90,0xe5,0x0b,0x20,0x81,0xe2, -0x07,0x20,0xc2,0xe3,0x00,0x00,0x55,0xe3,0x11,0x00,0x00,0x1a,0x08,0x40,0x93,0xe5, -0xdc,0xff,0xff,0xea,0x01,0x20,0x00,0xe2,0x24,0xc0,0x83,0xe2,0x01,0x20,0x22,0xe2, -0x01,0x10,0x82,0xe0,0x81,0x41,0xa0,0xe1,0x04,0xc0,0x8c,0xe0,0x08,0x00,0x9c,0xe5, -0x08,0x20,0x90,0xe5,0x02,0x00,0x5c,0xe1,0x2d,0x00,0x00,0x0a,0x10,0x30,0x93,0xe5, -0x02,0x00,0x53,0xe1,0x08,0x20,0x8c,0x95,0x0c,0xc0,0x82,0x95,0x2b,0x00,0x00,0x9a, -0xfe,0xff,0xff,0xea,0x22,0xc4,0xb0,0xe1,0x00,0x60,0x62,0xe2,0x02,0x00,0x00,0x0a, -0x01,0x08,0x5c,0xe3,0x1f,0xc0,0xa0,0x23,0x0a,0x01,0x00,0x3a,0x0c,0x11,0x83,0xe0, -0x2c,0x01,0x91,0xe5,0x00,0x00,0x50,0xe3,0x7b,0x00,0x00,0x0a,0x1f,0x00,0x5c,0xe3, -0x00,0x40,0xa0,0xe3,0xac,0x80,0xa0,0x11,0x00,0x80,0xa0,0x03,0x06,0x70,0xa0,0xe1, -0x19,0x80,0x68,0x12,0x04,0x10,0xa0,0xe1,0x12,0x88,0xa0,0xe1,0x06,0x00,0x00,0xea, -0x14,0x60,0x90,0xe5,0x0a,0x01,0x90,0xe7,0x00,0x00,0x56,0xe1,0x00,0x00,0x56,0x13, -0x06,0x40,0xa0,0x11,0x00,0x00,0x50,0xe3,0x66,0x00,0x00,0x0a,0x04,0x60,0x90,0xe5, -0xa8,0xaf,0xa0,0xe1,0x88,0x80,0xa0,0xe1,0x04,0xa0,0x8a,0xe2,0x03,0x60,0xc6,0xe3, -0x06,0x60,0x62,0xe0,0x07,0x00,0x56,0xe1,0xf0,0xff,0xff,0x2a,0x00,0x00,0x56,0xe3, -0x00,0x10,0xa0,0xe1,0x06,0x70,0xa0,0xe1,0xec,0xff,0xff,0x1a,0x00,0x10,0xa0,0xe1, -0x5a,0x00,0x00,0xea,0x01,0x20,0xa0,0xe3,0x12,0x11,0xc8,0xe1,0x00,0x10,0x83,0xe5, -0x04,0x30,0x80,0xe0,0x03,0x40,0x84,0xe3,0x04,0x40,0x80,0xe5,0x08,0x00,0x80,0xe2, -0x04,0x20,0x93,0xe5,0x01,0x20,0x82,0xe3,0x04,0x20,0x83,0xe5,0xa8,0xff,0xff,0xea, -0x04,0x50,0x93,0xe5,0x00,0x00,0x55,0xe3,0x0f,0x00,0x00,0x1a,0x0c,0x00,0x93,0xe5, -0x02,0x00,0x50,0xe1,0x00,0x00,0xa0,0x93,0xa1,0xff,0xff,0x9a,0x18,0x10,0x93,0xe5, -0x00,0x00,0x62,0xe0,0x01,0x40,0x80,0xe3,0x03,0xc0,0x82,0xe3,0x0c,0x00,0x83,0xe5, -0x02,0x20,0x81,0xe0,0x08,0x00,0x81,0xe2,0x18,0x20,0x83,0xe5,0x04,0x40,0x82,0xe5, -0x04,0xc0,0x81,0xe5,0x96,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0x00,0x00,0x65,0xe2, -0x05,0x00,0x00,0xe0,0x01,0x00,0x40,0xe2,0x20,0x16,0xa0,0xe1,0x10,0x10,0x01,0xe2, -0x30,0x01,0xa0,0xe1,0xa0,0xc2,0xa0,0xe1,0x08,0xc0,0x0c,0xe2,0x30,0x0c,0xa0,0xe1, -0x01,0xc0,0x8c,0xe0,0x20,0x11,0xa0,0xe1,0x04,0x10,0x01,0xe2,0x30,0x01,0xa0,0xe1, -0x01,0xc0,0x8c,0xe0,0xa0,0x10,0xa0,0xe1,0x02,0x10,0x01,0xe2,0x30,0x01,0xa0,0xe1, -0x01,0xc0,0x8c,0xe0,0xa0,0x10,0xa0,0xe1,0x01,0x10,0x01,0xe2,0x01,0xc0,0x8c,0xe0, -0x30,0x11,0x8c,0xe0,0x01,0x11,0x83,0xe0,0x2c,0xc1,0x91,0xe5,0x04,0x60,0x9c,0xe5, -0x0c,0x00,0xa0,0xe1,0x03,0x60,0xc6,0xe3,0x06,0x60,0x62,0xe0,0x07,0x00,0x00,0xea, -0x04,0xc0,0x91,0xe5,0x03,0xc0,0xcc,0xe3,0x0c,0xc0,0x62,0xe0,0x06,0x00,0x5c,0xe1, -0x06,0xc0,0xa0,0x21,0x01,0x00,0xa0,0x31,0x0c,0x60,0xa0,0xe1,0x01,0xc0,0xa0,0xe1, -0x10,0x10,0x9c,0xe5,0x00,0x00,0x51,0xe3,0xf4,0xff,0xff,0x1a,0x14,0x10,0x9c,0xe5, -0x00,0x00,0x51,0xe3,0xf1,0xff,0xff,0x1a,0x10,0xc0,0x93,0xe5,0x00,0x00,0x5c,0xe1, -0x1e,0x01,0x00,0x8a,0x02,0xb0,0x80,0xe0,0x0b,0x00,0x50,0xe1,0x1b,0x01,0x00,0x2a, -0x0c,0x10,0x90,0xe5,0x18,0x70,0x90,0xe5,0x01,0x00,0x50,0xe1,0xdd,0x00,0x00,0x0a, -0x08,0xa0,0x90,0xe5,0x0a,0x00,0x5c,0xe1,0x0c,0x10,0x8a,0x95,0x08,0xa0,0x81,0x95, -0xb2,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x04,0x00,0xa0,0xe1,0x07,0x60,0xa0,0xe1, -0x00,0x00,0x51,0xe3,0x00,0x00,0x50,0x03,0x2b,0x00,0x00,0x1a,0x02,0x10,0xa0,0xe3, -0x11,0xcc,0xa0,0xe1,0x00,0x00,0x6c,0xe2,0x0c,0x00,0x80,0xe1,0x05,0x00,0x10,0xe0, -0x00,0x10,0xa0,0x01,0x24,0x00,0x00,0x0a,0x00,0xc0,0x60,0xe2,0x00,0x10,0xa0,0xe3, -0x00,0x00,0x0c,0xe0,0x01,0xc0,0x40,0xe2,0x2c,0x06,0xa0,0xe1,0x10,0x00,0x00,0xe2, -0x3c,0xc0,0xa0,0xe1,0xac,0x42,0xa0,0xe1,0x08,0x40,0x04,0xe2,0x3c,0xc4,0xa0,0xe1, -0x00,0x40,0x84,0xe0,0x2c,0x01,0xa0,0xe1,0x04,0x00,0x00,0xe2,0x3c,0xc0,0xa0,0xe1, -0x00,0x40,0x84,0xe0,0xac,0x00,0xa0,0xe1,0x02,0x00,0x00,0xe2,0x3c,0xc0,0xa0,0xe1, -0x00,0x40,0x84,0xe0,0xac,0x00,0xa0,0xe1,0x01,0x00,0x00,0xe2,0x00,0x40,0x84,0xe0, -0x3c,0x00,0x84,0xe0,0x00,0x01,0x83,0xe0,0x2c,0x01,0x90,0xe5,0x0a,0x00,0x00,0xea, -0x04,0x40,0x90,0xe5,0x10,0xc0,0x90,0xe5,0x03,0x40,0xc4,0xe3,0x04,0x40,0x62,0xe0, -0x06,0x00,0x54,0xe1,0x06,0x40,0xa0,0x21,0x00,0x10,0xa0,0x31,0x00,0x00,0x5c,0xe3, -0x04,0x60,0xa0,0xe1,0x14,0xc0,0x90,0x05,0x0c,0x00,0xa0,0xe1,0x00,0x00,0x50,0xe3, -0xf2,0xff,0xff,0x1a,0x00,0x00,0x51,0xe3,0x37,0xff,0xff,0x0a,0x08,0x40,0x93,0xe5, -0x04,0x00,0x62,0xe0,0x00,0x00,0x56,0xe1,0x12,0xff,0xff,0x2a,0x10,0xc0,0x93,0xe5, -0x01,0x00,0x5c,0xe1,0x52,0x00,0x00,0x8a,0x02,0x00,0x81,0xe0,0x00,0x00,0x51,0xe1, -0x4f,0x00,0x00,0x2a,0x0c,0xa0,0x91,0xe5,0x18,0x80,0x91,0xe5,0x01,0x00,0x5a,0xe1, -0x2f,0x00,0x00,0x0a,0x08,0x90,0x91,0xe5,0x09,0x00,0x5c,0xe1,0x0c,0xa0,0x89,0x95, -0x0a,0x70,0xa0,0x91,0x08,0x90,0x8a,0x95,0x04,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea, -0x10,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3,0x10,0xa0,0x81,0x12,0x28,0x00,0x00,0x1a, -0x00,0x00,0x58,0xe3,0x32,0x00,0x00,0x0a,0x1c,0xb0,0x91,0xe5,0x4a,0xa0,0x8b,0xe2, -0x0a,0xa1,0x83,0xe0,0x04,0x90,0x9a,0xe5,0x01,0x00,0x59,0xe1,0x26,0x00,0x00,0x0a, -0x08,0x00,0x5c,0xe1,0x10,0x00,0x00,0x8a,0x10,0xa0,0x98,0xe5,0x01,0x00,0x5a,0xe1, -0x10,0x70,0x88,0x05,0x14,0x70,0x88,0x15,0x00,0x00,0x57,0xe3,0x24,0x00,0x00,0x0a, -0x07,0x00,0x5c,0xe1,0x09,0x00,0x00,0x8a,0x10,0xa0,0x91,0xe5,0x18,0x80,0x87,0xe5, -0x00,0x00,0x5a,0xe3,0x06,0x00,0x00,0x0a,0x0a,0x00,0x5c,0xe1,0x10,0xa0,0x87,0x95, -0x18,0x70,0x8a,0x95,0x02,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0xfe,0xff,0xff,0xea,0x14,0x80,0x91,0xe5,0x00,0x00,0x58,0xe3,0x14,0x00,0x00,0x0a, -0x08,0x00,0x5c,0xe1,0x14,0x80,0x87,0x95,0x18,0x70,0x88,0x95,0x10,0x00,0x00,0x9a, -0xfe,0xff,0xff,0xea,0x14,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3,0x14,0xa0,0x81,0x12, -0xd2,0xff,0xff,0x0a,0x14,0x90,0x97,0xe5,0x00,0x00,0x59,0xe3,0x14,0xa0,0x87,0x12, -0x29,0x00,0x00,0x0a,0x09,0x70,0xa0,0xe1,0xf9,0xff,0xff,0xea,0x00,0x00,0x57,0xe3, -0x04,0x70,0x8a,0xe5,0xdd,0xff,0xff,0x1a,0x01,0x70,0x87,0xe2,0x17,0x5b,0xc5,0xe1, -0x04,0x50,0x83,0xe5,0x0f,0x00,0x56,0xe3,0x8d,0x00,0x00,0x8a,0x02,0x60,0x86,0xe0, -0x06,0x00,0x81,0xe0,0x03,0x60,0x86,0xe3,0x04,0xc0,0x90,0xe5,0x04,0x60,0x81,0xe5, -0x01,0xc0,0x8c,0xe3,0x04,0xc0,0x80,0xe5,0x08,0x00,0x91,0xe2,0xcc,0xfe,0xff,0x1a, -0xbc,0xfe,0xff,0xea,0xfe,0xff,0xff,0xea,0x01,0x0c,0x4c,0xe2,0x20,0x08,0xa0,0xe1, -0x08,0x00,0x00,0xe2,0x1c,0x10,0xa0,0xe1,0x0e,0xc0,0x60,0xe2,0x01,0x0a,0x41,0xe2, -0x20,0x08,0xa0,0xe1,0x04,0x00,0x00,0xe2,0x11,0x10,0xa0,0xe1,0x0c,0xc0,0x60,0xe0, -0x01,0x09,0x41,0xe2,0x20,0x08,0xa0,0xe1,0x02,0x00,0x00,0xe2,0x11,0x10,0xa0,0xe1, -0x0c,0x00,0x60,0xe0,0xa1,0x17,0x80,0xe0,0x07,0xc0,0x81,0xe2,0x32,0xcc,0xa0,0xe1, -0x01,0xc0,0x0c,0xe2,0x81,0xc0,0x8c,0xe0,0xdf,0xfe,0xff,0xea,0x10,0x90,0x97,0xe5, -0x00,0x00,0x59,0xe3,0x10,0xa0,0x87,0x12,0xd1,0xff,0xff,0x1a,0x0a,0x00,0x5c,0xe1, -0x00,0x90,0x8a,0x95,0xa1,0xff,0xff,0x9a,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x10,0x10,0x90,0xe5,0x00,0x00,0x51,0xe3,0x10,0xa0,0x80,0x12,0x29,0x00,0x00,0x1a, -0x00,0x00,0x57,0xe3,0x34,0x00,0x00,0x0a,0x1c,0xa0,0x90,0xe5,0x4a,0x90,0x8a,0xe2, -0x04,0xa0,0x8d,0xe5,0x09,0x91,0x83,0xe0,0x04,0xa0,0x99,0xe5,0x0a,0x00,0x50,0xe1, -0x26,0x00,0x00,0x0a,0x07,0x00,0x5c,0xe1,0x10,0x00,0x00,0x8a,0x10,0x50,0x97,0xe5, -0x05,0x00,0x50,0xe1,0x10,0x10,0x87,0x05,0x14,0x10,0x87,0x15,0x00,0x00,0x51,0xe3, -0x25,0x00,0x00,0x0a,0x01,0x00,0x5c,0xe1,0x09,0x00,0x00,0x8a,0x10,0x50,0x90,0xe5, -0x18,0x70,0x81,0xe5,0x00,0x00,0x55,0xe3,0x06,0x00,0x00,0x0a,0x05,0x00,0x5c,0xe1, -0x10,0x50,0x81,0x95,0x18,0x10,0x85,0x95,0x02,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea, -0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0x14,0x50,0x90,0xe5,0x00,0x00,0x55,0xe3, -0x15,0x00,0x00,0x0a,0x05,0x00,0x5c,0xe1,0x14,0x50,0x81,0x95,0x18,0x10,0x85,0x95, -0x11,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x14,0x10,0x90,0xe5,0x00,0x00,0x51,0xe3, -0x14,0xa0,0x80,0x12,0xd1,0xff,0xff,0x0a,0x14,0x90,0x91,0xe5,0x00,0x00,0x59,0xe3, -0x14,0xa0,0x81,0x12,0x78,0x00,0x00,0x0a,0x09,0x10,0xa0,0xe1,0xf9,0xff,0xff,0xea, -0x00,0x00,0x51,0xe3,0x04,0x10,0x89,0xe5,0xdd,0xff,0xff,0x1a,0x04,0x70,0x9d,0xe5, -0x01,0x10,0x81,0xe2,0x11,0x57,0xc5,0xe1,0x04,0x50,0x83,0xe5,0x0f,0x00,0x56,0xe3, -0x1e,0x00,0x00,0x9a,0x00,0x00,0x54,0xe3,0x03,0x50,0x82,0xe3,0x01,0x10,0x86,0xe3, -0x04,0x50,0x80,0xe5,0x04,0x10,0x8b,0xe5,0x06,0x60,0x8b,0xe7,0x11,0x00,0x00,0x0a, -0xa4,0x41,0xa0,0xe1,0x01,0x50,0xa0,0xe3,0x24,0x70,0x83,0xe2,0x14,0x10,0x93,0xe5, -0x15,0x54,0xa0,0xe1,0x84,0x41,0x87,0xe0,0x08,0x00,0x15,0xe1,0x08,0x80,0x85,0x01, -0x04,0x50,0xa0,0x01,0x00,0x80,0x83,0x05,0x02,0x00,0x00,0x0a,0x08,0x50,0x94,0xe5, -0x0c,0x00,0x55,0xe1,0x08,0x00,0x00,0x3a,0x08,0x10,0x84,0xe5,0x0c,0x10,0x85,0xe5, -0x08,0x50,0x81,0xe5,0x0c,0x40,0x81,0xe5,0x08,0x60,0x83,0xe5,0x14,0xb0,0x83,0xe5, -0x08,0x00,0x90,0xe2,0x52,0xfe,0xff,0x1a,0x63,0xfe,0xff,0xea,0xfe,0xff,0xff,0xea, -0x02,0x60,0x86,0xe0,0x06,0x10,0x80,0xe0,0x03,0x60,0x86,0xe3,0x04,0xc0,0x91,0xe5, -0x04,0x60,0x80,0xe5,0x01,0xc0,0x8c,0xe3,0x04,0xc0,0x81,0xe5,0xf3,0xff,0xff,0xea, -0xfe,0xff,0xff,0xea,0xa6,0x71,0xa0,0xe1,0x03,0xa0,0x82,0xe3,0x01,0x80,0x86,0xe3, -0x04,0xa0,0x81,0xe5,0x1f,0x00,0x57,0xe3,0x04,0x80,0x80,0xe5,0x06,0x60,0x80,0xe7, -0x12,0x00,0x00,0x8a,0x00,0x60,0x93,0xe5,0x01,0x80,0xa0,0xe3,0x18,0x87,0xa0,0xe1, -0x24,0x50,0x83,0xe2,0x87,0x51,0x85,0xe0,0x06,0x00,0x18,0xe1,0x06,0x80,0x88,0x01, -0x05,0x60,0xa0,0x01,0x00,0x80,0x83,0x05,0x02,0x00,0x00,0x0a,0x08,0x60,0x95,0xe5, -0x0c,0x00,0x56,0xe1,0x04,0x00,0x00,0x3a,0x08,0x00,0x85,0xe5,0x0c,0x00,0x86,0xe5, -0x08,0x60,0x80,0xe5,0x0c,0x50,0x80,0xe5,0x5e,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x26,0x74,0xb0,0xe1,0x16,0x00,0x00,0x0a,0x01,0x08,0x57,0xe3,0x1f,0x70,0xa0,0x23, -0x13,0x00,0x00,0x2a,0x01,0x8c,0x47,0xe2,0x28,0x88,0xa0,0xe1,0x08,0x80,0x08,0xe2, -0x17,0x78,0xa0,0xe1,0x0e,0xa0,0x68,0xe2,0x01,0x8a,0x47,0xe2,0x28,0x88,0xa0,0xe1, -0x04,0x80,0x08,0xe2,0x17,0x78,0xa0,0xe1,0x0a,0xa0,0x68,0xe0,0x01,0x89,0x47,0xe2, -0x28,0x88,0xa0,0xe1,0x02,0x80,0x08,0xe2,0x17,0x78,0xa0,0xe1,0x0a,0x80,0x68,0xe0, -0xa7,0x77,0x88,0xe0,0x07,0x80,0x87,0xe2,0x36,0x88,0xa0,0xe1,0x01,0x80,0x08,0xe2, -0x87,0x70,0x88,0xe0,0x01,0xa0,0xa0,0xe3,0x00,0x80,0xa0,0xe3,0x1a,0xa7,0xa0,0xe1, -0x1c,0x70,0x80,0xe5,0x14,0x80,0x80,0xe5,0x05,0x00,0x1a,0xe1,0x10,0x80,0x80,0xe5, -0x0e,0x00,0x00,0x1a,0x4a,0xc0,0x87,0xe2,0x05,0x50,0x8a,0xe1,0x0c,0xc1,0x83,0xe0, -0x04,0x50,0x83,0xe5,0x04,0x50,0x8c,0xe2,0x04,0x00,0x8c,0xe5,0x18,0x50,0x80,0xe5, -0x0c,0x00,0x80,0xe5,0x08,0x00,0x80,0xe5,0x32,0xff,0xff,0xea,0x10,0x90,0x91,0xe5, -0x00,0x00,0x59,0xe3,0x14,0x00,0x00,0x0a,0x10,0xa0,0x81,0xe2,0x81,0xff,0xff,0xea, -0x1f,0x00,0x57,0xe3,0x07,0x51,0x83,0xe0,0xa7,0x70,0xa0,0x11,0x2c,0x51,0x95,0xe5, -0x19,0x80,0x67,0x12,0x16,0x88,0xa0,0xe1,0x04,0xa0,0x95,0xe5,0xa8,0x7f,0xa0,0xe1, -0x88,0x80,0xa0,0xe1,0x04,0x70,0x87,0xe2,0x03,0xa0,0xca,0xe3,0x07,0x91,0x85,0xe0, -0x0a,0x00,0x56,0xe1,0x10,0x00,0x00,0x0a,0x07,0xa1,0x95,0xe7,0x00,0x00,0x5a,0xe3, -0x05,0x00,0x00,0x0a,0x0a,0x50,0xa0,0xe1,0xf2,0xff,0xff,0xea,0x0a,0x00,0x5c,0xe1, -0x00,0x90,0x8a,0x95,0x3d,0xff,0xff,0x9a,0xfe,0xff,0xff,0xea,0x09,0x00,0x5c,0xe1, -0x04,0x00,0x00,0x8a,0x07,0x01,0x85,0xe7,0x18,0x50,0x80,0xe5,0x0c,0x00,0x80,0xe5, -0x08,0x00,0x80,0xe5,0x0f,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0x05,0x00,0x5c,0xe1, -0x08,0x60,0x95,0xe5,0x08,0x00,0x00,0x8a,0x06,0x00,0x5c,0xe1,0x06,0x00,0x00,0x8a, -0x00,0xc0,0xa0,0xe3,0x0c,0x00,0x86,0xe5,0x08,0x00,0x85,0xe5,0x0c,0x50,0x80,0xe5, -0x08,0x60,0x80,0xe5,0x18,0xc0,0x80,0xe5,0x02,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x00,0x00,0x51,0xe3,0xf0,0x07,0x2d,0xe9,0x64,0x00,0x00,0x0a,0x10,0x40,0x90,0xe5, -0x08,0x30,0x41,0xe2,0x03,0x00,0x54,0xe1,0x00,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea, -0x04,0xc0,0x11,0xe5,0x02,0x00,0x1c,0xe3,0xfb,0xff,0xff,0x0a,0x01,0x00,0x1c,0xe3, -0x03,0xc0,0xcc,0xe3,0x0c,0x20,0x83,0xe0,0x92,0x00,0x00,0x1a,0x08,0x10,0x11,0xe5, -0x01,0x00,0x11,0xe3,0x4a,0x01,0x00,0x1a,0x03,0x30,0x61,0xe0,0x03,0x00,0x54,0xe1, -0xf1,0xff,0xff,0x8a,0x14,0x50,0x90,0xe5,0x01,0xc0,0x8c,0xe0,0x05,0x00,0x53,0xe1, -0x38,0x01,0x00,0x0a,0xa1,0x61,0xa0,0xe1,0x1f,0x00,0x56,0xe3,0xff,0x00,0x00,0x8a, -0x08,0x50,0x93,0xe5,0x0c,0x10,0x93,0xe5,0x01,0x00,0x55,0xe1,0xf5,0x00,0x00,0x0a, -0x24,0x70,0x80,0xe2,0x86,0x61,0x87,0xe0,0x05,0x00,0x56,0xe1,0x03,0x00,0x00,0x0a, -0x05,0x00,0x54,0xe1,0x43,0x01,0x00,0x8a,0x06,0x00,0x51,0xe1,0x01,0x00,0x00,0x0a, -0x01,0x00,0x54,0xe1,0x3f,0x01,0x00,0x8a,0x0c,0x10,0x85,0xe5,0x08,0x50,0x81,0xe5, -0x04,0x10,0x92,0xe5,0x02,0x00,0x53,0xe1,0xd7,0xff,0xff,0x2a,0x01,0x00,0x11,0xe3, -0xd5,0xff,0xff,0x0a,0x02,0x50,0x11,0xe2,0x30,0x01,0x00,0x1a,0x18,0x60,0x90,0xe5, -0x02,0x00,0x56,0xe1,0x3c,0x01,0x00,0x0a,0x14,0x80,0x90,0xe5,0x02,0x00,0x58,0xe1, -0x31,0x01,0x00,0x0a,0x03,0xa0,0xc1,0xe3,0xaa,0x51,0xa0,0xe1,0x1f,0x00,0x55,0xe3, -0x8a,0x00,0x00,0x8a,0x08,0x10,0x92,0xe5,0x0c,0x20,0x92,0xe5,0x02,0x00,0x51,0xe1, -0x81,0x00,0x00,0x0a,0x24,0x60,0x80,0xe2,0x85,0x51,0x86,0xe0,0x01,0x00,0x55,0xe1, -0x03,0x00,0x00,0x0a,0x01,0x00,0x54,0xe1,0x23,0x00,0x00,0x8a,0x05,0x00,0x52,0xe1, -0x01,0x00,0x00,0x0a,0x02,0x00,0x54,0xe1,0x1f,0x00,0x00,0x8a,0x0c,0x20,0x81,0xe5, -0x08,0x10,0x82,0xe5,0x0a,0xc0,0x8c,0xe0,0x03,0x00,0x58,0xe1,0x01,0x20,0x8c,0xe3, -0x0c,0xc0,0x83,0xe7,0x04,0x20,0x83,0xe5,0x08,0xc0,0x80,0x05,0x13,0x00,0x00,0x0a, -0xac,0x21,0xa0,0xe1,0x1f,0x00,0x52,0xe3,0x14,0x00,0x00,0x8a,0x00,0x10,0x90,0xe5, -0x01,0xc0,0xa0,0xe3,0x1c,0xc2,0xa0,0xe1,0x24,0x50,0x80,0xe2,0x82,0x21,0x85,0xe0, -0x01,0x00,0x1c,0xe1,0x01,0xc0,0x8c,0x01,0x02,0x10,0xa0,0x01,0x00,0xc0,0x80,0x05, -0x02,0x00,0x00,0x0a,0x08,0x10,0x92,0xe5,0x04,0x00,0x51,0xe1,0x05,0x00,0x00,0x3a, -0x08,0x30,0x82,0xe5,0x0c,0x30,0x81,0xe5,0x08,0x10,0x83,0xe5,0x0c,0x20,0x83,0xe5, -0xf0,0x07,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x2c,0x14,0xb0,0xe1,0x16,0x00,0x00,0x0a,0x01,0x08,0x51,0xe3,0x1f,0x10,0xa0,0x23, -0x13,0x00,0x00,0x2a,0x01,0x5c,0x41,0xe2,0x25,0x58,0xa0,0xe1,0x08,0x50,0x05,0xe2, -0x11,0x25,0xa0,0xe1,0x0e,0x10,0x65,0xe2,0x01,0x5a,0x42,0xe2,0x25,0x58,0xa0,0xe1, -0x04,0x50,0x05,0xe2,0x12,0x25,0xa0,0xe1,0x01,0x50,0x65,0xe0,0x01,0x19,0x42,0xe2, -0x21,0x18,0xa0,0xe1,0x02,0x10,0x01,0xe2,0x12,0x21,0xa0,0xe1,0x05,0x10,0x61,0xe0, -0xa2,0x27,0x81,0xe0,0x07,0x10,0x82,0xe2,0x3c,0x11,0xa0,0xe1,0x01,0x10,0x01,0xe2, -0x82,0x10,0x81,0xe0,0x04,0x60,0x90,0xe5,0x01,0x70,0xa0,0xe3,0x17,0x71,0xa0,0xe1, -0x00,0x50,0xa0,0xe3,0x1c,0x10,0x83,0xe5,0x06,0x00,0x17,0xe1,0x14,0x50,0x83,0xe5, -0x10,0x50,0x83,0xe5,0x23,0x00,0x00,0x0a,0x1f,0x00,0x51,0xe3,0x01,0x01,0x80,0xe0, -0xa1,0x10,0xa0,0x11,0x2c,0x21,0x90,0xe5,0x05,0x00,0xa0,0x01,0x19,0x00,0x61,0x12, -0x1c,0x00,0xa0,0xe1,0x04,0x50,0x92,0xe5,0xa0,0x1f,0xa0,0xe1,0x80,0x00,0xa0,0xe1, -0x04,0x10,0x81,0xe2,0x03,0x50,0xc5,0xe3,0x01,0x61,0x82,0xe0,0x0c,0x00,0x55,0xe1, -0x0e,0x00,0x00,0x0a,0x01,0x51,0x92,0xe7,0x00,0x00,0x55,0xe3,0x03,0x00,0x00,0x0a, -0x05,0x20,0xa0,0xe1,0xf2,0xff,0xff,0xea,0x04,0x10,0x92,0xe5,0x88,0xff,0xff,0xea, -0x06,0x00,0x54,0xe1,0x00,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x01,0x31,0x82,0xe7, -0x18,0x20,0x83,0xe5,0x0c,0x30,0x83,0xe5,0x08,0x30,0x83,0xe5,0xbb,0xff,0xff,0xea, -0x02,0x00,0x54,0xe1,0x08,0x10,0x92,0xe5,0x01,0x00,0x00,0x8a,0x01,0x00,0x54,0xe1, -0x0a,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x4a,0x20,0x81,0xe2,0x06,0x60,0x87,0xe1, -0x02,0x21,0x80,0xe0,0x04,0x60,0x80,0xe5,0x04,0x10,0x82,0xe2,0x04,0x30,0x82,0xe5, -0x18,0x10,0x83,0xe5,0x0c,0x30,0x83,0xe5,0x08,0x30,0x83,0xe5,0xab,0xff,0xff,0xea, -0x08,0x30,0x82,0xe5,0x0c,0x30,0x81,0xe5,0x0c,0x20,0x83,0xe5,0x00,0x20,0xa0,0xe3, -0x08,0x10,0x83,0xe5,0x18,0x20,0x83,0xe5,0xa4,0xff,0xff,0xea,0x00,0x20,0x90,0xe5, -0x01,0x10,0xa0,0xe3,0x11,0x55,0xc2,0xe1,0x00,0x50,0x80,0xe5,0x84,0xff,0xff,0xea, -0x0c,0x60,0x92,0xe5,0x18,0x50,0x92,0xe5,0x02,0x00,0x56,0xe1,0x27,0x00,0x00,0x0a, -0x08,0x70,0x92,0xe5,0x07,0x00,0x54,0xe1,0x0c,0x60,0x87,0x95,0x06,0x10,0xa0,0x91, -0x08,0x70,0x86,0x95,0x04,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x10,0x10,0x92,0xe5, -0x00,0x00,0x51,0xe3,0x10,0x60,0x82,0x12,0x20,0x00,0x00,0x1a,0x00,0x00,0x55,0xe3, -0x73,0xff,0xff,0x0a,0x1c,0x60,0x92,0xe5,0x4a,0x70,0x86,0xe2,0x07,0x71,0x80,0xe0, -0x04,0x90,0x97,0xe5,0x02,0x00,0x59,0xe1,0x1e,0x00,0x00,0x0a,0x05,0x00,0x54,0xe1, -0x10,0x00,0x00,0x8a,0x10,0x60,0x95,0xe5,0x02,0x00,0x56,0xe1,0x10,0x10,0x85,0x05, -0x14,0x10,0x85,0x15,0x00,0x00,0x51,0xe3,0x65,0xff,0xff,0x0a,0x01,0x00,0x54,0xe1, -0x09,0x00,0x00,0x8a,0x10,0x60,0x92,0xe5,0x18,0x50,0x81,0xe5,0x00,0x00,0x56,0xe3, -0x18,0x00,0x00,0x0a,0x06,0x00,0x54,0xe1,0x10,0x60,0x81,0x95,0x18,0x10,0x86,0x95, -0x14,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x14,0x10,0x92,0xe5,0x00,0x00,0x51,0xe3,0x14,0x60,0x82,0x12,0xda,0xff,0xff,0x0a, -0x14,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3,0x14,0x60,0x81,0x12,0x11,0x00,0x00,0x0a, -0x07,0x10,0xa0,0xe1,0xf9,0xff,0xff,0xea,0x00,0x00,0x51,0xe3,0x04,0x10,0x87,0xe5, -0xe5,0xff,0xff,0x1a,0x04,0x20,0x90,0xe5,0x01,0x10,0x81,0xe2,0x11,0x66,0xc2,0xe1, -0x04,0x60,0x80,0xe5,0x46,0xff,0xff,0xea,0x14,0x20,0x92,0xe5,0x00,0x00,0x52,0xe3, -0x43,0xff,0xff,0x0a,0x02,0x00,0x54,0xe1,0x14,0x20,0x81,0x95,0x18,0x10,0x82,0x95, -0x3f,0xff,0xff,0x9a,0xfe,0xff,0xff,0xea,0x10,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3, -0x10,0x60,0x81,0x12,0xe9,0xff,0xff,0x1a,0x06,0x00,0x54,0xe1,0x00,0x70,0x86,0x95, -0xc1,0xff,0xff,0x9a,0xfe,0xff,0xff,0xea,0x00,0x50,0x90,0xe5,0x01,0x70,0xa0,0xe3, -0x04,0x10,0x92,0xe5,0x17,0x66,0xc5,0xe1,0x00,0x60,0x80,0xe5,0x10,0xff,0xff,0xea, -0x0c,0x50,0x93,0xe5,0x18,0x60,0x93,0xe5,0x03,0x00,0x55,0xe1,0x27,0x00,0x00,0x0a, -0x08,0x70,0x93,0xe5,0x07,0x00,0x54,0xe1,0x0c,0x50,0x87,0x95,0x05,0x10,0xa0,0x91, -0x08,0x70,0x85,0x95,0x04,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0x10,0x10,0x95,0xe5, -0x00,0x00,0x51,0xe3,0x10,0x50,0x85,0x12,0x20,0x00,0x00,0x1a,0x00,0x00,0x56,0xe3, -0x74,0xff,0xff,0x0a,0x1c,0x50,0x93,0xe5,0x4a,0x70,0x85,0xe2,0x07,0x71,0x80,0xe0, -0x04,0x80,0x97,0xe5,0x03,0x00,0x58,0xe1,0x4f,0x00,0x00,0x0a,0x06,0x00,0x54,0xe1, -0x10,0x00,0x00,0x8a,0x10,0x50,0x96,0xe5,0x03,0x00,0x55,0xe1,0x10,0x10,0x86,0x05, -0x14,0x10,0x86,0x15,0x00,0x00,0x51,0xe3,0x66,0xff,0xff,0x0a,0x01,0x00,0x54,0xe1, -0x09,0x00,0x00,0x8a,0x10,0x50,0x93,0xe5,0x18,0x60,0x81,0xe5,0x00,0x00,0x55,0xe3, -0x4f,0x00,0x00,0x0a,0x05,0x00,0x54,0xe1,0x10,0x50,0x81,0x95,0x18,0x10,0x85,0x95, -0x4b,0x00,0x00,0x9a,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, -0x14,0x10,0x95,0xe5,0x00,0x00,0x51,0xe3,0x14,0x50,0x85,0x12,0xda,0xff,0xff,0x0a, -0x14,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3,0x14,0x50,0x81,0x12,0x3b,0x00,0x00,0x0a, -0x07,0x10,0xa0,0xe1,0xf9,0xff,0xff,0xea,0x04,0x10,0x92,0xe5,0x03,0x50,0x01,0xe2, -0x03,0x00,0x55,0xe3,0xd6,0xfe,0xff,0x1a,0x01,0x10,0xc1,0xe3,0x01,0x40,0x8c,0xe3, -0x08,0xc0,0x80,0xe5,0x04,0x10,0x82,0xe5,0x0c,0xc0,0x83,0xe7,0x04,0x40,0x83,0xe5, -0x0a,0xff,0xff,0xea,0xac,0x31,0x90,0xe5,0x01,0x10,0xc1,0xe3,0x10,0x30,0x43,0xe2, -0x03,0x30,0x61,0xe0,0x03,0xc0,0x6c,0xe0,0xac,0xc1,0x80,0xe5,0x03,0xff,0xff,0xea, -0x01,0x10,0xc1,0xe3,0x01,0x50,0x8c,0xe3,0x04,0x10,0x82,0xe5,0x0c,0xc0,0x83,0xe7, -0x04,0x50,0x83,0xe5,0xe9,0xfe,0xff,0xea,0xfe,0xff,0xff,0xea,0x08,0x20,0x90,0xe5, -0x14,0x30,0x80,0xe5,0x02,0xc0,0x8c,0xe0,0x01,0x20,0x8c,0xe3,0x08,0xc0,0x80,0xe5, -0x04,0x20,0x83,0xe5,0x0c,0xc0,0x83,0xe7,0xf4,0xfe,0xff,0xea,0x0c,0x10,0x90,0xe5, -0x14,0x20,0x90,0xe5,0x18,0x30,0x80,0xe5,0x01,0xc0,0x8c,0xe0,0x03,0x00,0x52,0xe1, -0x01,0x20,0x8c,0xe3,0x0c,0xc0,0x80,0xe5,0x04,0x20,0x83,0xe5,0x1c,0x30,0x90,0xe5, -0x14,0x50,0x80,0x05,0x08,0x50,0x80,0x05,0x03,0x00,0x5c,0xe1,0xe7,0xfe,0xff,0x9a, -0x00,0x10,0xa0,0xe3,0xf0,0x07,0xbd,0xe8,0x93,0xfa,0xff,0xea,0x00,0x00,0x51,0xe3, -0x04,0x10,0x87,0xe5,0xb4,0xff,0xff,0x1a,0x04,0x60,0x90,0xe5,0x01,0x70,0xa0,0xe3, -0x04,0x10,0x92,0xe5,0x17,0x55,0xc6,0xe1,0x04,0x50,0x80,0xe5,0xa0,0xfe,0xff,0xea, -0x10,0x70,0x91,0xe5,0x00,0x00,0x57,0xe3,0x0a,0x00,0x00,0x0a,0x10,0x50,0x81,0xe2, -0xbe,0xff,0xff,0xea,0x14,0x50,0x93,0xe5,0x00,0x00,0x55,0xe3,0x0d,0xff,0xff,0x0a, -0x05,0x00,0x54,0xe1,0x14,0x50,0x81,0x95,0x18,0x10,0x85,0x95,0x04,0x10,0x92,0x95, -0x93,0xfe,0xff,0x9a,0xfe,0xff,0xff,0xea,0x05,0x00,0x54,0xe1,0x00,0x70,0x85,0x95, -0x8d,0xff,0xff,0x9a,0xfe,0xff,0xff,0xea,0x08,0x00,0x51,0xe3,0xf0,0x47,0x2d,0xe9, -0x00,0x40,0xa0,0xe1,0x02,0x00,0x00,0x8a,0x02,0x10,0xa0,0xe1,0xf0,0x47,0xbd,0xe8, -0xbb,0xfb,0xff,0xea,0x0f,0x00,0x51,0xe3,0x4f,0x30,0xe0,0x93,0x10,0x50,0xa0,0x93, -0x0f,0x00,0x00,0x9a,0x01,0x30,0x41,0xe2,0x01,0x00,0x13,0xe1,0x3f,0x30,0xe0,0x03, -0x01,0x50,0xa0,0x01,0x03,0x30,0x61,0x00,0x09,0x00,0x00,0x0a,0x10,0x00,0x51,0xe3, -0x01,0x50,0xa0,0x01,0x4f,0x30,0xe0,0x03,0x05,0x00,0x00,0x0a,0x10,0x50,0xa0,0xe3, -0x85,0x50,0xa0,0xe1,0x05,0x00,0x51,0xe1,0xfc,0xff,0xff,0x8a,0x3f,0x30,0xe0,0xe3, -0x03,0x30,0x65,0xe0,0x03,0x00,0x52,0xe1,0x00,0x00,0xa0,0x23,0xf0,0x87,0xbd,0x28, -0x0a,0x00,0x52,0xe3,0x0c,0x10,0x85,0xe2,0x0b,0x20,0x82,0x82,0x10,0x70,0xa0,0x93, -0x07,0x70,0xc2,0x83,0x04,0x00,0xa0,0xe1,0x07,0x10,0x81,0xe0,0x9c,0xfb,0xff,0xeb, -0x00,0x80,0x50,0xe2,0x4f,0x00,0x00,0x0a,0x05,0x10,0xa0,0xe1,0x08,0x60,0x48,0xe2, -0x8c,0xf8,0xff,0xeb,0x00,0x00,0x51,0xe3,0x04,0x20,0x96,0x05,0x14,0x00,0x00,0x0a, -0x01,0x20,0x45,0xe2,0x00,0x30,0x65,0xe2,0x02,0x20,0x88,0xe0,0x03,0x30,0x02,0xe0, -0x04,0x20,0x96,0xe5,0x08,0x30,0x43,0xe2,0x03,0x00,0x66,0xe0,0x0f,0x00,0x50,0xe3, -0x05,0x30,0x83,0x90,0x03,0x00,0x66,0x90,0x01,0x10,0x12,0xe2,0x03,0x20,0xc2,0xe3, -0x02,0x20,0x60,0xe0,0x25,0x00,0x00,0x1a,0x08,0xc0,0x18,0xe5,0x01,0x00,0x1c,0xe3, -0x22,0x00,0x00,0x0a,0x03,0x60,0xa0,0xe1,0x0c,0x00,0x80,0xe0,0x02,0x20,0x82,0xe3, -0x05,0x00,0x83,0xe8,0x01,0x50,0x12,0xe2,0x02,0x00,0x00,0x1a,0x00,0x30,0x96,0xe5, -0x01,0x00,0x13,0xe3,0x10,0x00,0x00,0x1a,0x03,0x20,0xc2,0xe3,0x10,0x30,0x87,0xe2, -0x03,0x00,0x52,0xe1,0x00,0x50,0xa0,0x93,0x0b,0x00,0x00,0x9a,0x07,0x30,0x86,0xe0, -0x02,0x20,0x67,0xe0,0x02,0x70,0x87,0xe3,0x02,0x00,0x83,0xe0,0x05,0x50,0x87,0xe1, -0x03,0x20,0x82,0xe3,0x04,0x50,0x86,0xe5,0x08,0x50,0x83,0xe2,0x04,0x20,0x83,0xe5, -0x04,0x30,0x90,0xe5,0x01,0x30,0x83,0xe3,0x04,0x30,0x80,0xe5,0x00,0x00,0x51,0xe3, -0x04,0x00,0xa0,0x11,0x05,0xfe,0xff,0x1b,0x00,0x00,0x55,0xe3,0x04,0x00,0xa0,0x11, -0x05,0x10,0xa0,0x11,0x01,0xfe,0xff,0x1b,0x08,0x00,0x86,0xe2,0xf0,0x87,0xbd,0xe8, -0x04,0xa0,0x93,0xe5,0x08,0x10,0xa0,0xe1,0x02,0x50,0x83,0xe0,0x00,0xc0,0x86,0xe0, -0x01,0x80,0x0a,0xe2,0x02,0x80,0x88,0xe3,0x02,0x20,0x88,0xe1,0x04,0x20,0x83,0xe5, -0x04,0x20,0x95,0xe5,0x01,0x20,0x82,0xe3,0x04,0x20,0x85,0xe5,0x04,0x20,0x96,0xe5, -0x01,0x20,0x02,0xe2,0x02,0x20,0x82,0xe3,0x00,0x00,0x82,0xe1,0x04,0x00,0x86,0xe5, -0x03,0x60,0xa0,0xe1,0x04,0x20,0x9c,0xe5,0x01,0x20,0x82,0xe3,0x04,0x20,0x8c,0xe5, -0x04,0x20,0x93,0xe5,0xca,0xff,0xff,0xea,0x08,0x00,0xa0,0xe1,0xf0,0x87,0xbd,0xe8, -0x10,0x30,0x9f,0xe5,0x10,0x20,0x9f,0xe5,0x03,0x30,0x8f,0xe0,0x02,0x00,0x93,0xe7, -0x04,0x00,0x40,0xe2,0x1e,0xff,0x2f,0xe1,0xd8,0x12,0x00,0x00,0x5c,0x00,0x00,0x00, -0x10,0x40,0x2d,0xe9,0x40,0x40,0x9f,0xe5,0x40,0x30,0x9f,0xe5,0x04,0x40,0x8f,0xe0, -0x03,0x30,0x94,0xe7,0x00,0x20,0x93,0xe5,0x02,0x00,0x52,0xe3,0x04,0x00,0x93,0x05, -0x10,0x80,0xbd,0x08,0x6e,0xf8,0xff,0xeb,0x01,0x00,0x40,0xe2,0x06,0x00,0x50,0xe3, -0x01,0x00,0x00,0x9a,0x01,0x00,0xa0,0xe3,0x10,0x80,0xbd,0xe8,0x10,0x30,0x9f,0xe5, -0x03,0x40,0x84,0xe0,0x00,0x01,0x94,0xe7,0x10,0x80,0xbd,0xe8,0xb4,0x12,0x00,0x00, -0x88,0x00,0x00,0x00,0xd0,0xf3,0xff,0xff,0x2a,0x74,0x68,0x69,0x73,0x20,0x69,0x73, -0x20,0x61,0x20,0x74,0x65,0x73,0x74,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xee,0xee,0xee, -0xee,0xee,0xee,0xee,0xee,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfc,0x7e,0xbf,0xdf,0xef,0xf7,0xfb,0xfd, -0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa, -0xaa,0xaa,0xaa,0xaa,0xaa,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xfe,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd, -0xfc,0x7e,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xee,0xee,0xee, -0xee,0xee,0xee,0xee,0xee,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfc,0x7e,0xbf,0xdf,0xef,0xf7,0xfb,0xfd, -0x7e,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, -0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, -0x09,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, -0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x09,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, -0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x92,0x52,0x0f,0xb0,0xe0,0x8a,0x9f, -0x0f,0x61,0x6b,0xe3,0xc1,0xae,0xb0,0x7c,0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e, -0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0xa3,0x9e,0x76,0xab,0xab,0x94,0x7a,0xa5, -0xbb,0x86,0x6e,0xb3,0xa3,0x9c,0x72,0xad,0x7f,0xde,0xe3,0xa1,0xd4,0x4a,0x99,0x04, -0x6f,0xcc,0xf7,0xb7,0xcc,0x50,0x85,0x1a,0x28,0x49,0x41,0xea,0xfc,0x03,0xd8,0xee, -0x93,0xcf,0x2f,0x59,0x5f,0x9f,0xaa,0x43,0xfb,0xe5,0x5b,0x25,0x07,0xe6,0x83,0xcb, -0x94,0x29,0xac,0x92,0xcb,0xb6,0x06,0xd1,0xa5,0x8a,0x65,0x3a,0xa2,0x6c,0xe6,0xf1, -0x36,0x45,0x4a,0x63,0xfd,0xf3,0x4c,0xb2,0x88,0xa3,0x52,0x6e,0x2a,0xcf,0xb4,0x9f, -0x1c,0x8a,0xfe,0xfc,0xe1,0x79,0xb2,0x4e,0x7e,0x94,0x7d,0x96,0x54,0x5b,0xc9,0x09, -0x48,0xd1,0x37,0xf5,0xa9,0xa8,0x85,0xbb,0x3c,0x03,0x97,0x45,0x68,0x58,0x5e,0x4c, -0x20,0x89,0x69,0xb9,0x89,0x21,0xec,0x02,0xda,0xcd,0xe0,0xe2,0xb2,0x95,0xbe,0xae, -0x92,0x1c,0xd7,0x17,0x1b,0x3d,0x3b,0x15,0xcb,0x2f,0xb9,0x4d,0x79,0xba,0x07,0xe3, -0xeb,0xa6,0xd0,0xf4,0xf0,0x9b,0xeb,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00, -0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00, -0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0xe3,0xc5,0x07, -0x61,0x23,0xa2,0x03,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0b,0x00,0x00,0x00,0x21,0x43,0x61,0x00,0x21,0xc3,0x20,0x07,0x00,0x00,0x00,0x00, -0x21,0x83,0x01,0x00,0x21,0x03,0x21,0x00,0x21,0x63,0x41,0x00,0x00,0x00,0x00,0x00, -0x21,0xa3,0xc4,0x02,0x21,0xc3,0xa4,0x02,0x21,0xe3,0x44,0x07,0x21,0xa3,0x4d,0x0d, -0x21,0xc3,0x41,0x03,0x21,0xa3,0x61,0x03,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x61,0x63,0x41,0x00,0x61,0x43,0x61,0x00,0x00,0x00,0x00,0x00, -0x0f,0x00,0x00,0x00,0x61,0x03,0x06,0x04,0x00,0x00,0x00,0x00,0x61,0x03,0x21,0x00, -0x61,0x03,0x82,0x03,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0f,0x00,0x00,0x00,0x41,0x23,0xa2,0x03,0x41,0x03,0x82,0x03,0x41,0x03,0x06,0x04, -0x41,0x43,0xe5,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x41,0xc3,0xa5,0x07, -0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1f,0x00,0x00,0x00,0x61,0xc3,0xa5,0x07,0x61,0x23,0xa2,0x03,0x00,0x00,0x00,0x00, -0x17,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, -0x41,0xa3,0x45,0x01,0x61,0x63,0x05,0x01,0x61,0xe3,0x47,0x05,0x61,0xc3,0x67,0x05, -0x61,0xa3,0x87,0x05,0x61,0x83,0xa7,0x05,0x61,0x63,0xc7,0x05,0x41,0x83,0x01,0x00, -0x41,0x03,0x21,0x00,0x41,0x63,0x41,0x00,0x41,0x43,0x61,0x00,0x41,0xc3,0x20,0x07, -0x41,0xe3,0xc5,0x07,0x00,0x00,0x00,0x00,0x41,0x23,0x85,0x02,0x41,0x03,0x65,0x02, -0x41,0x03,0xc3,0x06,0x41,0x23,0xe3,0x06,0x41,0x43,0x06,0x02,0x00,0x00,0x00,0x00, -0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x64,0x00,0x00,0x00, -0xe8,0x03,0x00,0x00,0x10,0x27,0x00,0x00,0xa0,0x86,0x01,0x00,0x40,0x42,0x0f,0x00, -0x80,0x96,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x00,0x80,0x80,0xff,0x00, -0x80,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x1a,0x00,0x10,0x00,0x09,0x00, -0x10,0x00,0x02,0x00,0x10,0x00,0x02,0x00,0x10,0x00,0x1a,0x00,0x10,0x00,0x1a,0x00, -0x10,0x00,0x1a,0x00,0x10,0x00,0x1b,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, -0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x14,0x00,0x00,0x00, -0x19,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x28,0x00,0x00,0x00, -0x2d,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x3c,0x00,0x00,0x00, -0x46,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x69,0x6e,0x6d,0x75,0x78,0x20,0x63, -0x68,0x61,0x6e,0x67,0x65,0x73,0x20,0x74,0x6f,0x20,0x62,0x65,0x20,0x61,0x70,0x70, -0x6c,0x69,0x65,0x64,0x20,0x69,0x6e,0x20,0x62,0x6f,0x6f,0x74,0x6c,0x6f,0x61,0x64, -0x65,0x72,0x20,0x77,0x61,0x79,0x0a,0x00,0x42,0x6f,0x6f,0x74,0x6c,0x6f,0x61,0x64, -0x65,0x72,0x20,0x53,0x74,0x61,0x72,0x74,0x20,0x61,0x74,0x3a,0x25,0x64,0x20,0x6d, -0x73,0x0a,0x00,0x00,0x04,0x40,0x00,0x60,0x04,0x41,0x00,0x60,0x04,0x42,0x00,0x60, -0x04,0x43,0x00,0x60,0x04,0x44,0x00,0x60,0x38,0x40,0x00,0x60,0x38,0x41,0x00,0x60, -0x38,0x42,0x00,0x60,0x38,0x43,0x00,0x60,0x38,0x44,0x00,0x60,0x34,0x40,0x00,0x60, -0x34,0x41,0x00,0x60,0x34,0x42,0x00,0x60,0x34,0x43,0x00,0x60,0x34,0x44,0x00,0x60, -0x25,0x73,0x3a,0x20,0x57,0x41,0x52,0x4e,0x49,0x4e,0x47,0x3a,0x20,0x63,0x61,0x63, -0x68,0x65,0x64,0x20,0x61,0x63,0x63,0x65,0x73,0x73,0x20,0x74,0x6f,0x20,0x4d,0x4d, -0x49,0x4f,0x20,0x28,0x25,0x78,0x2d,0x25,0x78,0x29,0x0a,0x00,0x54,0x33,0x30,0x50, -0x68,0x79,0x73,0x69,0x63,0x61,0x6c,0x4d,0x65,0x6d,0x4d,0x61,0x70,0x00,0x00,0x00, -0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66, -0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, -0x77,0x78,0x79,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x2c,0x55,0x02,0x40,0x94,0x54,0x02,0x40,0x98,0x54,0x02,0x40,0x28,0x55,0x02,0x40, -0x9c,0x54,0x02,0x40,0x24,0x55,0x02,0x40,0xa4,0x54,0x02,0x40,0xac,0x54,0x02,0x40, -0xb0,0x54,0x02,0x40,0xb8,0x54,0x02,0x40,0xc0,0x54,0x02,0x40,0xc8,0x54,0x02,0x40, -0xd0,0x54,0x02,0x40,0xd8,0x54,0x02,0x40,0xe0,0x54,0x02,0x40,0xe8,0x54,0x02,0x40, -0xf0,0x54,0x02,0x40,0xf8,0x54,0x02,0x40,0x00,0x55,0x02,0x40,0x08,0x55,0x02,0x40, -0x0c,0x55,0x02,0x40,0x14,0x55,0x02,0x40,0x1c,0x55,0x02,0x40,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0xd4,0x84,0x02,0x40,0x38,0x84,0x02,0x40,0x00,0xe0,0x03,0x40, -0x00,0x00,0x00,0x00,0xc8,0xd4,0x02,0x40,0x00,0x00,0x00,0x00,0xe8,0x84,0x02,0x40, -0xec,0x84,0x02,0x40,0xdc,0xfe,0x02,0x40,0x70,0x87,0x02,0x40,0xe0,0x2b,0x02,0x40, -0xe4,0xd4,0x02,0x40,0x94,0xfe,0x02,0x40,0x7c,0x93,0x02,0x40,0xc8,0x84,0x02,0x40, -0xfc,0xd4,0x02,0x40,0x00,0xd5,0x02,0x40,0x7c,0x91,0x02,0x40,0xd0,0x84,0x02,0x40, -0x00,0x00,0x00,0x00,0x00,0xe4,0x03,0x40,0xcd,0x84,0x02,0x40,0xb8,0xd5,0x02,0x40, -0xe4,0xfe,0x02,0x40,0xb8,0xdd,0x02,0x40,0x00,0x00,0x00,0x00,0xb8,0xfd,0x02,0x40, -0x68,0x32,0x02,0x40,0xc0,0xfd,0x02,0x40,0xe4,0xfe,0x02,0x40,0x4c,0x28,0x02,0x40, -0x64,0x74,0x02,0x40,0x3c,0x28,0x02,0x40,0xd8,0x84,0x02,0x40,0x78,0xfe,0x02,0x40, -0x00,0x80,0x00,0x40,0xe0,0xfe,0x02,0x40,0xcc,0x84,0x02,0x40,0x00,0x00,0x00,0x40, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0xc5,0x01,0x40, -0x64,0xc6,0x01,0x40,0xb4,0xc6,0x01,0x40,0x00,0xbd,0x01,0x40,0x24,0xc8,0x01,0x40, -0xe0,0xc6,0x01,0x40,0x68,0xcd,0x01,0x40,0xe0,0x1d,0x02,0x40,0x80,0x1e,0x02,0x40, -0xcc,0x1e,0x02,0x40,0x08,0x1f,0x02,0x40,0x14,0x20,0x02,0x40,0x74,0x20,0x02,0x40, -0x7c,0x20,0x02,0x40,0xa0,0x20,0x02,0x40,0x18,0x21,0x02,0x40,0x60,0x21,0x02,0x40, -0x74,0x21,0x02,0x40,0x5c,0x22,0x02,0x40,0x58,0x25,0x02,0x40,0x4c,0x26,0x02,0x40, -0xdc,0xf8,0x01,0x40,0x7c,0xf9,0x01,0x40,0xbc,0xf9,0x01,0x40,0x4c,0xff,0x01,0x40, -0xe8,0xf9,0x01,0x40,0xbc,0xfc,0x01,0x40,0xf0,0xfe,0x01,0x40,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x28,0xc5,0x01,0x40,0x64,0xc6,0x01,0x40,0xb4,0xc6,0x01,0x40,0x00,0xbd,0x01,0x40, -0x24,0xc8,0x01,0x40,0xe0,0xc6,0x01,0x40,0x68,0xcd,0x01,0x40,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1a,0x03,0x4e,0x00, -0x56,0x00,0x49,0x00,0x44,0x00,0x49,0x00,0x41,0x00,0x20,0x00,0x43,0x00,0x6f,0x00, -0x72,0x00,0x70,0x00,0x2e,0x00,0x00,0x00,0x0c,0x03,0x30,0x00,0x30,0x00,0x30,0x00, -0x30,0x00,0x30,0x00,0x0a,0x06,0x00,0x02,0xff,0xff,0xff,0x40,0x01,0x00,0x00,0x00, -0x09,0x02,0x20,0x00,0x01,0x01,0x00,0xc0,0xfa,0x09,0x04,0x00,0x00,0x02,0xff,0xff, -0xff,0x00,0x07,0x05,0x81,0x02,0x40,0x00,0x00,0x07,0x05,0x01,0x02,0x40,0x00,0x00, -0x09,0x07,0x20,0x00,0x01,0x01,0x00,0xc0,0x10,0x09,0x04,0x00,0x00,0x02,0x08,0x06, -0x50,0x00,0x07,0x05,0x81,0x02,0x40,0x00,0x00,0x07,0x05,0x01,0x02,0x40,0x00,0x00, -0x12,0x01,0x00,0x02,0x00,0x00,0x00,0x40,0x55,0x09,0x15,0x71,0x01,0x01,0x01,0x02, -0x03,0x01,0x00,0x00,0x04,0x03,0x09,0x04,0x08,0x03,0x41,0x00,0x50,0x00,0x58,0x00, -0x0c,0x03,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x01,0x00,0x00,0x00, -0x1a,0x03,0x4e,0x00,0x56,0x00,0x49,0x00,0x44,0x00,0x49,0x00,0x41,0x00,0x20,0x00, -0x43,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x2e,0x00,0x00,0x00,0x0a,0x06,0x00,0x02, -0xff,0xff,0xff,0x40,0x01,0x00,0x00,0x00,0x09,0x07,0x20,0x00,0x01,0x01,0x00,0xc0, -0x10,0x09,0x04,0x00,0x00,0x02,0x08,0x06,0x50,0x00,0x07,0x05,0x81,0x02,0x40,0x00, -0x00,0x07,0x05,0x01,0x02,0x40,0x00,0x00,0x12,0x01,0x00,0x02,0x00,0x00,0x00,0x40, -0x55,0x09,0x15,0x71,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x00,0x09,0x02,0x20,0x00, -0x01,0x01,0x00,0xc0,0xfa,0x09,0x04,0x00,0x00,0x02,0xff,0xff,0xff,0x00,0x07,0x05, -0x81,0x02,0x40,0x00,0x00,0x07,0x05,0x01,0x02,0x40,0x00,0x00,0x04,0x03,0x09,0x04, -0x08,0x03,0x41,0x00,0x50,0x00,0x58,0x00,0x0c,0x03,0x30,0x00,0x30,0x00,0x30,0x00, -0x30,0x00,0x30,0x00,0x01,0x00,0x00,0x00,0x1a,0x03,0x4e,0x00,0x56,0x00,0x49,0x00, -0x44,0x00,0x49,0x00,0x41,0x00,0x20,0x00,0x43,0x00,0x6f,0x00,0x72,0x00,0x70,0x00, -0x2e,0x00,0x00,0x00,0x0a,0x06,0x00,0x02,0xff,0xff,0xff,0x40,0x01,0x00,0x00,0x00, -0x09,0x07,0x20,0x00,0x01,0x01,0x00,0xc0,0x10,0x09,0x04,0x00,0x00,0x02,0x08,0x06, -0x50,0x00,0x07,0x05,0x81,0x02,0x40,0x00,0x00,0x07,0x05,0x01,0x02,0x40,0x00,0x00, -0x12,0x01,0x00,0x02,0x00,0x00,0x00,0x40,0x55,0x09,0x15,0x71,0x01,0x01,0x01,0x02, -0x03,0x01,0x00,0x00,0x09,0x02,0x20,0x00,0x01,0x01,0x00,0xc0,0xfa,0x09,0x04,0x00, -0x00,0x02,0xff,0xff,0xff,0x00,0x07,0x05,0x81,0x02,0x40,0x00,0x00,0x07,0x05,0x01, -0x02,0x40,0x00,0x00,0x04,0x03,0x09,0x04,0x08,0x03,0x41,0x00,0x50,0x00,0x58,0x00, -0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x71,0x02,0x40,0x10,0x72,0x02,0x40, -0x88,0x71,0x02,0x40,0x9c,0x71,0x02,0x40,0x9c,0x71,0x02,0x40,0x10,0x72,0x02,0x40, -0xc0,0x2f,0x02,0x40,0x68,0x30,0x02,0x40,0xc4,0x2f,0x02,0x40,0xa8,0x4f,0x02,0x40, -0xc8,0x2f,0x02,0x40,0x5c,0x30,0x02,0x40,0xd0,0x2f,0x02,0x40,0xd8,0x2f,0x02,0x40, -0xdc,0x2f,0x02,0x40,0xe4,0x2f,0x02,0x40,0xec,0x2f,0x02,0x40,0xf4,0x2f,0x02,0x40, -0xfc,0x2f,0x02,0x40,0x04,0x30,0x02,0x40,0x0c,0x30,0x02,0x40,0x14,0x30,0x02,0x40, -0x1c,0x30,0x02,0x40,0x24,0x30,0x02,0x40,0x2c,0x30,0x02,0x40,0x3c,0x30,0x02,0x40, -0x34,0x30,0x02,0x40,0x40,0x30,0x02,0x40,0x48,0x30,0x02,0x40,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xa5,0xa5,0x00,0x00, -0xa5,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xa5,0x00,0x00,0x00,0xa5,0x00,0x00,0x00, -0xa5,0x00,0x00,0x00,0xa5,0x00,0x00,0x00,0xa5,0x00,0x00,0x00,0xa5,0x00,0x00,0x00, -0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x01,0x05,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x04,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, -0x00,0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x00,0x00,0x00,0x00,0x02,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x03,0x07,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x00,0x00,0x08,0x3f, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, -0x00,0x00,0x09,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x07,0x00,0x00,0x00,0x00,0x00,0x0c,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x19,0x1d,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x20,0x08, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00, -0x01,0x00,0x21,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x47,0x00,0x00,0x00,0x02,0x00,0x22,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x03,0x00,0x23,0x08,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x24,0x06, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x00, -0x01,0x00,0x25,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x17,0x00,0x00,0x00,0x02,0x00,0x29,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x03,0x00,0x2a,0x05,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x04,0x00,0x37,0x08, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, -0x00,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1c,0x00,0x00,0x00,0x00,0x01,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x02,0x0b,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x03,0x0c,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, -0x00,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1c,0x00,0x00,0x00,0x00,0x05,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x61,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x00,0x00,0x00, -0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x47,0x00,0x00,0x00,0x05,0x00,0x57,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x06,0x00,0x59,0x08,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x07,0x00,0x7d,0x08, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00, -0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; diff --git a/kourou/libs/tegrarcm/nv3p.c b/kourou/libs/tegrarcm/nv3p.c deleted file mode 100644 index a237f6a..0000000 --- a/kourou/libs/tegrarcm/nv3p.c +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include - -#include "nv3p.h" -#include "usb.h" -#include "debug.h" - -/* nv3p command packet format */ -/*|------------32 bits--------------|*/ -/*************************************/ -/* NV3P_VERSION */ -/*-----------------------------------*/ -/* NV3P_PACKET_TYPE_CMD */ -/*-----------------------------------*/ -/* sequence no */ -/*-----------------------------------*/ -/* length of command arguments */ -/*-----------------------------------*/ -/* command, one of: */ -/* NV3P_CMD_GET_PLATFORM_INFO */ -/* NV3P_CMD_DL_BCT */ -/* NV3P_CMD_DL_BL */ -/* NV3P_CMD_STATUS */ -/*-----------------------------------*/ -/* command arguments */ -/* . */ -/* . */ -/* . */ -/*-----------------------------------*/ -/* checksum */ -/*-----------------------------------*/ - -/* nv3p ack packet format */ -/*|------------32 bits--------------|*/ -/*************************************/ -/* NV3P_VERSION */ -/*-----------------------------------*/ -/* NV3P_PACKET_TYPE_ACK */ -/*-----------------------------------*/ -/* sequence no */ -/*-----------------------------------*/ -/* checksum */ -/*-----------------------------------*/ - -/* nv3p nack packet format */ -/*|------------32 bits--------------|*/ -/*************************************/ -/* NV3P_VERSION */ -/*-----------------------------------*/ -/* NV3P_PACKET_TYPE_NACK */ -/*-----------------------------------*/ -/* sequence no */ -/*-----------------------------------*/ -/* nack code */ -/*-----------------------------------*/ -/* checksum */ -/*-----------------------------------*/ - -/* nv3p data packet format */ -/*|------------32 bits--------------|*/ -/*************************************/ -/* NV3P_VERSION */ -/*-----------------------------------*/ -/* NV3P_PACKET_TYPE_DATA */ -/*-----------------------------------*/ -/* sequence no */ -/*-----------------------------------*/ -/* length of data */ -/*-----------------------------------*/ -/* data */ -/* . */ -/* . */ -/* . */ -/*-----------------------------------*/ -/* checksum */ -/*-----------------------------------*/ - -typedef struct nv3p_state { - usb_device_t *usb; - uint32_t sequence; - uint32_t recv_sequence; - - // for partial reads - uint32_t bytes_remaining; - uint32_t recv_checksum; - - // the last nack code - uint32_t last_nack; -} nv3p_state_t; - -/* - * double the currently-largest command size, just to have some wiggle-room - * (updates to commands without fixing this on accident, etc.) - */ -#define NV3P_MAX_COMMAND_SIZE (2 << 12) - -#define NV3P_MAX_ACK_SIZE \ - NV3P_PACKET_SIZE_BASIC + \ - NV3P_PACKET_SIZE_NACK + \ - NV3P_PACKET_SIZE_FOOTER - -unsigned char s_buffer[NV3P_MAX_COMMAND_SIZE]; -unsigned char s_args[NV3P_MAX_COMMAND_SIZE]; // handed out to clients - -#define WRITE64( packet, data ) \ - do { \ - (packet)[0] = (uint8_t)((uint64_t)(data)) & 0xff; \ - (packet)[1] = (uint8_t)(((uint64_t)(data)) >> 8) & 0xff; \ - (packet)[2] = (uint8_t)(((uint64_t)(data)) >> 16) & 0xff; \ - (packet)[3] = (uint8_t)(((uint64_t)(data)) >> 24) & 0xff; \ - (packet)[4] = (uint8_t)(((uint64_t)(data)) >> 32) & 0xff; \ - (packet)[5] = (uint8_t)(((uint64_t)(data)) >> 40) & 0xff; \ - (packet)[6] = (uint8_t)(((uint64_t)(data)) >> 48) & 0xff; \ - (packet)[7] = (uint8_t)(((uint64_t)(data)) >> 56) & 0xff; \ - (packet) += 8; \ - } while( 0 ) - -#define WRITE32( packet, data ) \ - do { \ - (packet)[0] = (data) & 0xff; \ - (packet)[1] = ((data) >> 8) & 0xff; \ - (packet)[2] = ((data) >> 16) & 0xff; \ - (packet)[3] = ((data) >> 24) & 0xff; \ - (packet) += 4; \ - } while( 0 ) - -#define WRITE8( packet, data ) \ - do { \ - (packet)[0] = (data) & 0xff; \ - (packet) += 1; \ - } while( 0 ) - -#define READ64( packet, data ) \ - do { \ - (data) = (uint64_t)((packet)[0] \ - | ((uint64_t)((packet)[1]) << 8) \ - | ((uint64_t)((packet)[2]) << 16) \ - | ((uint64_t)((packet)[3]) << 24) \ - | ((uint64_t)((packet)[4]) << 32) \ - | ((uint64_t)((packet)[5]) << 40) \ - | ((uint64_t)((packet)[6]) << 48) \ - | ((uint64_t)((packet)[7]) << 56)); \ - (packet) += 8; \ - } while( 0 ) - -#define READ32( packet, data ) \ - do { \ - (data) = (uint32_t)((packet)[0] \ - | (((packet)[1]) << 8) \ - | (((packet)[2]) << 16) \ - | (((packet)[3]) << 24)); \ - (packet) += 4; \ - } while( 0 ) - - -#define READ8( packet, data ) \ - do { \ - (data) = (packet)[0]; \ - (packet) += 1; \ - } while( 0 ) - -// header structures for fun -typedef struct { - uint32_t version; - uint32_t packet_type; - uint32_t sequence; -} nv3p_header_t; - -static void nv3p_write_header(uint32_t type, uint32_t sequence, uint8_t *packet); -static void nv3p_write_footer(uint32_t checksum, uint8_t *packet); -static uint32_t nv3p_cksum(uint8_t *packet, uint32_t length); -static void nv3p_write_cmd(nv3p_handle_t h3p, uint32_t command, void *args, - uint32_t *length, uint8_t *packet ); -static int nv3p_wait_ack(nv3p_handle_t h3p); -static int nv3p_get_cmd_return(nv3p_handle_t h3p, uint32_t command, void *args); - -static int nv3p_recv_hdr(nv3p_handle_t h3p, nv3p_header_t *hdr, - uint32_t *checksum ); -static int nv3p_drain_packet(nv3p_handle_t h3p, nv3p_header_t *hdr ); -static void nv3p_nack(nv3p_handle_t h3p, uint32_t code); -static int nv3p_read(usb_device_t *usb, uint8_t *buf, int len); -static int nv3p_get_args(nv3p_handle_t h3p, uint32_t command, void **args, - uint8_t *packet ); - -static void nv3p_write_header(uint32_t type, uint32_t sequence, uint8_t *packet) -{ - WRITE32(packet, NV3P_VERSION); - WRITE32(packet, type); - WRITE32(packet, sequence); -} - -static void nv3p_write_footer(uint32_t checksum, uint8_t *packet) -{ - WRITE32(packet, checksum); -} - -/* - * Just sum the bits. Don't get two's compliment - */ -static uint32_t nv3p_cksum(uint8_t *packet, uint32_t length) -{ - uint32_t i; - uint32_t sum; - - sum = 0; - for (i = 0; i < length; i++) { - sum += *packet; - packet++; - } - - return sum; -} - -int nv3p_open(nv3p_handle_t *h3p, usb_device_t *usb) -{ - nv3p_state_t *state; - - state = (nv3p_state_t *)malloc(sizeof(nv3p_state_t)); - if (!state) { - return ENOMEM; - } - memset(state, 0, sizeof(nv3p_state_t)); - state->last_nack = NV3P_NACK_SUCCESS; - - state->usb = usb; - - *h3p = state; - return 0; -} - -void nv3p_close(nv3p_handle_t h3p) -{ - if (h3p) - free(h3p); -} - -int nv3p_cmd_send(nv3p_handle_t h3p, uint32_t command, void *args) -{ - uint32_t checksum; - uint32_t length = 0; - uint8_t *packet; - uint8_t *tmp; - int ret = 0; - - packet = &s_buffer[0]; - - nv3p_write_header(NV3P_PACKET_TYPE_CMD, h3p->sequence, packet); - - tmp = packet + NV3P_PACKET_SIZE_BASIC; - nv3p_write_cmd(h3p, command, args, &length, tmp); - - length += NV3P_PACKET_SIZE_BASIC; - length += NV3P_PACKET_SIZE_COMMAND; - - checksum = nv3p_cksum(packet, length); - checksum = ~checksum + 1; - tmp = packet + length; - nv3p_write_footer(checksum, tmp); - - length += NV3P_PACKET_SIZE_FOOTER; - - // send the packet - ret = usb_write(h3p->usb, packet, length); - if (ret) - return ret; - - h3p->sequence++; - - // wait for ack/nack - ret = nv3p_wait_ack(h3p); - if (ret) - return ret; - - // some commands have return data - ret = nv3p_get_cmd_return(h3p, command, args); - if (ret) - return ret; - - - return 0; -} - -static void nv3p_write_cmd(nv3p_handle_t h3p, uint32_t command, void *args, - uint32_t *length, uint8_t *packet) -{ - uint8_t *tmp; - - tmp = packet; - - switch(command) { - case NV3P_CMD_GET_PLATFORM_INFO: - case NV3P_CMD_GET_BCT: - // no args or output only - *length = 0; - WRITE32(tmp, *length); - WRITE32(tmp, command); - break; - case NV3P_CMD_DL_BCT: - { - nv3p_cmd_dl_bct_t *a = (nv3p_cmd_dl_bct_t *)args; - *length = (1 * 4); - WRITE32(tmp, *length); - WRITE32(tmp, command); - WRITE32(tmp, a->length); - break; - } - case NV3P_CMD_DL_BL: - { - nv3p_cmd_dl_bl_t *a = (nv3p_cmd_dl_bl_t *)args; - *length = (2 * 4) + (1 * 8); - WRITE32(tmp, *length); - WRITE32(tmp, command); - WRITE64(tmp, a->length); - WRITE32(tmp, a->address); - WRITE32(tmp, a->entry); - break; - } - default: - dprintf("bad command: 0x%x\n", command); - break; - } -} - - -static int nv3p_wait_ack(nv3p_handle_t h3p) -{ - int ret; - nv3p_header_t hdr = {0,0,0}; - uint32_t recv_checksum = 0, checksum; - uint32_t length = 0; - - h3p->last_nack = NV3P_NACK_SUCCESS; - - ret = nv3p_recv_hdr(h3p, &hdr, &recv_checksum); - if (ret) - return ret; - - length = NV3P_PACKET_SIZE_BASIC; - switch(hdr.packet_type) { - case NV3P_PACKET_TYPE_ACK: - length += NV3P_PACKET_SIZE_ACK; - break; - case NV3P_PACKET_TYPE_NACK: - length += NV3P_PACKET_SIZE_NACK; - break; - default: - dprintf("unknown packet type received: 0x%x\n", hdr.packet_type); - return EINVAL; - } - - if (hdr.packet_type == NV3P_PACKET_TYPE_NACK) { - // read 4 more bytes to get the error code - ret = nv3p_read(h3p->usb, (uint8_t *)&h3p->last_nack, 4); - if (ret) - return ret; - - recv_checksum += nv3p_cksum((uint8_t *)&h3p->last_nack, 4); - } - - // get/verify the checksum - ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4); - if (ret) - return ret; - - if (recv_checksum + checksum != 0) { - return EIO; - } - - if (hdr.sequence != h3p->sequence - 1) { - return EIO; - } - - if (hdr.packet_type == NV3P_PACKET_TYPE_NACK) { - return EIO; - } - - return 0; -} - - -static int nv3p_get_cmd_return(nv3p_handle_t h3p, uint32_t command, void *args) -{ - int ret; - uint32_t length = 0; - - switch (command) { - case NV3P_CMD_GET_PLATFORM_INFO: - length = sizeof(nv3p_platform_info_t); - break; - case NV3P_CMD_GET_BCT: - length = sizeof(nv3p_bct_info_t); - break; - case NV3P_CMD_DL_BCT: - case NV3P_CMD_DL_BL: - break; - default: - dprintf("unknown command: 0x%x\n", command); - return EINVAL; - } - - - if (length) { - ret = nv3p_data_recv(h3p, args, length); - if (ret) - return ret; - } - - return 0; -} - -static int nv3p_recv_hdr(nv3p_handle_t h3p, nv3p_header_t *hdr, - uint32_t *checksum ) -{ - int ret; - uint32_t length; - uint8_t *tmp; - - tmp = &s_buffer[0]; - length = NV3P_PACKET_SIZE_BASIC; - ret = nv3p_read(h3p->usb, tmp, length); - if (ret) { - dprintf("error reading packet: %d\n", ret); - return ret; - } - - READ32(tmp, hdr->version); - READ32(tmp, hdr->packet_type); - READ32(tmp, hdr->sequence); - - if (hdr->version != NV3P_VERSION) { - dprintf("version mismatch, expecting NV3P_VERSION(0x%x), got 0x%x\n", - NV3P_VERSION, hdr->version); - return EINVAL; - } - - h3p->recv_sequence = hdr->sequence; - - *checksum = nv3p_cksum(&s_buffer[0], length); - return 0; -} - -int nv3p_data_recv(nv3p_handle_t h3p, uint8_t *data, uint32_t length) -{ - int ret; - uint8_t *tmp; - nv3p_header_t hdr = {0,0,0}; - uint32_t checksum; - uint32_t recv_length; - - // check for left over stuff from a previous read - if (h3p->bytes_remaining == 0) { - // get the basic header, verify it's data - ret = nv3p_recv_hdr(h3p, &hdr, &h3p->recv_checksum); - if (ret) - goto fail; - - if (hdr.packet_type != NV3P_PACKET_TYPE_DATA) - return nv3p_drain_packet(h3p, &hdr); - - tmp = &s_buffer[0]; - - // get length - ret = nv3p_read(h3p->usb, tmp, (1 * 4)); - if (ret) - goto fail; - - READ32(tmp, recv_length); - - if (!recv_length) { - ret = EIO; - goto fail; - } - - h3p->recv_checksum += nv3p_cksum((uint8_t *)&recv_length, 4); - - // setup for partial reads - h3p->bytes_remaining = recv_length; - length = MIN(length, recv_length); - } - else { - length = MIN(h3p->bytes_remaining, length); - } - - // read the data - ret = nv3p_read(h3p->usb, data, length); - if (ret) - goto fail; - - h3p->recv_checksum += nv3p_cksum(data, length); - - h3p->bytes_remaining -= length; - if (h3p->bytes_remaining == 0) { - // get/verify the checksum - ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4); - if (ret) - goto fail; - - if (h3p->recv_checksum + checksum != 0) { - ret = EIO; - goto fail; - } - - nv3p_ack(h3p); - } - - return 0; - -fail: - nv3p_nack(h3p, NV3P_NACK_BAD_DATA); - return ret; -} - - -static int nv3p_drain_packet(nv3p_handle_t h3p, nv3p_header_t *hdr) -{ - int ret = EIO; - - /* - * consume an ack or nack packet. the other packet types are not - * recoverable. - */ - if (hdr->packet_type == NV3P_PACKET_TYPE_ACK || - hdr->packet_type == NV3P_PACKET_TYPE_NACK) { - uint32_t checksum; - - if (hdr->packet_type == NV3P_PACKET_TYPE_NACK) { - uint32_t code; - - // read 4 more bytes to get the error code - ret = nv3p_read(h3p->usb, (uint8_t *)&code, 4); - if (ret) - return ret; - - h3p->last_nack = code; - } - - // drain the checksum - ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4); - if (ret) - return ret; - - ret = EIO; - } - - return ret; -} - -void nv3p_ack(nv3p_handle_t h3p) -{ - uint32_t checksum; - uint8_t packet[NV3P_MAX_ACK_SIZE]; - uint32_t length; - - nv3p_write_header(NV3P_PACKET_TYPE_ACK, h3p->recv_sequence, packet); - - length = NV3P_PACKET_SIZE_BASIC; - length += NV3P_PACKET_SIZE_ACK; - - checksum = nv3p_cksum(packet, length); - checksum = ~checksum + 1; - nv3p_write_footer(checksum, &packet[length]); - - length += NV3P_PACKET_SIZE_FOOTER; - - // send the packet - usb_write(h3p->usb, packet, length); -} - -static void nv3p_nack(nv3p_handle_t h3p, uint32_t code) -{ - uint32_t checksum; - uint8_t packet[NV3P_MAX_ACK_SIZE]; - uint8_t *tmp; - uint32_t length; - - nv3p_write_header(NV3P_PACKET_TYPE_NACK, h3p->recv_sequence, packet); - - length = NV3P_PACKET_SIZE_BASIC; - - tmp = &packet[length]; - - // write the nack code - WRITE32(tmp, code); - - length += NV3P_PACKET_SIZE_NACK; - checksum = nv3p_cksum(packet, length); - checksum = ~checksum + 1; - nv3p_write_footer(checksum, tmp); - - length += NV3P_PACKET_SIZE_FOOTER; - - // send the packet - usb_write(h3p->usb, packet, length); -} - -static int nv3p_get_args(nv3p_handle_t h3p, uint32_t command, void **args, - uint8_t *packet ) -{ - uint8_t *tmp = packet; - uint8_t *buf = &s_args[0]; - - switch(command) { - case NV3P_CMD_GET_PLATFORM_INFO: - case NV3P_CMD_GET_BCT: - // output only - break; - case NV3P_CMD_STATUS: - { - nv3p_cmd_status_t *a = (nv3p_cmd_status_t *)buf; - memcpy(a->msg, tmp, NV3P_STRING_MAX); - tmp += NV3P_STRING_MAX; - - READ32(tmp, a->code); - READ32(tmp, a->flags); - break; - } - case NV3P_CMD_DL_BCT: - { - nv3p_cmd_dl_bct_t *a = (nv3p_cmd_dl_bct_t *)buf; - READ32(tmp, a->length); - break; - } - case NV3P_CMD_DL_BL: - { - nv3p_cmd_dl_bl_t *a = (nv3p_cmd_dl_bl_t *)buf; - READ64(tmp, a->length); - READ32(tmp, a->address); - READ32(tmp, a->entry); - break; - } - default: - dprintf("unknown command: 0x%x\n", command); - return EINVAL; - } - - *args = buf; - return 0; -} - -int nv3p_cmd_recv(nv3p_handle_t h3p, uint32_t *command, void **args) -{ - int ret; - uint8_t *tmp; - nv3p_header_t hdr = {0,0,0}; - uint32_t length; - uint32_t checksum, recv_checksum = 0; - - // get the basic header, verify it's a command - ret = nv3p_recv_hdr(h3p, &hdr, &recv_checksum); - if (ret) { - dprintf("nv3p_recv_hdr returned %d\n", ret); - return ret; - } - - if(hdr.packet_type != NV3P_PACKET_TYPE_CMD) { - dprintf("expecting NV3P_PACKET_TYPE_CMD(0x%x), got 0x%x\n", - NV3P_PACKET_TYPE_CMD, hdr.packet_type); - return nv3p_drain_packet(h3p, &hdr); - } - - tmp = &s_buffer[0]; - - // get length and command number - ret = nv3p_read(h3p->usb, tmp, (2 * 4)); - if (ret) { - dprintf("nv3p_read() returned %d\n", ret); - return ret; - } - - READ32(tmp, length); - READ32(tmp, *(uint32_t *)command); - - // read the args - if (length) { - ret = nv3p_read(h3p->usb, tmp, length); - if (ret) { - dprintf("nv3p_read returned %d\n", ret); - return ret; - } - - ret = nv3p_get_args(h3p, *command, args, tmp); - if (ret) { - dprintf("nv3p_get_args returned %d\n", ret); - return ret; - } - } else { - // command may be output only - ret = nv3p_get_args(h3p, *command, args, 0); - if (ret) - *args = 0; - } - - length += NV3P_PACKET_SIZE_COMMAND; - recv_checksum += nv3p_cksum(&s_buffer[0], length); - - // get/verify the checksum - ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4); - if (ret) { - dprintf("nv3p_read returned %d reading checksum\n", ret); - return ret; - } - - if(recv_checksum + checksum != 0) { - dprintf("checksum mismatch\n"); - return EIO; - } - - return 0; -} - -int nv3p_data_send(nv3p_handle_t h3p, uint8_t *data, uint32_t length) -{ - int ret; - uint32_t checksum; - uint8_t *packet; - uint8_t *tmp; - uint32_t hdrlen; - - packet = &s_buffer[0]; - - nv3p_write_header(NV3P_PACKET_TYPE_DATA, h3p->sequence, packet); - tmp = packet + NV3P_PACKET_SIZE_BASIC; - - // data header - WRITE32(tmp, length); - - hdrlen = NV3P_PACKET_SIZE_BASIC + NV3P_PACKET_SIZE_DATA; - - // checksum - checksum = nv3p_cksum(packet, hdrlen); - checksum += nv3p_cksum(data, length); - checksum = ~checksum + 1; - - // send the headers - ret = usb_write(h3p->usb, packet, hdrlen); - if (ret) - return ret; - - // send the data - ret = usb_write(h3p->usb, data, length); - if (ret) - return ret; - - // send checksum - ret = usb_write(h3p->usb, (uint8_t *)&checksum, 4); - if (ret) - return ret; - - h3p->sequence++; - - // wait for ack/nack - ret = nv3p_wait_ack(h3p); - if (ret) - return ret; - - return 0; -} - -int bytesleft = 0; -uint8_t packet[NV3P_MAX_COMMAND_SIZE]; -int offset = 0; - -/* - * nv3p_read() - buffered read, target sometimes pads extra bytes to the - * end of responses, and we don't handle short reads well, - * so buffer reads and copy out - */ -static int nv3p_read(usb_device_t *usb, uint8_t *buf, int len) -{ - int actual_len; - int ret; - - if (len > sizeof(packet)) { - dprintf("request for read too big (%d bytes)\n", len); - return E2BIG; - } - - if (len > bytesleft) { - ret = usb_read(usb, packet, sizeof(packet), &actual_len); - if (ret) { - dprintf("USB read failed: %d\n", ret); - return ret; - } - - offset = 0; - bytesleft = actual_len; - - len = MIN(len, actual_len); - } - - memcpy(buf, packet + offset, len); - - offset += len; - bytesleft -= len; - - return 0; -} - - diff --git a/kourou/libs/tegrarcm/nv3p.h b/kourou/libs/tegrarcm/nv3p.h deleted file mode 100644 index e3498bc..0000000 --- a/kourou/libs/tegrarcm/nv3p.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef NV3P_H -#define NV3P_H - -#include "usb.h" - -// nv3p protocol version -#define NV3P_VERSION 1 - -// Defines the maximum length of a string, including null terminator. -#define NV3P_STRING_MAX (32) - -// commands -#define NV3P_CMD_GET_PLATFORM_INFO 0x01 -#define NV3P_CMD_GET_BCT 0x02 -#define NV3P_CMD_DL_BCT 0x04 -#define NV3P_CMD_DL_BL 0x06 -#define NV3P_CMD_STATUS 0x0a - -// nack codes -#define NV3P_NACK_SUCCESS 0x1 -#define NV3P_NACK_BAD_CMD 0x2 -#define NV3P_NACK_BAD_DATA 0x3 - -// Holds the handle to the nv3p state. -typedef struct nv3p_state *nv3p_handle_t; - -// tegra2 chip sku -#define TEGRA2_CHIP_SKU_AP20 0x01 -#define TEGRA2_CHIP_SKU_T20_7 0x07 -#define TEGRA2_CHIP_SKU_T20 0x08 -#define TEGRA2_CHIP_SKU_T25SE 0x14 -#define TEGRA2_CHIP_SKU_AP25 0x17 -#define TEGRA2_CHIP_SKU_T25 0x18 -#define TEGRA2_CHIP_SKU_AP25E 0x1b -#define TEGRA2_CHIP_SKU_T25E 0x1c - -// tegra3 chip sku -#define TEGRA3_CHIP_SKU_AP30 0x87 -#define TEGRA3_CHIP_SKU_T30 0x81 -#define TEGRA3_CHIP_SKU_T30S 0x83 -#define TEGRA3_CHIP_SKU_T33 0X80 - -// tegra114 chip sku -#define TEGRA114_CHIP_SKU_T114 0x00 -#define TEGRA114_CHIP_SKU_T114_1 0x01 - -// tegra124 chip sku -#define TEGRA124_CHIP_SKU_T124 0x00 - -// boot device type -#define NV3P_DEV_TYPE_NAND 0x1 -#define NV3P_DEV_TYPE_EMMC 0x2 -#define NV3P_DEV_TYPE_SPI 0x3 -#define NV3P_DEV_TYPE_IDE 0x4 -#define NV3P_DEV_TYPE_NAND_X16 0x5 -#define NV3P_DEV_TYPE_SNOR 0x6 -#define NV3P_DEV_TYPE_MUX_ONE_NAND 0x7 -#define NV3P_DEV_TYPE_MOBILE_LBA_NAND 0x8 - -/* - * Defines sizes for packet headers in bytes. - */ -#define NV3P_PACKET_SIZE_BASIC (3 * 4) -#define NV3P_PACKET_SIZE_COMMAND (2 * 4) -#define NV3P_PACKET_SIZE_DATA (1 * 4) -#define NV3P_PACKET_SIZE_ENCRYPTED (1 * 4) -#define NV3P_PACKET_SIZE_FOOTER (1 * 4) -#define NV3P_PACKET_SIZE_ACK (0 * 4) -#define NV3P_PACKET_SIZE_NACK (1 * 4) - -// packet type -#define NV3P_PACKET_TYPE_CMD 0x1 -#define NV3P_PACKET_TYPE_DATA 0x2 -#define NV3P_PACKET_TYPE_ENCRYPTED 0x3 -#define NV3P_PACKET_TYPE_ACK 0x4 -#define NV3P_PACKET_TYPE_NACK 0x5 - -/* - * Holds the chip ID. - */ -typedef struct { - uint16_t id; - uint8_t major; - uint8_t minor; -} nv3p_chip_id_t; - -/* - * board ID - */ -typedef struct { - uint32_t board_no; - uint32_t fab; - uint32_t mem_type; - uint32_t freq; -} nv3p_board_id_t; - -/* - * Command arguments. - */ - -/* - * nv3p_cmd_status_t: high-level ACK/NACK for commands. This may be used in - * the event of a mass-storage device failure, etc. - */ -typedef struct { - char msg[NV3P_STRING_MAX]; - uint32_t code; - uint32_t flags; // reseved for now -} nv3p_cmd_status_t; - -/* - * nv3p_platform_info_t: retrieves the system information. All paramters - * are output parameters. - */ -typedef struct { - uint64_t uid[2]; - nv3p_chip_id_t chip_id; - uint32_t sku; - uint32_t version; - uint32_t boot_device; - uint32_t op_mode; - uint32_t dev_conf_strap; - uint32_t dev_conf_fuse; - uint32_t sdram_conf_strap; - uint32_t reserved[2]; - nv3p_board_id_t board_id; -} nv3p_platform_info_t; - - -/* - * nv3p_bct_info_t: holds information about BCT size - */ -typedef struct { - uint32_t length; -} nv3p_bct_info_t; - -/* - * nv3p_cmd_get_bct_t: retrieves the BCT from the device - */ -typedef struct { - uint32_t length; -} nv3p_cmd_get_bct_t; - -/* - * nv3p_cmd_dl_bct_t: downloads the system's BCT. - */ -typedef struct { - uint32_t length; -} nv3p_cmd_dl_bct_t; - -/* - * nv3p_cmd_dl_bl_t: downloads the system's bootloader. - */ -typedef struct { - uint64_t length; - uint32_t address; // Load address - uint32_t entry; // Execution entry point -} nv3p_cmd_dl_bl_t; - -int nv3p_open(nv3p_handle_t *h3p, usb_device_t *usb); -void nv3p_close(nv3p_handle_t h3p); -int nv3p_cmd_send(nv3p_handle_t h3p, uint32_t command, void *args); -int nv3p_cmd_recv(nv3p_handle_t h3p, uint32_t *command, void **args); -int nv3p_data_send(nv3p_handle_t h3p, uint8_t *data, uint32_t length); -void nv3p_ack(nv3p_handle_t h3p); -int nv3p_data_recv(nv3p_handle_t h3p, uint8_t *data, uint32_t length); - -#endif // NV3P_H diff --git a/kourou/libs/tegrarcm/nv3p_status.h b/kourou/libs/tegrarcm/nv3p_status.h deleted file mode 100644 index a973c21..0000000 --- a/kourou/libs/tegrarcm/nv3p_status.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef NV3P_STATUS_H -#define NV3P_STATUS_H - -// nv3p status codes. -typedef enum { - nv3p_status_ok= 0x00000000, - nv3p_status_unknown= 0x00000001, - nv3p_status_dev_fail= 0x00000002, - nv3p_status_not_implemented= 0x00000003, - nv3p_status_invalid_state= 0x00000004, - nv3p_status_bad_param= 0x00000005, - nv3p_status_inv_dev= 0x00000006, - nv3p_status_inv_part= 0x00000007, - nv3p_status_part_tab_req= 0x00000008, - nv3p_status_mass_stor_fail= 0x00000009, - nv3p_status_part_create= 0x0000000A, - nv3p_status_bct_req= 0x0000000B, - nv3p_status_inv_bct= 0x0000000C, - nv3p_status_missing_bl_info= 0x0000000D, - nv3p_status_inv_part_tab= 0x0000000E, - nv3p_status_crypto_fail= 0x0000000F, - nv3p_status_too_many_bl= 0x00000010, - nv3p_status_not_boot_dev= 0x00000011, - nv3p_status_not_supp= 0x00000012, - nv3p_status_inv_part_name= 0x00000013, - nv3p_status_inv_cmd_after_verif= 0x00000014, - nv3p_status_bct_not_found= 0x00000015, - nv3p_status_bct_write_fail= 0x00000016, - nv3p_status_bct_read_verif= 0x00000017, - nv3p_status_inv_bct_size= 0x00000018, - nv3p_status_inv_bct_part_id= 0x00000019, - nv3p_status_err_bbt= 0x0000001A, - nv3p_status_no_bl= 0x0000001B, - nv3p_status_rtc_access_fail= 0x0000001C, - nv3p_status_unsparse_fail= 0x0000001D, -} nv3p_status_t; - -#endif // NV3P_STATUS_H diff --git a/kourou/libs/tegrarcm/rcm.c b/kourou/libs/tegrarcm/rcm.c deleted file mode 100644 index aa8acf7..0000000 --- a/kourou/libs/tegrarcm/rcm.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2011-2016, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include "rcm.h" -#include "aes-cmac.h" -#include "rsa-pss.h" - -static int rcm_sign_msg(uint8_t *buf); -static int rcm1_sign_msg(uint8_t *buf); -static int rcm35_sign_msg(uint8_t *buf); -static int rcm40_sign_msg(uint8_t *buf); -static void rcm_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len); -static void rcm1_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len); -static void rcm35_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len); -static void rcm40_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len); -static uint8_t *rcm_get_msg_payload(uint8_t *buf); -static void rcm_msg_pad(uint8_t *data, uint32_t len); -static uint32_t rcm_get_pad_len(uint32_t payload_len); -static uint32_t rcm_get_msg_buf_len(uint32_t payload_len); - -static uint32_t rcm_version = 0; -static uint32_t message_size = 0; -static const char *rcm_keyfile = NULL; - -int rcm_init(uint32_t version, const char *keyfile) -{ - int ret = -EINVAL; - - if (version == RCM_VERSION_1) { - rcm_version = version; - message_size = sizeof(rcm1_msg_t); - ret = 0; - } - else if (version == RCM_VERSION_35) { - rcm_version = version; - message_size = sizeof(rcm35_msg_t); - ret = 0; - } - else if (version == RCM_VERSION_40) { - rcm_version = version; - message_size = sizeof(rcm40_msg_t); - ret = 0; - } - - rcm_keyfile = keyfile; - - return ret; -} - -uint32_t rcm_get_msg_len(uint8_t *msg) -{ - if (rcm_version == RCM_VERSION_1) - return ((rcm1_msg_t*)msg)->len_insecure; - else if (rcm_version == RCM_VERSION_35) - return ((rcm35_msg_t*)msg)->len_insecure; - else if (rcm_version == RCM_VERSION_40) - return ((rcm40_msg_t*)msg)->len_insecure; - else - return 0; -} - -int rcm_create_msg( - uint32_t opcode, - uint8_t *args, - uint32_t args_len, - uint8_t *payload, - uint32_t payload_len, - uint8_t **buf) -{ - int ret = 0; - uint32_t msg_len; - uint8_t *msg = NULL; - uint8_t *msg_payload; - - // create message buffer - msg_len = rcm_get_msg_buf_len(payload_len); - msg = malloc(msg_len); - if (!msg) { - ret = -ENOMEM; - goto done; - } - - // initialize message - rcm_init_msg(msg, msg_len, opcode, args, args_len, payload_len); - - // fill message payload - msg_payload = rcm_get_msg_payload(msg); - if (payload_len) - memcpy(msg_payload, payload, payload_len); - - // sign message - rcm_sign_msg(msg); - -done: - if (ret) { - free(msg); - msg = NULL; - } - - *buf = msg; - - return ret; -} - -static int rcm_sign_msg(uint8_t *buf) -{ - if (rcm_version == RCM_VERSION_35) - return rcm35_sign_msg(buf); - else if (rcm_version == RCM_VERSION_40) - return rcm40_sign_msg(buf); - else if (rcm_version == RCM_VERSION_1) - return rcm1_sign_msg(buf); - else - return -EINVAL; -} - -static int rcm1_sign_msg(uint8_t *buf) -{ - rcm1_msg_t *msg; - uint32_t crypto_len; - - msg = (rcm1_msg_t*)buf; - - // signing does not include the len_insecure and - // cmac_hash fields at the beginning of the message. - crypto_len = msg->len_insecure - sizeof(msg->len_insecure) - - sizeof(msg->cmac_hash); - if (crypto_len % RCM_AES_BLOCK_SIZE) { - return -EMSGSIZE; - } - - cmac_hash(msg->reserved, crypto_len, msg->cmac_hash); - return 0; -} - -static int rcm35_sign_msg(uint8_t *buf) -{ - rcm35_msg_t *msg; - uint32_t crypto_len; - - msg = (rcm35_msg_t*)buf; - - // signing does not include the len_insecure, modulus - // and object signature at the beginning of the message - crypto_len = msg->len_insecure - sizeof(msg->len_insecure) - - sizeof(msg->modulus) - - sizeof(msg->object_sig); - if (crypto_len % RCM_AES_BLOCK_SIZE) { - return -EMSGSIZE; - } - - cmac_hash(msg->reserved, crypto_len, msg->object_sig.cmac_hash); - - if (rcm_keyfile) - rsa_pss_sign(rcm_keyfile, msg->reserved, crypto_len, - msg->object_sig.rsa_pss_sig, msg->modulus); - - return 0; -} - -static int rcm40_sign_msg(uint8_t *buf) -{ - rcm40_msg_t *msg; - uint32_t crypto_len; - - msg = (rcm40_msg_t*)buf; - - // signing does not include the len_insecure, modulus - // and object signature at the beginning of the message - crypto_len = msg->len_insecure - sizeof(msg->len_insecure) - - sizeof(msg->modulus) - - sizeof(msg->object_sig); - if (crypto_len % RCM_AES_BLOCK_SIZE) { - return -EMSGSIZE; - } - - cmac_hash(msg->reserved, crypto_len, msg->object_sig.cmac_hash); - if (rcm_keyfile) - rsa_pss_sign(rcm_keyfile, msg->reserved, crypto_len, - msg->object_sig.rsa_pss_sig, msg->modulus); - - return 0; -} - -static uint32_t rcm_get_msg_buf_len(uint32_t payload_len) -{ - return message_size + payload_len + - rcm_get_pad_len(payload_len); -} - -static uint8_t *rcm_get_msg_payload(uint8_t *buf) -{ - return buf + message_size; -} - -static void rcm_msg_pad(uint8_t *data, uint32_t len) -{ - if (!len) - return; - - *data = 0x80; - memset(data+1, 0, len-1); -} - -static void rcm_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len) -{ - if (rcm_version == RCM_VERSION_35) - rcm35_init_msg(buf, msg_len, opcode, args, - args_len, payload_len); - else if (rcm_version == RCM_VERSION_40) - rcm40_init_msg(buf, msg_len, opcode, args, - args_len, payload_len); - else if (rcm_version == RCM_VERSION_1) - rcm1_init_msg(buf, msg_len, opcode, args, - args_len, payload_len); -} - -static void rcm35_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len) -{ - uint32_t padding_len; - rcm35_msg_t *msg; - - msg = (rcm35_msg_t *)buf; - - padding_len = rcm_get_pad_len(payload_len); - - msg->len_insecure = sizeof(rcm35_msg_t) + payload_len + - padding_len; - - memset(&msg->object_sig.cmac_hash, 0x0, sizeof(msg->object_sig.cmac_hash)); - memset(&msg->reserved, 0x0, sizeof(msg->reserved)); - - msg->opcode = opcode; - msg->len_secure = msg->len_insecure; - msg->payload_len = payload_len; - msg->rcm_version = RCM_VERSION_35; - - if (args_len) - memcpy(msg->args, args, args_len); - memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len); - - rcm_msg_pad(msg->padding, sizeof(msg->padding)); - rcm_msg_pad(buf + sizeof(rcm35_msg_t) + payload_len, padding_len); -} - -static void rcm40_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len) -{ - uint32_t padding_len; - rcm40_msg_t *msg; - - msg = (rcm40_msg_t *)buf; - - padding_len = rcm_get_pad_len(payload_len); - - msg->len_insecure = sizeof(rcm40_msg_t) + payload_len + - padding_len; - - memset(&msg->object_sig.cmac_hash, 0x0, sizeof(msg->object_sig.cmac_hash)); - memset(&msg->reserved, 0x0, sizeof(msg->reserved)); - - msg->opcode = opcode; - msg->len_secure = msg->len_insecure; - msg->payload_len = payload_len; - msg->rcm_version = RCM_VERSION_40; - - if (args_len) - memcpy(msg->args, args, args_len); - memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len); - - rcm_msg_pad(msg->padding, sizeof(msg->padding)); - rcm_msg_pad(buf + sizeof(rcm40_msg_t) + payload_len, padding_len); -} - -static void rcm1_init_msg( - uint8_t *buf, - uint32_t msg_len, - uint32_t opcode, - void *args, - uint32_t args_len, - uint32_t payload_len) -{ - uint32_t padding_len; - rcm1_msg_t *msg; - - msg = (rcm1_msg_t *)buf; - - padding_len = rcm_get_pad_len(payload_len); - - msg->len_insecure = sizeof(rcm1_msg_t) + payload_len + - padding_len; - - memset(&msg->cmac_hash, 0x0, sizeof(msg->cmac_hash)); - memset(&msg->reserved, 0x0, sizeof(msg->reserved)); - - msg->opcode = opcode; - msg->len_secure = msg->len_insecure; - msg->payload_len = payload_len; - msg->rcm_version = RCM_VERSION_1; - - if (args_len) - memcpy(msg->args, args, args_len); - memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len); - - rcm_msg_pad(msg->padding, sizeof(msg->padding)); - rcm_msg_pad(buf + sizeof(rcm1_msg_t) + payload_len, padding_len); -} - -static uint32_t rcm_get_pad_len(uint32_t payload_len) -{ - uint32_t pad_len = 0; - uint32_t msg_len = message_size + payload_len; - - // First, use padding to bump the message size up to the minimum. - if (msg_len < RCM_MIN_MSG_LENGTH) { - pad_len = RCM_MIN_MSG_LENGTH - msg_len; - msg_len += pad_len; - } - - /* - * Next, add any extra padding needed to bump the relevant subset - * of the data up to a multiple of 16 bytes. Subtracting off the - * rcm_msg_t size handles the initial data that is not part of - * the hashing and encryption. - */ - pad_len += 16 - ((msg_len - message_size) & 0xf); - - return pad_len; -} - diff --git a/kourou/libs/tegrarcm/rcm.h b/kourou/libs/tegrarcm/rcm.h deleted file mode 100644 index 7c07d4c..0000000 --- a/kourou/libs/tegrarcm/rcm.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2011-2016, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _RCM_H -#define _RCM_H - -#include - -#define RCM_MIN_MSG_LENGTH 1024 // In bytes - -#define NVBOOT_VERSION(a,b) ((((a)&0xffff) << 16) | ((b)&0xffff)) -#define RCM_VERSION_1 (NVBOOT_VERSION(1, 0)) -#define RCM_VERSION_35 (NVBOOT_VERSION(0x35, 1)) -#define RCM_VERSION_40 (NVBOOT_VERSION(0x40, 1)) -#define RCM_VERSION_MAJOR(ver) ((ver) >> 16) -#define RCM_VERSION_MINOR(ver) ((ver) & 0xffff) - -// recovery mode commands -#define RCM_CMD_NONE 0x0 -#define RCM_CMD_SYNC 0x1 -#define RCM_CMD_DL_MINILOADER 0x4 -#define RCM_CMD_QUERY_BR_VERSION 0x5 -#define RCM_CMD_QUERY_RCM_VERSION 0x6 -#define RCM_CMD_QUERY_BD_VERSION 0x7 - -// AES block size in bytes -#define RCM_AES_BLOCK_SIZE (128 / 8) -#define RCM_RSA_MODULUS_SIZE (2048 / 8) -#define RCM_RSA_SIG_SIZE RCM_RSA_MODULUS_SIZE - -/* - * Defines the header for RCM messages from the host. - * Messages from the host have the format: - * rcm_msg_t - * payload - * padding - */ -typedef struct { - uint32_t len_insecure; // 000-003 - uint8_t cmac_hash[RCM_AES_BLOCK_SIZE]; // 004-013 - uint8_t reserved[16]; // 014-023 - uint32_t opcode; // 024-027 - uint32_t len_secure; // 028-02b - uint32_t payload_len; // 02c-02f - uint32_t rcm_version; // 030-033 - uint8_t args[48]; // 034-063 - uint8_t padding[16]; // 064-073 -} rcm1_msg_t; - -typedef struct { - uint32_t len_insecure; // 000-003 - uint8_t modulus[RCM_RSA_MODULUS_SIZE]; // 004-103 - union { - uint8_t cmac_hash[RCM_AES_BLOCK_SIZE]; - uint8_t rsa_pss_sig[RCM_RSA_SIG_SIZE]; - } object_sig; // 104-203 - uint8_t reserved[16]; // 204-213 - uint32_t ecid[4]; // 214-223 - uint32_t opcode; // 224-227 - uint32_t len_secure; // 228-22b - uint32_t payload_len; // 22c-22f - uint32_t rcm_version; // 230-233 - uint8_t args[48]; // 234-263 - uint8_t padding[16]; // 264-273 -} rcm35_msg_t; - -typedef struct { - uint32_t len_insecure; // 000-003 - uint8_t modulus[RCM_RSA_MODULUS_SIZE]; // 004-103 - struct { - uint8_t cmac_hash[RCM_AES_BLOCK_SIZE]; - uint8_t rsa_pss_sig[RCM_RSA_SIG_SIZE]; - } object_sig; // 104-213 - uint8_t reserved[16]; // 214-223 - uint32_t ecid[4]; // 224-233 - uint32_t opcode; // 234-237 - uint32_t len_secure; // 238-23b - uint32_t payload_len; // 23c-23f - uint32_t rcm_version; // 240-243 - uint8_t args[48]; // 244-273 - uint8_t padding[16]; // 274-283 -} rcm40_msg_t; - -// security operating modes -#define RCM_OP_MODE_PRE_PRODUCTION 0x1 -#define RCM_OP_MODE_DEVEL 0x3 -#define RCM_OP_MODE_ODM_SECURE 0x4 -#define RCM_OP_MODE_ODM_OPEN 0x5 -#define RCM_OP_MODE_ODM_SECURE_PKC 0x6 - -#ifdef __cplusplus -extern "C" { -#endif - -int rcm_init(uint32_t version, const char *keyfile); -uint32_t rcm_get_msg_len(uint8_t *msg); -int rcm_create_msg( - uint32_t opcode, - uint8_t *args, - uint32_t args_len, - uint8_t *payload, - uint32_t payload_len, - uint8_t **msg); - -#ifdef __cplusplus -} -#endif - -#endif // _RCM_H diff --git a/kourou/libs/tegrarcm/rsa-pss.cpp b/kourou/libs/tegrarcm/rsa-pss.cpp deleted file mode 100644 index ab0a680..0000000 --- a/kourou/libs/tegrarcm/rsa-pss.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2015-2016, Avionic Design GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Avionic Design GmbH nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -using std::cout; -using std::cerr; -using std::endl; - -#include -using std::hex; - -#include -using std::string; - -#include -using std::exit; - -#include "cryptlib.h" -using CryptoPP::Exception; - -#include "integer.h" -using CryptoPP::Integer; - -#include "files.h" -using CryptoPP::FileSource; - -#include "filters.h" -using CryptoPP::StringSink; -using CryptoPP::SignerFilter; - -#include "queue.h" -using CryptoPP::ByteQueue; - -#include "rsa.h" -using CryptoPP::RSA; -using CryptoPP::RSASS; - -#include "pssr.h" -using CryptoPP::PSS; - -#include "sha.h" -using CryptoPP::SHA256; - -#include "secblock.h" -using CryptoPP::SecByteBlock; - -#include "osrng.h" -using CryptoPP::AutoSeededRandomPool; - -#include "rsa-pss.h" -#include -#include "rcm.h" - -extern "C" int rsa_pss_sign(const char *key_file, const unsigned char *msg, - int len, unsigned char *sig_buf, unsigned char *modulus_buf) -{ - try { - AutoSeededRandomPool rng; - FileSource file(key_file, true); - RSA::PrivateKey key; - ByteQueue bq; - - // Load the key - file.TransferTo(bq); - bq.MessageEnd(); - key.BERDecodePrivateKey(bq, false, bq.MaxRetrievable()); - - // Write the modulus - Integer mod = key.GetModulus(); - // error check - if (mod.ByteCount() != RCM_RSA_MODULUS_SIZE) - throw std::length_error("incorrect rsa key modulus length"); - for (int i = 0; i < mod.ByteCount(); i++) - modulus_buf[i] = mod.GetByte(i); - - // Sign the message - RSASS::Signer signer(key); - size_t length = signer.MaxSignatureLength(); - SecByteBlock signature(length); - - length = signer.SignMessage(rng, msg, len, signature); - - // Copy in reverse order - for (int i = 0; i < length; i++) - sig_buf[length - i - 1] = signature[i]; - } - catch(const CryptoPP::Exception& e) { - cerr << e.what() << endl; - return 1; - } - catch(std::length_error& le) { - cerr << "Error: " << le.what() << endl; - return 1; - } - - return 0; -} - -extern "C" int rsa_pss_sign_file(const char *key_file, const char *msg_file, - unsigned char *sig_buf) -{ - try { - AutoSeededRandomPool rng; - FileSource file(key_file, true); - RSA::PrivateKey key; - ByteQueue bq; - - // Load the key - file.TransferTo(bq); - bq.MessageEnd(); - key.BERDecodePrivateKey(bq, false, bq.MaxRetrievable()); - - // Sign the message - RSASS::Signer signer(key); - string signature; - FileSource src(msg_file, true, - new SignerFilter(rng, signer, - new StringSink(signature))); - int length = signature.length(); - // error check - if (length != RCM_RSA_SIG_SIZE) - throw std::length_error("incorrect rsa key length"); - - // Copy in reverse order - for (int i = 0; i < length; i++) - sig_buf[length - i - 1] = signature[i]; - } - catch(const CryptoPP::Exception& e) { - cerr << e.what() << endl; - return 1; - } - catch(std::length_error& le) { - cerr << "Error: " << le.what() << endl; - return 1; - } - - return 0; -} diff --git a/kourou/libs/tegrarcm/rsa-pss.h b/kourou/libs/tegrarcm/rsa-pss.h deleted file mode 100644 index 39e88c0..0000000 --- a/kourou/libs/tegrarcm/rsa-pss.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2015-1016, Avionic Design GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Avionic Design GmbH nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _RSA_PSS_H -#define _RSA_PSS_H - -#ifdef __cplusplus -extern "C" { -#endif - -int rsa_pss_sign(const char *key_file, const unsigned char *msg, - int len, unsigned char *sig_buf, unsigned char *modulus_buf); - -int rsa_pss_sign_file(const char *key_file, const char *msg_file, - unsigned char *sig_buf); - -#ifdef __cplusplus -} -#endif - -#endif // _RSA_PSS_H diff --git a/kourou/libs/tegrarcm/usb.c b/kourou/libs/tegrarcm/usb.c deleted file mode 100644 index 68070a3..0000000 --- a/kourou/libs/tegrarcm/usb.c +++ /dev/null @@ -1,353 +0,0 @@ -/* -< * Copyright (c) 2011-2016, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include "usb.h" -#include "debug.h" - -// USB xfer timeout in ms -#define USB_TIMEOUT 1000 - -#define USB_XFER_MAX 4096 - -uint32_t usb_timeout = USB_TIMEOUT; -// -// returns 1 if the specified usb device matches the vendor id -// -static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid -#ifdef HAVE_USB_PORT_MATCH - , - bool *match_port, uint8_t *match_bus, uint8_t *match_ports, - int *match_ports_len -#endif -) -{ - struct libusb_device_descriptor desc; -#ifdef HAVE_USB_PORT_MATCH - uint8_t dev_bus; - uint8_t dev_ports[PORT_MATCH_MAX_PORTS]; - int dev_ports_len; -#ifdef DEBUG - int i; - char portstr[(PORT_MATCH_MAX_PORTS * 4)]; - char *portstrp; - size_t portstr_lenleft; - int printed; -#endif -#endif - - if (libusb_get_device_descriptor(dev, &desc)) { - dprintf("libusb_get_device_descriptor\n"); - return 0; - } - if (desc.idVendor != venid) { - dprintf("non-NVIDIA USB device: 0x%x:0x%x\n", - desc.idVendor, desc.idProduct); - return 0; - } - switch (desc.idProduct & 0xff) { - case USB_DEVID_NVIDIA_TEGRA20: - case USB_DEVID_NINTENDO_SWITCH: - case USB_DEVID_NVIDIA_TEGRA30: - case USB_DEVID_NVIDIA_TEGRA114: - case USB_DEVID_NVIDIA_TEGRA124: - break; - default: - dprintf("non-Tegra NVIDIA USB device: 0x%x:0x%x\n", - desc.idVendor, desc.idProduct); - return 0; - } -#ifdef HAVE_USB_PORT_MATCH - dev_bus = libusb_get_bus_number(dev); - dev_ports_len = libusb_get_port_numbers(dev, dev_ports, - PORT_MATCH_MAX_PORTS); - if (dev_ports_len < 0) { - dprintf("libusb_get_port_numbers failed: %d\n", dev_ports_len); - return 0; - } - if (*match_port) { - if (dev_bus != *match_bus) { - dprintf("bus mismatch dev:%d match:%d\n", dev_bus, - *match_bus); - return 0; - } - if (memcmp(dev_ports, match_ports, dev_ports_len)) { - dprintf("ports mismatch\n"); - return 0; - } - } - if (!*match_port) { - *match_port = true; - *match_bus = dev_bus; - memcpy(match_ports, dev_ports, dev_ports_len); - *match_ports_len = dev_ports_len; -#ifdef DEBUG - portstrp = portstr; - portstr_lenleft = sizeof(portstr); - printed = snprintf(portstrp, portstr_lenleft, "%d-%d", - dev_bus, dev_ports[0]); - portstrp += printed; - portstr_lenleft -= printed; - for (i = 1; i < dev_ports_len; i++) { - printed = snprintf(portstrp, portstr_lenleft, ".%d", - (int)dev_ports[i]); - portstrp += printed; - portstr_lenleft -= printed; - } - dprintf("Enabling future match %s\n", portstr); -#endif - } -#endif - - dprintf("device matches\n"); - *devid = desc.idProduct; - - return 1; -} - -static void usb_check_interface(const struct libusb_interface_descriptor *iface_desc, - uint8_t *endpt_in, - uint8_t *endpt_out, - int *found_in, - int *found_out) -{ - int endpt_num; - const struct libusb_endpoint_descriptor *endpt_desc; - - for (endpt_num = 0; - endpt_num < iface_desc->bNumEndpoints && (!*found_in || !*found_out); - endpt_num++) { - endpt_desc = &iface_desc->endpoint[endpt_num]; - // skip this endpoint if it's not bulk - if ((endpt_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != LIBUSB_TRANSFER_TYPE_BULK) - continue; - if ((endpt_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) { - // found input endpoint - *endpt_in = endpt_desc->bEndpointAddress; - *found_in = 1; - } else { - // found output endpoint - *endpt_out = endpt_desc->bEndpointAddress; - *found_out = 1; - } - } -} - -static int usb_get_interface(libusb_device_handle *handle, - uint8_t *ifc, - uint8_t *endpt_in, - uint8_t *endpt_out) -{ - libusb_device *dev; - struct libusb_config_descriptor *config = NULL; - int iface_num, alt_iface; - const struct libusb_interface *iface; - const struct libusb_interface_descriptor *iface_desc; - int found_in = 0, found_out = 0; - - dev = libusb_get_device(handle); - if (!dev) { - dprintf("libusb_get_device failed\n"); - return ENODEV; - } - if (libusb_get_active_config_descriptor(dev, &config)) { - dprintf("libusb_get_active_config_descriptor failed"); - return EIO; - } - - for (iface_num = 0; iface_num < config->bNumInterfaces; iface_num++) { - iface = &config->interface[iface_num]; - for (alt_iface = 0; - alt_iface < iface->num_altsetting && (!found_in || !found_out); - alt_iface++) { - iface_desc = &iface->altsetting[alt_iface]; - - usb_check_interface(iface_desc, endpt_in, endpt_out, - &found_in, &found_out); - - if (found_in && found_out) { - // save off the interface - *ifc = iface_desc->bInterfaceNumber; - break; - } - } - } - - if (config) - libusb_free_config_descriptor(config); - - if (!found_in || !found_out) { - dprintf("failed to find input and output endpoints\n"); - return ENODEV; - } - return 0; -} - -usb_device_t *usb_open(uint16_t venid, uint16_t *devid -#ifdef HAVE_USB_PORT_MATCH - , - bool *match_port, uint8_t *match_bus, uint8_t *match_ports, - int *match_ports_len -#endif -) -{ - libusb_device **list = NULL; - libusb_device *found = NULL; - ssize_t cnt, i=0; - usb_device_t *usb = NULL; - - if (libusb_init(NULL)) { - dprintf("libusb_init\n"); - goto fail; - } - - cnt = libusb_get_device_list(NULL, &list); - if (cnt < 0) { - dprintf("libusb_get_device_list\n"); - goto fail; - } - - for (i = 0; i < cnt; i++) { - libusb_device *device = list[i]; - - if (usb_match(device, venid, devid -#ifdef HAVE_USB_PORT_MATCH - , match_port, match_bus, match_ports, - match_ports_len -#endif - )) { - found = device; - break; - } - } - - if (!found) { - dprintf("could't find device\n"); - goto fail; - } - - usb = (usb_device_t *)malloc(sizeof(usb_device_t)); - if (!usb) { - dprintf("out of mem\n"); - goto fail; - } - memset(usb, 0, sizeof(usb_device_t)); - - if (libusb_open(found, &usb->handle)) { - dprintf("libusb_open failed\n"); - goto fail; - } - if (usb_get_interface(usb->handle, &usb->iface_num, - &usb->endpt_in, &usb->endpt_out)) { - dprintf("usb_get_interface failed\n"); - goto fail; - } - - // claim the interface - libusb_claim_interface(usb->handle, usb->iface_num); - - usb->initialized = 1; - libusb_free_device_list(list, 1); - - return usb; - -fail: - if (usb) - free(usb); - if (list) - libusb_free_device_list(list, 1); - return NULL; -} - -void usb_close(usb_device_t *usb) -{ - if (!usb) - return; - if (usb->initialized) { - libusb_release_interface(usb->handle, usb->iface_num); - if (usb->handle) - libusb_close(usb->handle); - } - libusb_exit(NULL); -} - -int usb_write(usb_device_t *usb, uint8_t *buf, int len) -{ - int ret; - int chunk_size; - int actual_chunk; - - while (len) { - chunk_size = MIN(len, USB_XFER_MAX); - ret = libusb_bulk_transfer(usb->handle, usb->endpt_out, buf, - chunk_size, &actual_chunk, usb_timeout); - if (ret != LIBUSB_SUCCESS) { - dprintf("libusb write failure: %d: %s\n", ret, libusb_error_name(ret)); - return EIO; - } - if (actual_chunk != chunk_size) { - dprintf("write truncated"); - return EIO; - } - len -= actual_chunk; - buf += actual_chunk; - } - - return 0; -} - -int usb_read(usb_device_t *usb, uint8_t *buf, int len, int *actual_len) -{ - int ret; - int chunk_size; - int actual_chunk; - - *actual_len = 0; - - while (len) { - chunk_size = MIN(len, USB_XFER_MAX); - ret = libusb_bulk_transfer(usb->handle, usb->endpt_in, buf, - chunk_size, &actual_chunk, usb_timeout); - if (ret != LIBUSB_SUCCESS) { - dprintf("libusb read failure: %d: %s\n", ret, libusb_error_name(ret)); - return EIO; - } - len -= chunk_size; - buf += chunk_size; - *actual_len += actual_chunk; - - if (actual_chunk < chunk_size) - break; - } - - return 0; -} diff --git a/kourou/libs/tegrarcm/usb.h b/kourou/libs/tegrarcm/usb.h deleted file mode 100644 index ceca124..0000000 --- a/kourou/libs/tegrarcm/usb.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2011, NVIDIA CORPORATION - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of NVIDIA CORPORATION nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef USB_H -#define USB_H - -#include -#include - -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - -#if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102) -#define HAVE_USB_PORT_MATCH -#define PORT_MATCH_MAX_PORTS 7 -#endif - -#define USB_VENID_NVIDIA 0x955 -#define USB_DEVID_NVIDIA_TEGRA20 0x20 -#define USB_DEVID_NINTENDO_SWITCH 0x21 -#define USB_DEVID_NVIDIA_TEGRA30 0x30 -#define USB_DEVID_NVIDIA_TEGRA114 0x35 -#define USB_DEVID_NVIDIA_TEGRA124 0x40 - -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - -typedef struct { - libusb_device_handle *handle; - uint8_t iface_num; - uint8_t endpt_in; - uint8_t endpt_out; - int initialized; -} usb_device_t; - -usb_device_t *usb_open(uint16_t venid, uint16_t *devid -#ifdef HAVE_USB_PORT_MATCH - , - bool *match_port, uint8_t *match_bus, uint8_t *match_ports, - int *match_ports_len -#endif -); -void usb_close(usb_device_t *usb); -int usb_write(usb_device_t *usb, uint8_t *buf, int len); -int usb_read(usb_device_t *usb, uint8_t *buf, int len, int *actual_len); - - -#endif // USB_H diff --git a/kourou/main.cpp b/kourou/main.cpp new file mode 100644 index 0000000..8e73497 --- /dev/null +++ b/kourou/main.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include "kourou.h" + +static UC_DeviceInfo di; +static Kourou device; +static QString input_path; +static QString output_path; +static int last_error = 0; + + +void PrintDeviceInfo() +{ + printf("Battery : %2d%%\n", di.battery_capacity); + printf("AutoRCM : %s\n", di.autoRCM ? "Enabled" : "Disabled"); + printf("Burnt fuses : %d\n", di.burnt_fuses); + if (di.sdmmc_initialized) + { + QString fs; + if (di.mmc_fs_type == FS_FAT32) fs.append("FAT32"); + else if (di.mmc_fs_type == FS_EXFAT) fs.append("exFAT"); + else fs.append("UNKNOWN"); + printf("SD Filesystem : %s\n", fs.toUtf8().constData()); + + qint64 fs_size = 0x200 * (qint64)di.mmc_fs_cl_size * ((qint64)di.mmc_fs_last_cl + 1); + qint64 fs_free_space = 0x200 * (qint64)di.mmc_fs_cl_size * (qint64)di.mmc_fs_free_cl; + + printf("FS total size : %s\n", QLocale().formattedDataSize(fs_size).toUtf8().constData()); + printf("FS free space : %s\n", QLocale().formattedDataSize(fs_free_space).toUtf8().constData()); + } + else + { + printf("SD Filesystem : N/A (no SD card?)\n"); + } +} + +bool SimpleDeviceCommand(UC_CommandType command, void *response, u32 response_size) +{ + UC_Header uc; + uc.command = command; + + // Send command + if (device.write((const u8*)&uc, sizeof(uc)) != sizeof(uc)) + return false; + // Get response + if (device.readResponse(response, response_size) != response_size) + return false; + + return true; +} + +void SetAutoRcmOn() +{ + bool success = false; + if (!SimpleDeviceCommand(SET_AUTORCM_ON, &success, sizeof(success)) || !success) + { + printf("Failed to enable autoRCM\n"); + last_error = -1; + return; + } + printf("autoRCM enabled\n"); +} + +void SetAutoRcmOff() +{ + bool success = false; + if (!SimpleDeviceCommand(SET_AUTORCM_OFF, &success, sizeof(success)) || !success) + { + printf("Failed to disable autoRCM\n"); + last_error = -1; + return; + } + printf("autoRCM disabled\n"); +} + +void ReadSdFile() +{ + auto error = [&](QString s, int err = -1) { + printf("%s\n", s.toLocal8Bit().constData()); + last_error = err ? err : -1; + return; + }; + + if (!input_path.size()) + return error("input path argument (-i) is missing"); + + // Read distant file + std::vector file; + int res = device.sdmmc_readFile(input_path.toLocal8Bit().constData(), &file); + if(res != SUCCESS) + return error(QString().asprintf("Failed to read file %s", input_path.toLocal8Bit().constData()), res); + + // Write to output + QFile output(output_path); + bool output_is_file = false; + if (output_path.size()) + { + output.open(QIODevice::WriteOnly); + if (output.isOpen()) + output_is_file = true; + } + + if (output_is_file) + { + output.write((const char*)file.data(), file.size()); + output.close(); + } + else + { + std::cout << file.data() << std::endl; + } +} + +struct DispatchEntry { + UC_CommandType command; + void (*f_ptr)(); + QString command_str; +}; + +static DispatchEntry dispatchEntries[] = { + { GET_DEVICE_INFO, &PrintDeviceInfo, "GET_DEVICE_INFO" }, + { SET_AUTORCM_ON, &SetAutoRcmOn, "SET_AUTORCM_ON" }, + { SET_AUTORCM_OFF, &SetAutoRcmOff, "SET_AUTORCM_OFF" }, + { READ_SD_FILE, &ReadSdFile, "READ_SD_FILE" }, +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + QStringList args = a.arguments(); + + + if (argc < 2) + { + printf("No argument provided\n"); + return -1; + } + + // Get & validate command + QString command = args.at(1); + DispatchEntry entry; + entry.command = NONE; + for (auto cur_entry : dispatchEntries) if (cur_entry.command_str == command) + { + entry = cur_entry; + break; + } + + if (entry.command == NONE) + { + printf("%s is not a valid command\n", command.toLocal8Bit().constData()); + return -1; + } + + // Get command arguments + for (int i = 2; i < args.size(); ++i) + { + if (args.at(i) == "-i" && i+1 < args.size()) + input_path = args.at(++i); + + if (args.at(i) == "-o" && i+1 < args.size()) + output_path = args.at(++i); + } + + // Initialize RCM device + if (!device.initDevice()) + { + DWORD err = GetLastError(); + printf("Failed to init device. RC = %d\n", err); + return err ? -int(err) : -1; + } + + // Launch Ariane if needed + if (!device.arianeIsReady()) + { + QFile ariane_file("ariane.bin"); + if (!ariane_file.open(QIODevice::ReadOnly)) + { + printf("Failed to open ariane.bin\n"); + return -1; + } + + QByteArray ariane_bin = ariane_file.readAll(); + if (device.hack((u8*)ariane_bin.data(), (u32)ariane_bin.size()) != 0) + { + printf("Failed to inject ariane.bin\n"); + return -1; + } + + if (!device.arianeIsReady_sync()) + { + printf("Failed to communicate with Ariane\n"); + return -1; + } + } + + // Get device info + if (device.getDeviceInfo(&di) != 0) + { + printf("Failed to get device info\n"); + return -1; + } + + entry.f_ptr(); + + return last_error; +} diff --git a/kourou/usb_command.h b/kourou/usb_command.h index 527938b..b74ef33 100644 --- a/kourou/usb_command.h +++ b/kourou/usb_command.h @@ -15,11 +15,15 @@ typedef unsigned long DWORD; #define MAX_FILE_SIZE 0x6400000 //100MB #define SUCCESS 0 #define USB_BUFFER_LENGTH 0x1000 +#define COMMAND_MAX_SIZE 0x120 #define RESPONSE_MAX_SIZE 0x20 #define FS_FAT32 3 #define FS_EXFAT 4 +#define FILEBASED 2 +#define RAWBASED 1 + typedef enum _UC_CommandType : u8 { NONE, @@ -31,11 +35,15 @@ typedef enum _UC_CommandType : u8 GET_DEVICE_INFO, GET_STATUS, SET_AUTORCM_ON, - SET_AUTORCM_OFF + SET_AUTORCM_OFF, + SIZE_SD_FILE, + ISDIR_SD, + MKDIR_SD, + MKPATH_SD, + GET_KEYS } UC_CommandType; - typedef struct _UC_Header { u16 signature = COMMAND; @@ -62,6 +70,15 @@ typedef struct _UC_EXEC } UC_EXEC; +typedef struct _UC_INI +{ + u16 signature = EXEC_COMMAND; + UC_CommandType command; + char ini_path[256]; + + +} UC_INI; + typedef struct _UC_BlockHeader { u16 signature = BIN_PACKET; @@ -72,18 +89,29 @@ typedef struct _UC_BlockHeader typedef struct _UC_DeviceInfo { - u16 signature = DEVINFO; // UC signature - u32 battery_capacity; // Fuel gauge - bool autoRCM; // autoRCM state - u32 burnt_fuses; // Number of burnt fuses - bool sdmmc_initialized; // MMC FS initialized - u8 emmc_fs_type; // 3 is FAT32, 4 is exFAT - u16 emmc_fs_cl_size; // Cluster size in sectors (always 512B per sectors) - DWORD emmc_fs_last_cl; // Last allocated cluster - DWORD emmc_fs_free_cl; // Number of free cluster - bool cfw_sxos; // SX OS bootloader - bool cfw_ams; // AMS fusee - bool cbl_hekate; // Hekate + u16 signature = DEVINFO; // UC signature + char deviceId[21]; // Console unique ID + u32 battery_capacity; // Fuel gauge + bool autoRCM; // autoRCM state + u32 burnt_fuses; // Number of burnt fuses + bool sdmmc_initialized; // MMC FS initialized + u8 mmc_fs_type; // 3 for FAT32, 4 for exFAT + u16 mmc_fs_cl_size; // Cluster size in sectors (always 512B per sectors) + DWORD mmc_fs_last_cl; // Last allocated cluster + DWORD mmc_fs_free_cl; // Number of free cluster + bool cfw_sxos; // SX OS bootloader + bool cfw_ams; // AMS fusee + bool cbl_hekate; // Hekate + bool cbl_nyx; // Nyx + u8 nyx_version[3]; // Nyx version str (major, minor, micro) + u8 ams_version[3]; // AMS version str (major, minor, micro) + char fw_version[10]; // SysNAND firmware version + bool exFat_driver; // SysNAND exFat driver + char emu_fw_version[10]; // emuNAND firmware version + bool emu_exFat_driver; // emuNAND exFat driver + bool emunand_enabled; // Is EmuNAND enabled ? + int emunand_type; + } UC_DeviceInfo; @@ -98,5 +126,9 @@ typedef struct _UC_DeviceInfo #define SEND_COMMAND_FAILED -0x1001 #define RECEIVE_COMMAND_FAILED -0x1002 #define USB_WRITE_FAILED -0x1003 +#define USB_READ_FAILED -0x1004 +// GENERIC +#define BAD_ARGUMENT -0x2005 +#define BUFFER_TOO_SMALL -0x2006 #endif // UCOMMAND_H diff --git a/languages/tegrarcmgui_fr.ts b/languages/tegrarcmgui_fr.ts index 0a29ea5..dbf9129 100644 --- a/languages/tegrarcmgui_fr.ts +++ b/languages/tegrarcmgui_fr.ts @@ -1,54 +1,415 @@ + + QKourou + + + Device detected but driver is missing +Install driver from SETTINGS tab + + + + + Preparing files + + + + + Copying + + + + + Installation finished + + + + + QPayloadWidget + + + Form + + + + + Browse + Explorer + + + + Path: + + + + + Auto inject: + + + + + INJECT PAYLOAD + + + + + Payload selection: + + + + + Favorites: + + + + + Add current payload selection to favorites + + + + + Remove selected item from favorites (payload file will not be deleted) + + + + + Work in progress + + + + + Double-click to inject payload + + + + + RCM device is not ready. Reboot to RCM + + + + + RCM device undetected! + + + + + Wait for Ariane to be fully loaded + + + + + Double-click to push favorite into current selection + + + + + Argument missing + + + + + Payload path is missing + + + + + File missing + + + + + Payload path does not point to a file + + + + + Duplicate Path + + + + + Payload already in favorites + + + TegraRcmGUI - + TegraRcmGUI - - TEST + + DEVICE INFO + + + + + RCM status: + + + + + Ariane autoboot: + + + + + Ariane status: + + + + + TegraRcmGUI v3.0-a by eliboa + + + + + X + + + + + - + + + + + Battery charge: + + + + + Burnt fuses: + + + + + SD Filesystem: + + + + + FS Total size: + + + + + FS Free space: + + + + + %p% + + + + + Enable Ariane autoboot + to display device info - Smash - Injecter + Injecter - Push to device - Envoyer vers l'appareil + Envoyer vers l'appareil - - Browse - Explorer + Explorer - Device Info - Info. appareil + Info. appareil - - Device : - Appareil : + Appareil : - connected - connecté + connecté - disconnected - déconnecté + déconnecté + + + + PAYLOAD + + + + + HEKATE + + + + + TOOLS + + + + + SETTINGS + + + + + TegraRcmGUI is still running in system tray + + + + + DEVICE STATUS + + + + + + READY + + + + + + OFF + + + + + LOADING + + + + + Reboot + + + + + Boot + + + + + device to RCM to launch Ariane + + + + + Payload successfully injected + + + + + qHekate + + + Form + + + + + PushButton + + + + + qProgressWidget + + + Work in progress + + + + + qSettings + + + Form + + + + + Minimize to tray + + + + + When enabled the application will be minimized to system tray instead of taskBar. Use tray's icon context menu to show or control application + + + + + Driver + + + + + LibusbK driver is required to communicate with the Nintendo Switch (RCM). + + + + + Install driver + + + + + The required APX device driver is missing. +Do you wan to install it now ? + + + + + InstallDriver.exe not found! +Expected location: + + + + + qTools + + + Form + + + + + Toggle autoRCM + + + + + Controlled brick of BOOT0 partition. Enabling autoRCM will force your Switch to boot straight to RCM. + + + + + Waiting for Ariane response + + + + + Ariane needs to be loaded! + + + + + + Boot device to RCM + + + + + Enable Ariane autoboot first + diff --git a/libs/libusbK/bin/lib/amd64/libusbK.lib b/libs/libusbK/bin/lib/amd64/libusbK.lib new file mode 100644 index 0000000000000000000000000000000000000000..ce345948c5b64de3ce587ff627df7116d5584400 GIT binary patch literal 23804 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 W*Rd9qe8di|1+n?O?hrHlp8p33`QvW@ literal 0 HcmV?d00001 diff --git a/libs/libusbK/bin/lib/static/amd64/libusbK.lib b/libs/libusbK/bin/lib/static/amd64/libusbK.lib new file mode 100644 index 0000000000000000000000000000000000000000..f20f18dea31b67c2b55a1b21508882403a6be68a GIT binary patch literal 1427362 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%0DaICza6FU$L{#*=rB6OXCZ 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 literal 0 HcmV?d00001 diff --git a/libs/libusbK/bin/lib/static/ia64/libusbK.lib b/libs/libusbK/bin/lib/static/ia64/libusbK.lib new file mode 100644 index 0000000000000000000000000000000000000000..0e43a803c20310a795d9778dea7ab4827364daaa GIT binary patch literal 1437590 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 z zMOjBjd&}b09fph1fM+^uag1Y(Hqs8?3>{&8oW-JKtXb45Hyc5%3f5U1W@8Qvb9S#* zw2F-Gm%Lc_G64tP@i=`TJUDXyVx23|&eiI2ZhnMJdW}k^lR~C;&=7+266+N@B#Dw7_80cFHr`by) zVNrFyhuJrx;&a$R{xEZANt*p45~le!wb<}(_KZjz>>NN75NB*t1I>OBFPz$!h)-yk zy&{UfcjA)S8zS%sI&Ix*%zhAo%Q^++8^?(Z{&}?76QbyHn#*X$D5>OO_Jl~B`8fL| zS{K0vA@P?&#S%->0=%Gtd4;G(2=80hu57Dz(OPNG|7e?DNIdAj_|N$tpX}+50Gy-D zkvm93tEipkD4k}JNs|U&lL^!3BG`HGaAi2n8rM=2-^JyHEjMBCYGA#9Cm*Lo=!Rlc z-e~}UC5MhzUODMip42$5u9kbS=aY6c@auINKT5XcbfhSAJ-4>`>cC(?-i`r2%C;3x z%65gxKStnugm47LppIQ=W@L*?ig0^7Jgzy$F2*%wV1FfkS{`^stoBFO#$IoP#vDdk7vtt5W?##O&RW_Zr^LZ4-sOcW zB#?va#%!FOsc&#bpRn@G*>k$JcrHPtgQH+S$*nWB3|1c=m!ftLVLPB|wYXspaPAm{ zDOmRkL4l!l>z!<{)FO^+8uqO#u15aQq7lI}4eJk(hn|-Ft*gc2%p>mmlo_Vk0BUk! zhsi>`jB-K8hNJq+)=8Bn!x!dm$dq)M{;&o!gU|B8v9PQ;?&E_;8?YI~;mF8Z!%|zT zxMXIq_gHQ4l)bMugzX47!>KlnBZ#QvPn;_Ka=_8wIP-hEoXl%@o_7l zfk)8IM=Bx>Q1LLv>hjO>!nspiS{QY4*1Zkj7A?#mP$Q=KVx5CjFjom0iKwUI-t)Y1 z-4-a66tGwJuB}y{FSHr7d6uX*#s!^I0AoGbf~Tq{{Ucjj@vJjU^AUsb zJiHms&vg9LO?+$YG+{qCVS2n`ehn@@J$#wYSsLHjJ4&O+IF;v2=Nz5pT$83C5JHWU zUZ42+KblXZqgR7Db6BO%cFx!7FEHuTui)$1KMpIvjmfn4z}Df~1Z=3(R_n~;i-6ar z?bl`cI2UXBml*n%oFu=^6t_gerlR4b(*V88tXi&e9-Xl2c2tl+-uXt z_2nh#T(9Ha;Knt&omZc3a>LZUZp<6&sZH}1jptT3uEFEgvtOF9lzQpMmErtaRgwL&qsUcDq(eD3b@LF|?WzPRUBh2G3)47-5NOPY_W8JUA`049pmh*s4 z_u!7wb*YzG&ciz0BPN~Ic1UkWZRb&)_OB+bTNZsB6ZUwQFt05BzJsuT>>%tZ6V{Cf zR-``a&a^P7S)X3N{ZE6V8-CeOJcEC)Z2CCQ@*8FIoJni(YrbeSN0$s!sEoNrN-u)EF#-Hf)j5RB?_6wAu)c(xlDOY?YC5R_{J_ZK6BqrSv{9I6JfZ+Jaw0>r27TJ_J((qfA_1J zhn$D760UaI+eg4D^LHV_N*U(a7-f!jDd02Zv}$`dtV(kQ!e*0}z0+0a@oI#{h%Zgp zbqJf!bpG9~l8+k^b`;a43A-6#%fWZT-SMjOaU0;PM3#EDtIor(0AB|>{++HW%^e6! ziY(IXa@Fbo4{^4l47kIUGP(=jXVHHz-Og5>=J$wmp^DRWSF4V5H{x6={JYaT|BhB2 z?~jOgqsU^%@$N^wUn`naq$RHp0d|*^jWJ=b7x-TQ|Fe{fAO0BNk3hD1$EuXY-vE2U z@wSFi22TL?oGJsC){}s}=9IZRQyK4Rz_!6N(CkPh?0LXG#vT%HC#ouo7XjZ+xJOFp zzXG@uU|mrB+q+MR?{$RdFx+!x)4NU;-ggk5$8dMYse-=?`0zlAEdYM%W1v}YBTe%c zOx2dn?7>r%W%RRd9c_?_f;d#56xCco!L%!kz_1!4@oJ)#jX3m0&k+>NorUQ+09Ilo zt~<}xc(EEI@QSD$0wD7VtilKkHli|PJIvOw###>JDo;5Y#z_U|mFB+P_rX2p6r7_F zkD61MFR<#36P`}v&I^cJljf(s?)KuX=N*C!G>mz)8gh;X2+OqQ-U8^ zb*HadA#n>6LsrVBpL9VGG3eM*7Of2rmxB*1+f)Nx)sfv%K$sb2lSf{)A zT@v2kG48f{aY^&UQ7uorc9n0oxgGOUiyxndhB5GJzi;u=)G%oe$S*ZGS_kC>S$rQO zxIAlNKE7p^=xP^1HG@o!G;7aJEK*rh9}y!|BNkSuin^YSDPiGxdj9Q)V+FW6Qe)be zKdiE@tjhS#VYir%7S77XvL`IA+TM@b2Ylf;0n1%k#SH|$FgjZzJJP0c6M-)bSff>L z8}x_4xen~9_WAwE{xD^ELd}@&on^co67R1BJ3-;S zs&p^hgNs#CT-k=BF4XZ1s$Z*aS=_#;eZ3vP+KW5}wT7 zZD3xZhVUE^T`qE>q8o-0t7&=r%C?oO6FM9|3|89m)veeiK%DSlu;7y4_SLuwiMGT{ zEvroAm8+_iSZP8|+3Qj<^+Q;WdPhQ*@XkS4Wa{=#-1)ew+1phy8WQTm8~a*TtX^R) z_j|X_sqsoko%!`JCvqu>b9m1I58+2DXo1$&>v*cH#OhWR(8VL=kl&+WBO*Ke9)wq z(Xp$W6CEku2LS`uWxyJTwSq;htCcRwZ|w8&_6*>=kK>I&^pN42M#!J{A7%|h&oRJ^ zDXu2M+TgJ5>Gc?|&Py9{S7g-aNOuUeO~s6pY}ZV~@I1C56Ce%~Uf58Ed0Sj04R`Ji zcZ_CYO{;Y64IsDqDSO$N-+X=dy1ko%@V$dwcUcf#66AgxJ#xd_h5kys#>M=VLW|`> zV%q&_ZfSeA4B|{3nZ;J;#`V@y-IE&JFl|3b{;ij~psG7-8&-BKYSlGFq?r$Pl&&Xz z235C&=^q#dea|;zRJG63+4?vwzHmD&^t~<~GQ^2J<0w^Lk&B*jZkC+Tx`!oMt>Z!S z`4RhXUCC*S;#@VdDg9~1qNDX%DZewF6)kPnH*V%@X=-07^E!t2ciI-U>77~p&U03* zToOmej&?{tD7LYDEB`|s*ZHZd9~9b?dv=Dqf}0Pl7;oKn!*6?)$3dOOimv|<2;GLd zo?MZ-;$xd7yp^8<_KYLkRnUx<;zgBx@XyCD7=yyfmaQ9k)V|V8c z-tC?D?ha|dvrR99_rd1fEk(Un;C_4S`|gftH%!|z-EX}%0pE0`hlowD%PvvaxM=GW zIMxKH9@k;RL>=8iIhW%o!2YTPGErthMim>ENe9-|$mpb5A7UhT?LkPXFOe7QTa$oS zjp&eH^5?ppPm~hyZlhN9Ro3if+HTq#Iz`kF@d0qX)Y-!lj`MO?uUOpN9$l)`6w~{v zy4~2m7@n={=b&y$pD-CT^Jq6P(K&X*T8a)VI7RXUr1;Cza^4ztP>w)K4!(s=rVwt~9hdX>Tb&UD0rc(C2({ko4DJH4@zvLdXH?4yMwn0M$n z(2RozTRd~@-*HKrl@D)q$XJWB2hD7P1IC1wC4JXza=!nb^UeuN+Hqdonr6x~fd7mD z&Jaxbo6ywKI%erIfua^7jzsmvk~qs+1%^B$&eMncBH%;fw6qBr+9=|TBuU?&#KAci z{6oKnIDO8L59>$bB-RTAbpmm==3Bw?Dsh%9mUmgv3;g`N)Huw;ev_t6%eVd}PM%ge zb>jZh4%puU;&oz4$<(P+^Yf=on=)mJ1RaF|nftMw;0^m7QD6GqZ~9;N{4F)NUh>Ru z3kvJ+YuFrchV;*N7*@V1fYW-_pDk}fDDCm7Qs|ebWTj=!c;DfFNlLt#PTox6Q_G$4 zD(W3)F$>B1bK_~*GiW3JuWPg-;nj_&<yRUbs53xVWQz(VCXT!jAUU zZO1HZg|lp8@i7Y%?M(||!d!eze7WpOPfTcXikGZRIK@><)-+8knXn33F0NYH8?-Hp z7p`1abi2y`RombRvai&nKPT)U{f4STyMEQhuA)4L8h^_X8B@Y*>i zj5)64ap!r3J#=ADI1;N@;gFO>LXbRv(s3Uif7mt8WgRy8x%&sdP!~Fp$$xCY4(xc7KhwYRLn z0SO|9!-oE)jnl?*r&-`FGe-8=7$iRM2%d071L(A7Prv@(Dz=9`xao;&aA zbNRdbXYD@vqfec)zIx>F&{aPK4<*{vA&6cmI^>AG&j0Jsvp0-8`)}`*eHXfRM~K)p zC6=s-FF~PV%K)<`SROk5$>iVrJ$L;nH#~X3^wKXEgs$lcODcxRFSYG`^WA?v_2@%d zGcOAczBhE~jxaQ}cPzv|q@n2FKk>S=^N$bT4cWHR`d>k|Mlbj z7lqFLX!l#2{&C*0JtLvJ2JZj?JJj}7O_J>~S+Bo3Zpfs)IvWPOve$wGb3&axrQ~q9 za;++-jZZ&v%*)pg3)QU~`_-1>w?>A3-&5+ul4DR~QB#F_)~|mP`$fgXkIujDfhXD) zkDD3#!;aFksG8R`ty0ZoP2LM9zdrxUFOHgd*Sh4f|9n04Y)@$+@I~!v44IJC@4cTr zec*)VZ?hkH_8%9#9D1&&#A_D0Rr~Xq8?JqL?-|aw7iDig?f-6hG4%Y763g%fndxp~ z-HIu*R$N@N{H-g#o4@R-KRyuJzN5s_sybjK7IBr{ShMt+IinYBd;HaJn`77gJ~Vnr z55;^8R(+dWylU^U}j#{N}NieU4xMbx(HSrmM~D0FcC&LuCE&T!Izvje)Qh45ADBt^PM06>$f9ni%tza zHMZyEtTU4O_hauIzUacg{A65K>ws&&{_4@tdu2VO)p68>t19aw z_kBC(Z}0r|Pfr|q(^EhB@3n`AK0UhU#7!&PgmU%Llg_#5qz49HboV{)Uh<1~4hglc z=sB_J&R4AI7kuutJI^l8c;)WUoNZ5qR`iq@Dcdmv64L8OtUC0UyB>MdpmVmYyZqU4 z^`X&iJ(F&4Rvr2Ww~c-9%q6EDanO~w-Szg9xwnKej_n~ajuT2~rcWMl;q=JO=U%kn z%>m~>F!(Qj4psG(7=?uy)mqgve0AezuQwN-R95!JRlB!6GHgm{R*%Ws+7!fr^U_BA~uUeUBpN^0?<+a4M4`kfhzzHEPZ(??gF z6}qISlr1Y(NXlU&HeJ>H)4sQy)lzqRBzxfa(5dTspo!(LcoU4wx+8mW?@NEXi$hya>N#~=LiHuM!IF}t&mvGL%9;saQXj|#o*rMS3dT3=-{17-nK-sKls3Rzi&O_;=|^Azw+MeHjh6jRIs(j+^_Y{BfVwpF87)oO4h3-IPVQtu44Y^vO;nUVL=R5;Z@4{lv|W4edMk^Y`uwX$~WG9j@GN}iDe8B_ne!u;WBQE%=V@;oX^Fj~pL~5Lkzq&(BYexL~O(!!#sIu# zRr|^{LjK>M4_fg0(K91k_qeUK;;55{g&yx2!HUGX6{_4mxbl}@-Fxe=>vzBG;{kW? zao>ngLC>jIx3{j)W72g6uRip`J-427;)PlN`00J;UKT3-SC6?z&Q}@9m;Y^SxIXmI z^=D3c>FYB)JHw&J|J`GHbVe;Jn>tkfs|H_})xYq;4~k}7yXqHjzB@WJ@$(%bkf{m` z0E^Xt{B3yHPgdQ2(z-{V8*%A5CtbQBRI8HzU=tgRn95v9^9Gy|q-bjXKH#X!Zkj&f z@#)Xv$lHOdL$M!@9o=l}YK$uyeL|KL1^ew67sXb*^}uV7A9&I`uWj4yi%|5(U{{7- zLHv)o?;aW4?c0lM`@K*({-wIxLg#%YGX0@KS<=2H4kcZ1j(Pd^*NRX&Xn){CUth_uGIocE*f&#msm~W%}W05&CXN;++ zDk+^mW1757>GCpZz69W*Vz}QkosE5*%)rDe$0pn0*cgD@$mKST%9(Sj%PPuo)(>dR zuI?=zO=dF4tP?T=$3jF-H7xsUWhv6x63EKTcalkjCMzc6=L@XbjC!Ob5E!v&cN@#L5hmy%}vL^Nlv`{85vPd zWaO=t_}L#zJ!6*VIl*6T$2!?xkRUKH3(U)*`^xzvu20*K&*uHVTQjn9knTlds0-ug zFkndj(^;Mu$RIz0Ba4&+19MUkMcSGa5}l2giR6#7@pBU1DuE(!+dhGT1G**)uk$5* zl?gwI;O9}i9lAU(C<*gY5>_^+p?CNkB%6Yj-nEKeaNw|%WQJe4-&phe8Y$M);OA~6 zO+K8K-w`Q@$gd#L{JudXC&lpd8dic_e)sH}4E)*&-(tes55>=TtggEJj!sEPe(hvJ zZ#S&2B+o}Om)~(I$t-@kHN-9Bw@GyXmfezj4#m&CX?fl!1)1hqA<}%mOGKsf@l(Ew z#rJ+)lPbP_iQi-5V;11&=Sb}GJ}D)!=G~W6=>GFCB;AgrF8`$|Ne%yvyr){1_xq&! z@Iw3~hvDbNw7egff{45e63zFAL{fGXey-is;(KP-WZ>IQ_z@F!EW*#nNa*rhk&=)+ z+sTC9D~plru;CWJk(6YHUu+F=`TaL3KCuKpZy;&%gS7lsrywG~f<*KC36Y$#96xw$p?nW}Vd=E=WX84u+#dZ1eMxf-- z75JL|AouOm_rkzYZg`TZ}EoW2S_%XhckL2C-VQneMG|vi==KE_RTDT5BkM3#l zo#>iW@$F0eEfb#ue~9F;Q5NrOQW9(4eMyCG;CLiWBB@*6C!{1b{L3Bjn)mNW^@|hm zlar61&(qfLlT#3pcR`~0rhicKwIqJVkGA;U+%*~awiEIkjpVKy@v{yI-SR#)B_VmX zlL@_3HX+#?NM`uWbzUCpISV5&6WDW|2^ezcVAFma2NQB!9xTuS?*`NzU}bgnVSNjj zlN=&pZ|E@bN5hFxIDoeSr!?cb(FUa7MdFlQ6QJ)r&k}^E5?m{iymKzs`Ft=B%*Fo6 z9A_}l#E3qQeFY8fQ5QmFOTfttX2REMS2q%lOH#)f;wb0YDk~DJAF$4T6S>8KL6z0< zNCgZ!ayw3IYrLeSWFkn95Yp{nG$z*=rJQPx7$XrQ;82ah?NqJo-JD<`CmBfYjsRri zP!Ony;DE_6&Y`Remm|Xptz;nwSy(j|X9U8V4cD{d`aLIEg@ifIP&fN>C{j3%le8LZ zv6-d}{_!5C*+5V>q!9;z&XNO$oxO6L?MSL6%Tr2t#HBgA3tOS$_0dM0MWw_onb-w5 zZo_0k4%${6A{+FF&2=6afV{PzjSPr}A61eVf3HBr2GX(Eb zDz!e41}B{1)NbtLf>I;`dfVcXhx@4wvAm;NDw1#(MD|t>oz)1>O(&TE)=Vm$IM#jf zoH%zlG_UJWx43GCcoR;pa}eUhJl|m_St|rTvk3C+XgTz$A*xS?@`&aE#Zsv;-Co1z zBo7q<{i&;fuvG&Up&Ac;$pl6yiMtB9(&rUxz5>Wfp=?Ml2GvU9e{j<^5PN%HJq%ug;C5!EkW-GPPTHu2&a$H<)wQ)Al?_LuG<#Gxf z`aEjLbhOPZ+s|o*^}Gq5UGvbar1~ES!J`9sJz(EvjFYw_RgrYJx(gzy?!!RoW;SFN zS4u;!LiLe4Eyus}G+U^8!rTn0tLd(U!Hh>@++yVF+pFp%d07_vuc2|Ph2=WGVh-qe z@5@1sv&|~YdFTjnLVq;Y7*i+E%0Wh6*=GUovqP$56^(MPx|94&NImU#HC@iPagw}J zE7zI-UlbTPz zxDhQEj4E^DRlLVQMo7WMT1_>H-B6Bm6nbiPil^*Xh9A3}s;# zX{zBVuYYc?gu*8L{tYckx2MsZM2 zA4dt-?ji0L&)-O`eR{05&yFPlD4f*&C9KXV$5CqK;X11>K$YF@Wy_2ak}vjCxz1BV zVy1%}NG2RNqbd2!ad!8Mu@c9@S2S=uvZS~ta<+#*UR~Kd_vBvYqJ^b)i^Khg+g0wYQqjj2>MOuI*Slf=F%q<&8JO+uJlEnf#!f=h#cX@@YQb;C9SQOIS!5!AHBMAQm=uP~WO*_dFLGWi8 zDbgJQ3HlQe1-*(Hsm#HP-WbKf{T-|0m&rwaZKMi2)$Pee2IB4R_Gn!?vO$pC^%sfS zm*%2qWMqG2By+^RJglU8QKCZ`0}SDE zRuGWz{_0%kCq~k;5z41LHqMkGoIA;KoB|_tInvS-IYqgLD@vZ7uk;354W!+2PW6e@W4T;lE_w0l^8r%o za}A@iGt911InFMA7Ukp+eg3pZjS9I?+ZEJW!HG1kuD#69q;Ost+^CvQerAhO;`O*8 zI(((XX+o)pGU{n8)_E9C@*q}$1KcS<$_!v{BP}!fTZ&X)WN{9&=&Ablcz+|v=Qumw|tvIg8f3cHFczL7vW zQ937g|E;QaIZpo+WJrkHm2mF{cJZaFZUcepDO0tPzm)D}h7|l7%3;U)53gX)bs8Bl zy|#0&L>PsRV@~CQ+IU4x9GzJ_wy2%^>7C?EA@nJODR8ei?RjF3ljCQvu^v5!I>x*r z8e3qAs2@sav_CQr$Aq~IlOmjlxd5i3im+Uv;mLI`uux}-9+5SBHi=;lEz-Ja(FdzFZ$=wUs5F%3?gM&b2Sv>4tuBqq0w84KAL#4Obh zmW&1*vyS8H8_*sgA3^%9mE|fJ0d1oNTgpp=8|!D&V&II-0*ze+gb%hVV=p1dA0((3wvHNwyVF9a1M+5!Xa5n2`4t-OVIt%_^S2HU9LGW%;V+>Sl&?~Y37#3!-04=pjM^@^zXK5ft~TIm?5iSFPSe> z$d65R;Ms&2l_8M>g^4fTOl9z%xf>JD6g%VXSnv2F1>pAq8ElGbmTuFoUpm zDK&t-SPXZ};g*YV6z(UBtafnCa&O@Qi_#^Tl$sw=yiVbwmk&q>AwRf!*!%$jhwL#!H; zVKAwB5U*xW0=}c*BZtG4<%l&WxkzMuw;3Ac07Zoy13HSt%tpGLUE?GdOAZcEN?c8B zUaB5Pd*x^7W|U38>rmGu=|8ZfDVH7TyN=SCj=0Lv-?a1;#ZcLHexFj~8T67-TLp@J1hY4G*GK zp>FDSg`BnsoxMOOR^JFqWmOsPy_AWNv}n#|n*7!VjhR=?c$OqKqyuE)D2q@vB-7m6!YpjVE6+F@Hf&`aT!`_z$yXOxG}pbQdISEB){(e>MPP(jQ27*N)sD_4(4HN!rKR-d;0O92c5s55_iO; zw#9s8Xge~b)N-wuXmf$BVsciP=yxqaqx(a*#d~W+ z0fvC>{v^}MJYQx~whELZ9mE@h;T-@ISqD@a^c8OI(@x`d^UETlZ)i?8iQWTDF7~%Y z+`5=}7 zp(E~M28RxCWRWwwdC@9SbMz|dVkx{9)pM3Z)=DXoK84fG?fx#&9T};GN+k9u_oMZs zu5P1-h#I?I+E*cXNV)P0;|LFb&2?@J!1>!<_8DuWr{_eEBZHX(T#LM=@y?Ut{x4fD zrz$#rNNUoYH;umt=P!De(p6FCs@Bt7Al2(RCrF0!-j;q?Ei?1tDP;8|L3=agq;E(x zCVJIPiztGS*DTcx>Kib^`%J*B8Q-xr?VumZtW^aB7nqezMn`Lr5*i5s>TV9ko*FDa zx>mgbAUpbD-QqEMuEXttR4Lr$Lgs6Kf4vh!ERB1-E;Le^uD&0DRJs0ChUawAIjJp? z@uK?~GE_!Wx|RW7d0z~*dSL%qYfkcH5&i&wW~4{$Zt5@ynLk=pYTDSul;9}@Y*qiU zS{3i8uP?*(*i>{O-ikTaAj74!N|QOLu->go{$sa|kHr0ENJ}|>-3(~sOi`i1tMz)f zpx9Bqi|WW`=p%9oliVQExYetQ=)rl(rsxY&5$U*fw&EWBr@Hvt++>1GYTH>qhXD>-;i+EpcrtsidLzUM97PO}nf1p^V3!GCHxo)x*6C)!Ch9L41=1 z<*W7(;G0<=4ZfglnLDPOEDTuJ#<;D-SVgUN!YcKb z_uRP$tFgM;Smvc7FHS(m_^FvSe9W~l^@5L0%wEec1ZRUx+he!2vTbS0veoVC2xik+ z-Eh5B9!_Gk$J-gg@<%3R8h5o1ua-3CV0Va#S4!kykyb9T=4?kSpZel)u>uGW9EWP& z)B`h3em+I(r|YG-u5s4m>dgCt$^A@L)l~~l@+{%tzf#+&N_Xu& zXat6Tk6R>FbrC3H)lih(u8Vn%>b!>Mhv6wvT?J)y7AJE0mRVjZ8*Q{RPfcu?Kl5VE z_s?;MBUUTwFM1wxMV|CMZaFuhO{9xr$FK4CEXUfAcfv`r~DnBp$f>wk$$`Llj zH{m=4=Q#Ty@8a!cGR@OCXQgNcxxh11y36!-GOkqSI-RB`lRabDJp=-o;|4g1MAM?S zrP||oCZ;PA`#;!qn&z-~2=zjy`#+>pClNt_{W6hkjU=0DO23<{Oq}FJ!uAIyGpHrj z`NdB1VqtrjTNdKFT2%)}R@h#wCP*zU->;=m$5*$+dY8$1+6wK(x3XG!Is=%Y2X>Cr z$KQ7J*oKCgcG^Wn>_2V?Vy3?CB2kW0=tpOoqIAX32H;g|^-_BS+a0V*u6gAW3ivah zQaystoCkT%*HIzb4z;*+#E2hWfK(|a`-i+2_<)IoqkX58IikbSZj1%Zo ztHQ9yb69p2;VdWfc;zTBj$-aQDHe64RM-f_Ca+H9cam31oq8Yi&7!O^)YQyLXCtPu z<Qm*rm3G;?_|6IM(L_m$`ayJh4 zAPJVaXx+?N_vV~jCk_c1Gq!#IAhM}ko;Dgv-qk%$a;o4TF*K$IDMY?OAjh(0b0VZC z`t<@`P8wb3M=eH>*9vq_AkOyOt(%Vmh)Hh4&1BYPHQ5!_C z9Q>;^6nK1k=4u{tfFtW1?@cy8I~fzlVxx2M*peyk&!qWdOD6G4y`(;In+&%!I~kLY z|Dj1wL|WNU6UczsY0%-xO8P|o@9%#S_@4y+CxQP-;C~YMp9KCVf&WS1e-hYf2}FYz z1fl^aI(fj-(C#G#efot1xw#pG@|=O!hW02A4;%)gS~PfJ01@DfGH_w&Xnr%z;nCoU zI_YB}0xt?ggBRof68v9^|I6@yxq1dNqQNU9GNFOYXz)t!D>oXvN_}08*nCaih5QSG zKyoHj@O4eS~XzNn%y2Yel(0)|W80@=~vjeW?kKlSZc!p**1R9)P5Kd-- zVGzG0r>gj(oZ<^|6mcHa?-ZV&BN^z+3|y3>GH^kTmw`)jAlW{MiA>;KXM#l*$cYC3 z+Se5eUw2XR>KhF{pX&zjbyzfbU7ic!D~g^0N!WEDSEB0|4gPMh#JOv5G}wv%->WCl z{y~MXeE14{h!99#AVvPH7syuxKIcLBIy4$&z#cl)g_7!d73T{O*^Ymr#*@SV3XF;d zM-P$Q6reKjb&LwAjpCjl2K=xZz%f)4!OQuc-*?lDcibf`g~ISgQAG{-c!6^Q9J?^4>uGaAjQLnTwgYRD|plt zk0iwh6-B)Fp5o(*ViPDXG8F$tii=XpaS18@T~Wk)?6^7z#q`1POIDT`1Q?|Ka`YKX=T~Wn*@2PH6RM&uNhoSl&sdl8) z*R`bhzM_ct-c$TUQ9J<@k24fMCB@@XD4s})pDBuX?>)t@6vd68m^2i>CdH&has1}d zknHH`n@IH=MHTP8r>X~mpMvVChAKyZ&Qnub$!Vmhdwjh2p5j1YM{jo~D4t;`4kE=f zQhI{3NHGr~={dy2yq#q&V%97AygDV~$U5)k;Mb@0zL% z=E*D2fTF>bLuEkc@Sc1J*M|MTAzad3I#k4e*s!YN`NN9m4%4IfWdH-~6?hab95#7N zS)gfqrjwDA`k`#^@&(Bd4Il2?*z!Bbi&(VFr0gjFa zN6Uv5FEt$94=^Y^h(}@TFo-wMxqR5x4Je)&D4wkwSUe9QklgG;ZnkddY(<1dJeQIg z9eXB=CdVxrM#%-lE1F}-$iu({M)2NyM*ayLV5A+4tQuC_W*B(}U{H7tkHQYc$f{IE zo<|@V8Lt`XK!kzhq>Y^D=qa2qj-QhRIe7u7zzN=a&&f9604K+RlXb(2*BDOT0~i!O zz@zX4Rms++t7IP{0=Wt6N_GMwv5u`FGggX}I>u=JI(9r6`WLW)A-wmVp|61h3~dBM z$zjDO8HTBY$Ga|5LP9ifpc1p=Gioawwkr4-nVuBI8 z_nwghfdh>EY*>}<$$kO=vv&k~(wQ5x`AU}wh`X9Cv_77Yjg!72-K zhCu8%r;kXDbDlu#IJ@k_I2-r$Fz+D{8}kKS;_N#djUT8BpOoVG;vo#MlnLL2=AJ^;FEiK<@MYF zy(^2`rwPB$jHxPqdW>ea6R^&w$0!!YZ6POtNn6U9%X_S#oNNVzP@X^NPgc-y zH)t~v{@Du3cY{Q@_gX=F`-ASYf=b*VL3qCvRH`!X=*&NcAV~1pF-C$v%zPoL!qdQk zzTyqY>$Ne(uNaa2lT=?(BBNY7U&FhuB+n?aZ~hpvuPUVqGXtM^r|K1QxS8dLnC$eE_KcsTUGqsnBs2?{cM0czfttrbUMHD#GHdLRQ15vA5qow z6xlu?n>n^PI9B%#gGn|xR(c1vz0S^McXAIRnyntPLGj-shW9q1zJ zB1Js+#}J>Whz|tu{)TudiT4L__E*yskwGqzAZ@5g+7q>9^%8k~YOM6lf1dFJ2S_9c zBu5`11%CgGs^WWRQ0$%e&e&2;GbNaIM!R3~0ub(&g*Ovl95}l4pS-0UFHW*QQ*gf( zjhhe5Kz(>%hN%xhW-xi`{%*D}m2BTtCfRF7f)*OL|CHyjB;Z}^o$PcIo`I_XGJU4p+c~T(b znibaE{mH zLtZv%0Y`?8l?byCfv<%+_01CaK|2F~*zm+O$rq3u!_zK_s^TFD-C$n?taC_0S=Xs? zK#kt$j4BQ#`K~@QK1O!-^B1)yI?3Y7{I=y7BQHV zA4|%jB4VML6=DF!-iv`|P>5jy#4tWlypIvXw*YtU)0N>ViO%uqpcDh|1TQSJ#Gqm- zF(_P~81^Fr=w&E|0}@43L<~5l8g<7K12IqxOl`yQc8I~+huTB)H)KyIFBqVh-HMKBnQqGc;Mb*SIoA1FQVC+4!hXMzR zu@20}62-NK**btbYr8T#SD39wXyM})voX!AO5rhE&ulg@n;FyRCyG?+My3u~%-X39 zvyyVIq%4|GEc5stECRgu%)NvCsRS7w(aIuA<+tw(mQLmD_1 zY#I`9265Q0#y~j}?M|T)3FyS0G~(pr21)2hLP%vB(Tf^RY!k0?v1>?_G#C%Ma*zAjPJAu{>{aoaK? zZpw)GjEp4Z-IB6s9kJZQ_h1p=y_eBLzyTQ@4;igD(s>xL&h=g8aI)m}5rnd0M5SVE z)DcZ(*f{+JX6-M`TE_GZi6WKgQG6E;KqY`T#(WBo=oMo+#a|^w(FUe|jPJoBVCp?% z&jJS++XBWmCyF;3-kt-vb7NQDPET}hP6w?=cAiI?!f#Z`AI{9Hn5yIzF3moM=2OYQ z3uGW;`k9HM(?w=45<|a)H>eW>%a^G|3?}7ElCtPbVtJYG!6IPPVo+WgPhhBw2G2qa zJVcG83Kb2uukj#n2;>q4IdvWUZSb0$CJMGBc}F7Lg$V|{H?(z*Uk62lr>zq_m!6W_1c$cC|liagEnIY1FF5mn@Qr?FtNwJWn zKPIZEN%j}fAaA^s2)w&eQU~RYPA$9?Qqcvs>H|<-G$~MCSg8>Nbzh zrJLsFS$!v85Cvb60@J)d(#u95?nYNJl4o0)9j6&!=jE=@k>BJ40^wznf=gg*_+TA< zg1~s&qxnoOmaxZ7n2MBa5~w8pSY}kbW6?wSiNJKBN~~`Ma&aIUfQuO~RFue^6snKp zb=k~=PNHGA2n>;!9}Npht@Ov+Okcctj!qh2Qof9$0>9%Q?8VD8$xe)l;Po+V!mcWQ6u+9+-vi#sZ}9pA9{RlmrLUlP zOH%s5lI>N2ixBPuDhT0eV5us862Dpq_XA$|48AS;4-m$xAxteJQ%s?V_A6l3Fi(7_mATYwJds^O6p5@^4J(3rwk7`ac!szaVZA;gYYy z+9H|iAI)sI7y?1~U4vo{y4AGO)uMb9xR^02Lo?kj3J~e36gqlvyBY4JEW85xE7D6* zJjP6sbsd3CR_FI|#t9b5SMLkx31C41y#^9h#joJE_$B=4QhE}Bg>T>+Imh~-I3_(s z*qeUX(}1B&{;3|%;?YSgsNnD7(MhyhH%)s7k0Jr6Kn)+o2KYL{fZ=&0Es}Wec?mn2 z1G-3UK#^?-(4nT}>cOS&t0XTV2`j{lq^c;TPe42Wfgh+uFX==tlit4-?3FGESYE*t zvU+`C#;DSdk<3pJ@q^vO$9T>7$mgq?^y_#U*#-wG*}lQ-d`i4pLX>k?&OhrZ1~ci; zS{g3$ONqx6Wnh0~VLE9S5sZw!NqOujAJhJWh^!e_0lq~J2sf+=USNBh?CNS`VDA9d zkcGf^@iP5$($+%S1^^57eLPtT7KINaQ4wP!!iP-xp?d!p-i!XL-ao?ojx+xSBBo^i z-$X!oYDPasKq^C@0A?tE%7oh$<f5K8`z?~O21)ZAMm)*0+c+U?DF#zsqc}xNMe(ojpAFP@Bx8>K*^bfB7mtuQA%u! zc7Ex1NR(1tf=okrs&q3DkSg6Qz#6iOC{{?a557$0$!18Vd=;{L`pK3uRwWSI=OA`X zc$sk!t95meuIM>TkujZJWRdO#`vJ5=L2I!(c5mCCc!EXJ_x64SsRI^_Ag6!J5#%)d z7H`Fm9zp662!0#XqY;n7vk_W&7Je)jq4@~tWLl~|8ywZc>ntBXs`MNtVX);KbQqEp zF#zZfSLhe2#}Vprq#D?LVpailDi0cr6eO{-%su^O36d5Ojg6O`_!$ayGs02xLCm5f#gc{wF-~I%aF40|5OcG%NjydsWqfz zONf<{@=gtAMcF|x>&p&;MW^W=Icv`jQnM26AeeP&2f@`W;&g=%x zdRDTf9KtE&2_&o(EE82JbX9AIs5>cYscMDN8C{A`6jTC1s1ov}tAy+T{h>w_?i$?_ zwc>m9j@ngqlvdSCuL3F5Xi+Dw6tbg>2rK0Ev@+{B9!1Z20dlV&)zhw(nDkrR3yEL!$;t8HBnx<}im$^jt9IdyB!et+s!?<^KKvjv zEkTS?rMDwkBq7Y51m>!lbrmrER)iKwl-n5Zm-soTd+ zC(^?pZhEd%W&&Tyg&VjbprKFEUC19(Ok+liI{EX5ZnK<(pS1j?%R1e~QnH>bMSM5= zo2)D)OZ*|o$=xO=q+fIoex~1vA1EJ`q_6rEvYaT?ohtG<4Vgv1K>}U6ovbfV!ltnn z6p@6M)UOX9BqgSN)6Pq$fN+FBtbR4w=!KH1g=n6NIn=quJ;4_xsGFjSnqz(YvK z2yp3jXIT1Z5OnUH^M8c%SJ^MIJst=tcB|7$BOeg9Vyq(cSKT&3vrB)j$fQFPEi@qe zs%l=YLWYlx&ngX*k!$ZvHVzW17CeT}1;48vP3C7y$#8 zT{azDc4O72NMwa-=*p#bNE0W)&y3%--sA% zUIb;@pSv#;>0~WCTl%8&&o2FqpG$+~^~Tv~H(H+RD1FSPk4Gm%8Pw4oY-E(MlMQQ<=QF0su6~MmcqKS?%v=z|6m5OxA{r!h8_B?2zThWAUcn6 zivbIzqq4?i=(kWd4nWn=Z=v%z{@9^En^J{zhyQ;ev<~S|0jG&x#^8DdX*MZ`d>E<0@lC){aBCR9xTW2SAanm$*;X@F#AG6)q)T4 zDP1HJ)~|fycjzOfI7i%%K@}rlz|xy8G8_c;^NVrLZo8^3|MwG zep_~9)glt*LWj4i2p2vp+)iiD0WnfiYH{fOL$20ZVVpI4KA^yctCr`Q{emgC1&TidMSci0FkUgEH;U-Is}s z-B1RtMC9WdyaExD{zQ#|-_Sy#pYtD7S?D=x)<>=?*da5O%|ZhR8EsgaxTU^7+#W6W5Fbc}!j%dSRl%WkY% zNupfn@KzP!!e@ose#%NR#RB@fNwAhCBP`9Yy|eTZv2+#Wh>@8H zw(1&Sj8&_Vju9|m>5Um{f}q2jQKXS?ZUP_lP&0B{>3$<(-=0A?2g=uL5+q1C>jjx{Q%3HSfDRnFiCDP-A2A_0 zo^&VRgN7PBa&N@}AN0Mn^PrV?23$%5lQTr@QVau>Ye(!&Bdokx3hT=5h~2^rVy*n7 zcEgU?R)jlZTM(VcxW#~l`bKOE^^MpTI?q31cdJ6WBX%2fgo@4zDjVC(kF8YO&CNSv zyHIl&T~_}#x1;Rpzl^=e;DVQUw(KnzUj;~ez=WXP=tC`HC*xyf6Fx8@piO;VGnX~> zi7KBHflXl2bv!`t;Y5J`5MwsFd@HsiJ<>#gG?)mi$Cnt8ZXKh0Y9XbaZW;uv$^kYA zJrVF=IT2_827N8R_O9g}DJ`!Ha-^?i!aAsLBG3yA73W0Y6r^JW3|M;8*Y*WLecj-o ziGWBWpSNG9E9Q3iF)nFv_& zK@$NM4-(kfxnV1M9q{jaTa%3X# zCFWr!0vF>UJ=Y5|!?8>Rt^hi4B0$8-OYspClFLYUIX-Bp!4rX9C+AKCO6=18N^mI+ zOwJH-zG4`lTssly9$_NDQdn1ZCj!?pgV=Taq;|tj1gr>mB49yu9^)1R7V4V_Sg3Cz zV4?H;6M?KMq&pF~9y&rrX9bmw-N28VsJ5G%Zz5pjdbi+RS`O)^o?U2lAT$*ST^|VD z6bRkwfnpAEvndJ-5W58*E3d`}<`Aq7pTo^%C4VBn;T+;BFlqM~pyP24L05_~8(rKL zcOpH~9D+2MLtKI{u{~QvjGnE9lzz)igMeNzz_z645FRY&5MKla-88@UuF=*=qy0AI zNH@)d^=;oA;%;E5IOh;|Asr)Nz|xy;`ko-DuLm78hY)Gx^Hz=(YL_d(8rd+{N5h@aytMzsf6N;8M} z1=9XGgd&d-5hD-s5?2v;IL5C}U*p*5>i3$5|K(zj5%)MqrGg>oeJ z6!KzKNOwN*5_E)$&I&3U`#nEi8B%TUwt&sS8LV~*K&IMVRpyyp2LvHv`2T~+nfb+D z#mCAQ@qyu=*7NzvT-M2_s%}mLehp?_s{`~KP6OxxF=nULTk#swBTWNHgK5B1_!5)R zp<{GREu{2yHw^+--T<3|o(6cZoCZ7&40>9A?R~pDQQF-bkR`n>6V@$#Q-L>uq4Jyx z`~~S40RxtvPK5C0(!T{keI4PTseni$pSPl{VEU|{Z(}O(mLik>NBA_rcF=?P>;Oe_ zn2le1Z?K{`gjfMr+H0n2VI`!5pZLWj4k z2p2vp+;)6ck}d~Ym*Vy=GWd^yG^Y9K4giZnFzM*hrk%i zet>k0fB{QyO!-j|ba+#WH1f^;4?gIrW=deC`wfZC{9{n2{ki)xktu;?XRGIw!1>t6 zrNQo$KryKP-pA~j5>N(p%$X8cax>`I>SFOQB?yBrMzsf6N;4&hP$QZ(hdf3^j66V! zyNDRvo($%_sCC}ufGNQ?sr5XFmnlI3^D$F`(RfJD^@7Y;B~yZ8paZ7_M64{rM@&e@ zl5QM6Xsp3gf-B!IaP%NG=pDmEa48K;&Jc0CVi=%YI~5q|9Ro`t?rbJ%H1&a{Qj^|M@>8crErE@%I zHO82YR%^w9NRKq0lLq7Y7<@^&>5VaZl@?N3;-*2s8W^A->+#%!<#;{{7<85V+WSV+ zDUD_(WJy=ag!L`ocs>UhD$nu!Af#gi3|M-zdYT&q_4Q(d#&eNIK5qqC!DitEB*ycD z6`6D%!lwbYcOArM`yi6TZ2a1Lv-OJE=0nzkdH4|9@kwl_#&g1hO}P*lW6DF3ju9|m z+0}S%*^OlnBT+7Nc*}}#;j_YRuVp0}1KaU@ky1}=ED{KC)w8A!l3=Y(Mp&C)dvEO> zV(rC{C5C1q*s{xkF_vA5bc}!jOK(hhL=bd%Q;Ib5&0U5Mda4=Et#rR3(Ic0FGVRaZ zmx+w$mR+yqOIP^0G}s-_6@wbjeaxoQM$bhV)G=o~x8!Ezu+_!lVLU$)UoomZz*3s= z{3xXTEuk?}kM zbl`YS#L7y1#DpYHx+;9oScAv&+lvcx#&h>o!Li^{8kn3R;y%SNK)H52&wdBx;ok^L ze3r(#wO+!&i|UwBEXhx5IqbM@MY!X-1<{d=iwsz(Z(O%f-?(m}^ZeubcT{2BaXkec zp`x>b%Epf4N1AH8x%plhSh=NEGsN;+=qm3Vz(T77Y1doYa=P?jBk^!GRpY@(E2|r_ zq#Xsac=sSIOE!yoG;ElIG?*f@ps_}LtgOKY<{+##pM%b&Q!uAJ_A|~w)__U7(*PZn za}c^-jM?a-tT-O&k>((z!5pLlUo^xDwxAeWf)-MGf|~{by=8!HPtQR-Sk6I?0S4VW zzxKYNpD7J}BV4w7K4O-5Lo zUwd!u^TgU6kR^s@BG|I00AnoMiFAyB0ZVU8*%JgE-jpJZd~>_-K~FVv5G&npNQ@r6 zpiKL7_hlk;5X;V1&pm}cKbHo(a}dR#<{&<1Gr*wdq73SoGY7HcgXSPC9_AoB@D-!l z11zPPgX~1wKL=6dF(P8*L0;l60uRUdWolh+K9DONYa^jK1qV8z(6~@2G^@bL)Hdy^ z=<4t6bIuPtk-S1DbWkW%0(iQw$2mWuK-myZNRA7SiiEB$G`v?82J>D4c)F*>McPsm|(pnXe7b8)Hu%xWycx`Cs~3Mgdn5|#u80 zWJ|Cmn4sGdY!4>bX$ks*2~M{Jrv?*z-V$Vk2`;n*=S_0jopVhw$D3kaYze+N$>|4$ zu@rtPT~*{)EX8G$oDNrnwbZqi;3|j!g%M$meY2&wfoh&hXJKs=n>@a53BD?|F^J$h zmf+6df}SwdxXk*gPI-Hu)iW9jtp%j1x6Q4?sN@?8Z=CA%Y1$AKio$POte{PU1f4XL zpw<9E+pM6iN)WC_mS!_46xy6CXtLI*Lkj|Jh)rw~H0rg2x(5mB97<4MfS}J>LA#V7 z;|{RVj$A>;MyCZ7?ekVpc92GA8SbQ+qrSO=RG3cV{3sa@lCv&MzTMIdhfSw-l)BH`(?#)_DIW*IS) zXE`nYZY(;>>Gt+w5oj_l912gHRj9 zXz%IjbRBJ)aqw3y`OCANR99DrOS2znLZO%TM9N>Sls7=$(bm-2-@Ur0tG~OVsk5c6 z!>Hk$pQk)6d!WdE%}?xRy}zLUxF=b^ZL@xBwo}&9*S@2vuf40YqN}s7Z5M_F)Bn#D zk#Fva$ak&Cf9?tSe=Pa?dqN(XV=CyQ*-m9gM|D$YYlo)~U=@c#|J@T&1y)qv9H*+i zv#F!~R8@Li@23E z>N_;G_dq8srD+tQ$e%7A>(A->ip>mADa{UHv^R z9#^L>q0sTYPGwtfAKaG>*DZUESJPcuZl9LhW#x7ZCHG{X+;sb?$eE^56U41P>=3zr zPUm{2`VO6DbKO0H9WK(GU(ouVXF1O{oF3OvhB(V$Jg(!bE?!734J5=1$W7DWt>#W! zPfu4*MOSN^JHODw4R7#POuVt%F!5?|r#HtYydK=y-nPA~XSZt*HRMPm<0aTi6feCt zqIkphAW^(wdl*p>UOcVZIxn48LV3xw5z0HQo!*=lzsYz+9)?lg#;kmd7c!eZm3Kbt zeCyjbyQOH=tfL|kUTCbc<}Jc1YhD>_vgQrMLu4Ha^HO3WEBm{}k=5wi&0#qbitrj^ zr=tx{jP@svHY$?O`!FS!eBP!hD(CZRPD$nQ`b)v)@oG_(;{n{e{B3 zX4PpICd~9?hT9hk^D11YT{t{Y-gfG=Y!&cXB*y>lP?$HE0xU8t7-K=+xP0{w9`a=@ z_m%3GnN;YDNSOiXLZqG5{q3!}Ba14)`3AkV$uleJ7Doz&zeH?rOA}@qTzYymzQpj+ z`?P<6DIC6-h%LyEeRZ#M)+k^Pb!KM!XfLizfj7EcWrXDFMpp}kc-Nw+?s~XU>^hT6 z4gAom1#|E+K4p%ZOe(~y_*6~m-r@m+iu}~1@_&RBbB*NRkCe=T^M8nx%!2a=ES49( zDJ*Y%6KvkSNJ*v)6j+QFm&N>7`o8ckTN#94QVI7 zqfbvb-N_DbL*gv?b`o^zX`rf!bBThl^O`q7rMh~pm7<}@w+Qd;YwGFqA;hmnjT<$N zJr8dbQ-*xhrXDe=&_hU>#=$$vWLBL!$rClWw&3kqO4d_0^`uFKeub2g^%&AlM_0=> zz1LwTwo!2iUbi)TPP~#y<@7s~iu}f;!o1o^VR@C6O7V&;NriZAlhNZDq=(4~T_g!a zQBS*wO55b}hxgow)Ce!kkyJjf^-&(i>wc6E@xCABVeeQh?-Wwlw+%Lr*8nMbZwVbe zjCcA7U4%FJh?EGgc9Kpo%sY9+6T^QpbYWiBBXl9&xMMu*_ec-xVZ5~{$HOkx9`?FH z`5Y+};T=OGc~}I&G*YH;*rq}z72*XqrZzsLG_KonJxtV~hmAFS;Ub$FV^X0)q>QXl zNDu8{dBhHz(=;PBypKsmrkGTCvQ160si;YXCLm?>7>D#QIfcT-BpBMm4mVOG%S?qJE4?EJPR+?0(6e&|1%aIPO z4N-$07B_t1N}H-MsZbeGM%FP%5A9(`6C31VHmBo^)NsnAB6TJeuC=Ken_6R1p=zXz z9#u#WlT#?1Ai>Zc)@h_hwwqM`$w(;=Ye!0X*jA*Jhi$glHj8aF*t`~`l!rA59X*VP znpGc`F?5lWgpMA@L&?g+)*HI;Izty~K+1SnJ<`K^SR)Di9(IlPu;UFX$HPt_d;|~c z2aWQuKAY+_sn97%ncC<=I^p;M7EvUVXow1@2=Hps(lP8S-f z;R{SEa-KW-_9YVdJ?uK|VV4QZlkRIB@?j<(J!)#8!FjB)jSflFX5t9l(Y*P=})Pp7!`YBRIkDnkt zOirQj10)#Q!+63#<^GyU<-dxQ@~}T3r9A8vq?CvK-eO;}*xwm!-fxjo@?I1=dKgbr zC=YwV&_$jXI(isSL#RINDMJ^2($Iw-N6L8EFOeSB!+u2qzlZ%md)PAumE&R05lQK393z7(*8x zZRkRykTM>|P~BlYtbhc54|_m+*jR(g@i4|4kK|zogGSXAqi0oWj!A_MLdw(zqhbSV zL)4&$F~(C#ILxLNnpEgeq>QZjNDu8{3<@1Sr=yJ2Fe3+5oiJWe<<8(km13}^N->C2 zQlX_t89f#wJxoraFhdxJ@i0a-iPQ)~qa>Bj050W24D3=KmPSf>*l`xiNH>LLsGDH( z>X1_MYJ`p+#^^2OVaFP}2m=q5hcWs}d02&^3o|TBjl$-@}gBxMRSHcF)!b0w(|!oN}3>z_eFjQrjoI+s+s0`_0 zW1TU0VUUM-!J;vt;%J*I+MZ<*S`5@AbFD&La_WK-AfiGMf zF|?3z3NS`SzJY5Q3^U1IvNVV1FVm39RFu`!l$TYk$;9i{ChC)QnYD|Z#vu@^ zRypq|8}DP}&L2u{Dw(WNf|vrQ)Xlzz?=wU3Rn)}G>Kap-)%D57l-9%xa&?$)Wa&EM z+YtU|J+mHYwF5xIdY)lu%LDT*t7u59Eo(@i_!Y^zhWPph#XM~ZiibTgvi8u#? z2S4G^)w!jrzY}lc@j~xy!siJ*)z;J7-rLuPjX~5g;V}j8;cNRg`rq<=K%MY>fm0S@ zuAQU$J3E`Ux3wk7Pzucws^^&Cqu03`Ip820L z*t4+(uH-Xh9BF8^4*6P#qYYfk;9FJx_sTei&ycao&?0U5blLs+hMWq`Q)zjWjminP z`r$HhO}E<6X+7BEb3`DmvS-*yXxd{9E%dN9^yqK+_?nzHsMUORhELNHZ^~+DQ=0ZT zLmLf6*_%;^gYZqgT>T?XTGKZedTkFQmprV?wVH07q4Si}FEi|H(6q-JS}l_;n0Zql z%G{{wPIT#ty9J|0iHw2kGO#UChUwLmk3^g%EvMPg!>**!J}bVti8P*iYtuZN4Np!U zEVt+?Z6V@p)%5K-^qd{=KmT0$5oepG?=bY^BU8FTL%E9`jAnBKd;ZmpiAuCqewnrz zF7EQkDA6*|_TMfl_x59zO?^#^rDvQ8nmmWkOYHL~d0r~dr$AnzJTG&o2WCOx9>C0B zu_Frj^??2*AfWz-GH-1!d1|vsYvP#%M*I4@ zGEP;3z-}F$V`MH2toJp^@?$gQWoZucHVy8#iCyW< zvjF8M7m6Ipa-3C#frT~- z<(Np@VpNFLBlRb!FD8bWqfU-t}2;{ zOEvl-#-5iLIm=a>%eCjFz%O!I`g?jf1yXYf!b+X3ZB4DHN0bSE7QPHH^M~HDq+tkg-jb+jSUvNe-N98X)T)h(0gY;D_RXj#Ui zoJ4O$M^`6THuU|kf`64$+qI)jwe@`H`!$cgo6yz+oRK~s0M_;mZtJASGP5eNy0Km@ zIxFMpiuy#VAz2T3!=c@J`#N+RuCJw&r>o2A7K;VPp=`*HW{}`o!9J zeWomxFhzGEM$Vl^&M?02wi_&uE7llcIbgTE-yU9OO`;syt;v+HsjKv?;e)`g%)5-t z;9Y@ri8_`zM`Qrhl>2TYZ;A3-_NR_h(YH(c*mr@K=QV14zQ;VTgZ;4zMt?i%dw><@ zw2k0Z@Jo6XoI8>+*F{ck6BhG5s*UIX6wivbRO4*}(IjjMoDr_ltt-{kx7Df0&cxiiG75&9=Z+l_zqy3oW|bfbRW(@ zD7t$A+lm=Z%eFS@eK_KdMl1Y2;O4IztuUbbHjW)UG7jN|$+a~>qeB4L^_T(ZBCRfX zR+mK6s3}XO;#>o`51PL&xR+*z+#?%GnIN3;xciMh!TWG)C|k{nRLb!E*zldKJoSfS z<0NXRqp7>Qt<}`|j{q<6?541norj*YtmTycc66|Y?k9j7pQ~x_+-BhP%~CyUWqq<& z{a?V$-&WLTfWcXx0bsWtY`HPhv1P$NQ>I&nLXvsmIubBWJBH{2{X8_o(p+}*Uw3H#%OJwGxojRE`xMdvrh2hPf3+wATC6Qa5=*tMt%W@VX z0yK_`s)j^aO=f*nygp4oBwYk_PS&MsOvf_~iQ0IwvB6PtKE}%i7q4-d+OqT-$|#y& zATt>H&STI{>1^G`=!OEQ*-p@Gj6`O)-IUrqo09*^lw7Y;=w*oE?&A(D`%S(h$a505 z-LbDPblm>k?9o0ceB`Ble4D7jd$dE$aH%s5nW;(C;T3_buX15V_ot2SdM2rK$JwX$ z-mUOzgvTmxe+G1g+#waX3oEv;hPLfkfv~)!o#q_Z-`21C8Z(o8)>FPcnn?za@KWJY zKJPw&EuaCSg!BRQHP4wcX6J^2=ca1(Rck1g;FsVi#r%15mnzZYcwXgc(@)^J8g06* zr=r~SnzUTXNnseosj5U$YM!tLrz};`(9_h}ySc4LjG}rS<}(X5z20eP-`>{M->0^+ zv9+N3BkHsXbK~vxSjz5JdeD=%I_sL+`!tWHeG2(>I}KZVxavizDf|Bb%Q|kq^gNz# zbk;+OL|@x>wVO|Qx4ST<7_EjrWjy+*7rfzR_>xS-k}$j`7$oKJ2`t=`Y4N_cOh+2ys3wv6@2H) zBFro6HF;LDh|87rhNfqKpDT+nudKhyvyw$zuB^XldajvrWfA6;^$&SgvWUx-^-oRz z1AOPoBFro6U3pfrh|87ro~C~Q-?_2~^UC@_o|P=(a%KHj)Bhabxv~iJ%KBKIl`P_N zWrZe!K6{oP^$(&zwfe;oPStV<(<@@Ys@u10RdBYzVkfzIb8nk{hep_B4HHV;qSzvf zF|TUpy4ur9r#V~WJM=p^?i_+F9DzpWuf*|8D=~-+nqy8?y%JjqRvPNKuO5>)_sRFj z%3WmyzPp>Hl zt0=>wAc5Ie;`lhNPEQGITvdG{j&}na3_POY>3BtBeWGDQrmd`edyrsme7**Mnk+E*7)PG zgv9hWu7X4iK5X%{pX$HJPT3JZE?t+Xsxr7di^FD8WpZ7nKAvuVB<#^3iyC##WPc|eg5R{|j zV+O9v#(Jr#m6FFZcvu6C>O{_HOJjV$9B<83t&Xucqr3{3iLaN)mKu{!k)>OU)>c{8 z5YN;>)zwU}AyMD4md47eO4P)uM@_PIQ`8 zU;&8NeyFrmSvtKgSznparZRPl)rhuFx~wXmDMv*$B$bROwZ!Axn4DwWD7rVgU3iLWlJ*nrK_+7!&5W^>Vc?_+7JlJ$7A0gGeD7aObC zs%>ag@}^mu^|duLsn&5{3pe^S#B1tMd{Zr&Za+&`6_0Bjr(0M#{Sf;DsYYR}O*NQy zvA?B3S6ff@IdGyUC@+|DfbIz<>z+WZ-{K9rCTkMu2HhhBU{udw_ZuoIGF4^i1}@OG z#)v7Y$W)*Qu2C%@%;(y41w05;9+(Euvm-)N=A+3YEZtBkqP4~I39Cxk998Qk-3AJ` z<4u9cORZCCn3haEQtP~Wj8^%sXN_|2qDWh2DlCHzks|R1VlAxUc@hh(v~#kGM2d}K zO{S_53Q!|h0I;%(3b+eiy4EGI&q+8e0eD?}9X1LuWYCo|=m*lMG-;c#0`SS2$|3Nu z2>IC@`Cg<3J)y{jRRC|OZ^S!Z$W2sX#MVK2wJG$-bq$%?1UwfFMDiIW^zrraOgdgu zgmyl78p8! z^`ZotPf=CDlrh@U)98axud*hS;N=gAP8?|H=*TQuv}iG%a0nFY05yhrntksbxYLaK zTjRdw@IFC+@J~nnL+?~$lv7cOnT*ruc>p&(2KgUg_~)y6;tV`v$6#H1XG2dvHZD0Q zBdpNbTCsUc?UtUUOC0Xbgi-zjg_iW3!|lQD(=f3lGa-xm%)+;nXKEp^ z5#xW(b@|P8$!yIt$MEP_msy}EpPwF)k(z#oujAAuqW|{0AH+k>UvqnuodUfhXQW?ip%%JR*@<64bi9g z)9bTv2z?Io>QlT2`a~mB72+F`tCOy`!#z3`Punwnt~L6M|MdDCF@!#)UVX;zfj+1=zRlA0mPOO})V{qkS0`O> zM|yNZy&;c1&#qBdr@yk=jx>E?K2*o_O#ykE<^O0`sr=7Y6yMGy!uSt1N&s> z>z!w=^s#r0Xq{9~S4&$jdlmLHgyWq6;FY@(nvL)<1uqc|5XG$D%N~U15?ngQYv2-H zaT^^m7w~ybMQvtvTVF=KK+YhjQDnz}TV!x4gjnd+`2xTZIn>ps-)t|!b9H%5uX$dI z=k@h?=0>=tSq@lUmOmVhH(DCDLSXz2QDm%PM+uC-2bSE?p<%}ej6Vnh7*E`3c)7rN zv3R;~J7DZ(x%*rJxcSS=-Z!_<@s62JqxT78;M+xdA5HC!^mq2-y_}4U7>&7)7Wc|? zJOk(uqvJl(KK{HQj2!i`5Aysb@YlO0e5PrALY`nr_MsUH9>% z-8X#y(mSono85Pt)V2iKVdn#JL~e;#BV!T0uuH!lF|R|6_Y+@Cyg|tAVyXoYH`&9B zS1VFlT5+0#n5S-T$PTs+<5@~_A{eM|N!S-(VO!t4Fs=q_Yuc{g%USrMFee7;Z65cq zI9E)1tXdj&--VhtgxrlZwatD}Y8%#^VbUYLxpNP+xNo~O%*ahc2k+d9@2naCqrLdw z-ABxG8Ug2gY^~uz`iDjrJva06uP42Y+s<<~X#V33zXxYzZ!|bPZ}ZA?WksBmw5*Jw zx3XMZlffNp_I$()T=mw(u?K;rZzIC)WOIV8My+!KX%cmc>g}S>6v#Z6wrPQURckpS zImr(a1EUuO*r^Zx#Im(Q9_O%a_@h^siVBAgJ-rdoLSIOd$n*f`}cgsBpnA2lKGhiivbx9D2YBgH`o9C3bZSLx6 zvl6u2t-vjEPR&$h+B3T{Z5hg8f5E7PcHqq4Dq|ybv^;HQyqgPAK8q)2-*Q*qcn7#T zz6P5v+TLl zrCA-X!}8ItzOf#4aoQWOk0onWtUX-I|6AKohPhq|3;%m#)%6wsgoB^UAZG*MA z7PmxtZEm0GH}Ho!rmYPTtHEB`jmWbh76D)gL@iP#`!Z?&s5!jp4Vzk1-zu0HQCB8h z!xLcb%IJpvB15m`y6}7o{=4lp?DX&%`SluF{oa=OyL2I^U(@X{be^*vB~Z%WCq_gRC}ZBP1dEsHYU{PUdCwY)QibN%Tn7N_3-QaAdkH_t1zoU1IYk>mQ=H3paCmws6h=Q=IxdPDCitDiRP z+^A`9GPH>83TTUL$Fg}TA?Jgpia{v1joxBp=jeSa^Y*lv+q5oUHS`we*5B=eaBh8l zBLHXW=bHu>JQLQQEb~hCH}$oubGAO7ixEFZpYkmu*WJdduwJ!oVMQC{{z58=OCH=~?~`HZ@G#PE8`Yj8ie zIJX`9`_r)VOD*RyL+kMi=1Y42IFjf5O7lEnc(B*Uu^SPkve>ClVzU=7fH@Z8wFqD2 z=%59)|BP4#ADw+Sfwz=l%!ruZQ;@CKPFkEy6uo>fAjV~nzE5j?bNkX~w7$<8eLZu; zH)M|ZRlMosN~#kSjAJoTXnlBQ3=3w6G8f#5XT0(1Y14DVQ}N8x(M|2!ZHTy;OP&TC zPDHC{RTnFA&IE2ABF*}|2SfDS@+{yMIoMPPz?}nJDRG{~7xlgX@Kq9d(9_jnR&-k4 z7l5l~Ua78~Z9S?ttdCb zd(^T|>v1*U-D1mj-tulwq+AR5F66@#DXy8+ocadfvSN$g-maE*gm=1URZJOf2F>}X z1D;W#Exv~5ix~^qv)hV8DR4VC4%F-U_}4*mrJ_+fvdVk5s}gFOJ3w=zlwTcoLv^(E z;D+xuEzHQe6LhzWErzH2F6h3a^5jxobp0M+_etFVqN|2wxDW9Em3r~Re+c-aux(ST zh>*JY5nxX`>w4Pz+N|840QQ2a0}J~pU@tpm&0V+{*5v;)z}`TVWqe;{_f z%VwkM;unCwPq>?vKkVi)DEd_(I~{uz5HKcK@|s{2%be z#AAD|yRE0sM1emC__R>Ynh86mv(ZC5&pgc^b_3WgxU+e#n*0!S6*!4&W+-}ew$FML zSZI2&1b)pRy|uruwQDEteo!mjsxI97-fE#-5qNs5-#{O%N({PTH|kg38G0d5qG-t| z&uqoBH^hjFxYLjeQF=$F{0{PEXElU!px3vje30gO6IoH{(fRkF-2@nWLH>Uk&n&wf zM@6*FD|`muAMh=FNRv*|x;Lc^!q^l4(Z`?X{7Lh_X83i4)T?-Q+&;n6Ln;4x9r!{g z+1=J@o27jd_J;7P3f-eOVLjfcEbJE1dn=k+w(5TQCCSSL(hvVkSg4}ewA&kDqiG?l zi-hfxt^{h7xNu*DF8BBT;?Z?pNY$7-pWK5}T3Pqqah*glnf(&wX#&H7UBXwy`@)XE z${G;-Qr_rB5k(YS?qMNso_el8^hgRaKrvnqn^vRQ6LS8%^}mh@8e0!>_z`6ZO(4 zw5egyd6E~8d^{2aKiP{n5kcBU#!shsX(U1lS!lcAhoW3RS0N$s$|3BxkC#^E!Jvnl z8XJhH%010XCjpjje*1cHGzL)24!d%=J)&Ofdp|FY?5x){AZ{j=Oeff~(Ys*`)cQ~N z(xN&Mol+l9A@anOLDTK;rK_lc2O(lr#cbekliO1s;H676)~%^Svvl1Roa#aASgYZ8pjabsi; z^5bi}L-1()#75alJuJ za-CbBi@dbbzp?Su+X&UgK0L2w^R+9}8H&x8cxlCnafe%~1~JHp&B7KE8ld>cQZHSq zu^b_R)#xW}@60kR^U|;(*OYDW_qwXzINVDo0hx?!mB>ZA>%ZJbBLUS2{L1a_mAoT- zw2T)<{MiuW2hP;G{jn4i9wSxM zZoXMtxH~gP8yx1>H<`3OF~eCVb{d9!1I@k0pf}LBLJ}gyG2L~~nNgOyN5VY^@c+PH z;(1fe=XvH$HQtHv&C|PpnLnNj;F>A-4h^%G%7x3yB>OA*bJm9VQBJ!L z&o*x6^aW1y_Od?w9#eCFUz?8YAWxyZ>E_-D)>doPZFBE=EHl~}_NoaOh;~Dp47{iU zc7hJB@95p`Y;&GjZHn2e>Jqqsg8NK*MA3U>0+;3_W7--LDevD5-}jXkMN4V8jPZy>pg)ZDly<$> z>%{@|9g4%;ov_r@_uQa2+tuq3>%+qc@-4G4_{aq0DSqL-38WfVCl0y^1oH|DPt`Q8 z=4vB@b0~?rgk61Mj^WZ^UnYb730?uIjzXvv0_G4dO%exBcv38b7@{;z-l5fbZvvSJ z?bHp5_9hU+tNNbc7!J7{5GTNR^CZr(adCo;eMZ&zfDi%yE6V=BMnwq?w{ASeSG_Ds zPktANLunE@q}RnfDec2!TgR-Kc?#NxtB=>>T)AC$^R%)LulEi!DhFAAVP@c`k&9EH zJ$5zOQs`@w#accx>8^bc6xw@|nGr-&z{hzedS3iRoT+?Qw?`G^=;w3My$$lvXI`j%(3}G;J}n@~B92Z?m3+XRKeE z`uH-fwyCd0-wH5|@VsPabyr`iqhFnMo(|YFz+?hg-qY38+R|k10@@$AlDwR^Lx?(N z3p@Zg`={^j#A(+d?+~^93an-Ci$mJpQ>LSwXNk~^4s%AW!EZyzZ{%g}02(rIJ&JSe z3G)m-)_k-HpK;5N?ZNpx%5iPL`r#X!`5s*gZT;+FY?x=&pGB)-i`v)p&=#lTXfapf zTnwk@(~XFJs47FqtX>o0)I4D3e6SpHP1fP?Ja-|&(2@0c81$5L*y%?9xoq>yR*(Ge zF!^^X8?v7D?Hjy%QioH!V=^KbeESTeJvLMRBP&T8-O4jth=R3Kf6U+c_8jN-ls%Vt z>`DI#x+{@gbr2jyKu^Nk!e}Yny^*Y4U4!|+dhUtxK&09-)>cClYc3v#n%!%OtMFFE zbMACFTIqig^*S644)3Bya6*=?gqB%`lHv{1>Y8MESxqw4kcn3_1RC!!)CN%i0tH0R zU_HZ)KC+RYu%a_`^eA=`YHMXcR+oOU+ovHtU}V7&5B+mDbi@pwO$AontWUg@O8p=P zc{{HA_w*lQL+W-xc!TsQD?nEqGK)rZ$n+k$nOpge;C1Z2k0%0u>FpItwnL%ItKGas zw^Mn}S8};IU~~}psB~M8TuAE4qaeL|dou%5+}WAX7AhIu+Z9@j-~|C=?ZI7)=)6VKEW=6YG92{oiF%+#@f@rS1voZ3$_lYDgx z6?w3iX5~qJ>e?gD%;M<~h>%xk?McLAFU|5|8QRy?($!&VnfOAd-QvYp5v9pHDv$D5 zOz*3?%c4&brD@xjjyANKjgOPoo@@h{bjvKM6kQ06JiSi}JYG*mNR4Q{{a$q#^TGB-m!gX$0A*b>{rp-}Ig zL02`ZcyZW=XxZA+)!Eh06FtO-c|OeYmiKpHokMuU2bXH;>F@57H|eIIt3+A2E~`{0 zmE;9I&Sm%^9DVfpskoG#TPreTOY19vWob*CLTWYkQzJ4Ki|yO{w|f?h#y9o-P+Tm& z&DA3Hsq)&@j@G&HtT62mF|abic;>FsH|p62>k~KX$c@O}9?cn{7j(k@9Zh!lS>F7qDP4UJEZh8}Fk^^m0kYVE4h@F82S zse;E@64?_0qJnxde$xQCGNwvo=$G`GCoLs+#}M`|dFoV~d?4$+!~ zBMwHw;*y(HQ!r=oC~K_K*wb9yDyQDiq@_hQBF|z*+!=C?`iL{;N^z~|14jH6Ydd(R z?<}N#M7dW} zfNq@OYO!3sx=&E2Xu0xQ-gk$+m8MR_+Zp@uhFtHyBA@NP;(WEQc!H!*RXdB>eBEtCI zQ+6g;ezp*L=84b`vqlo|XqK8PnkSauj#m22MfOsA)6!bZG4UdNgV7Yvb-Y)^^znF3 zERnfv#9?}wr1O}rSLu97mkN9o(-j*eUBEPgR7`A5A)m_;)1_sP7Q88s%5Mx|h`liP zZxsm-f3i&B$MSh?S$(3+ja3*&mZWDzE51Kxzo|l;C zN$Po-d7do1s*F<HjQt2hjD~rh z&SzeMQdVDIrt4;Z!YUMiau47$cfqjmOVqjhLNf@jNzu^Kst#1o>j)s5R2UV8&^S}RqSk0($bKuUSZ z!zmW}3f}fFEx82G9{W41$g_cw96}$?I$1zak&GWuwhU)K{ur=C4KH!htzYue5N^Mj z{XKzm=41BcW))0Xrd#wTv}m|_ysohpty!nok}-#~Cu)$kak<&BZqc%Wh1;*jISAaI zorW&5?q`W)HR{DJU4jS&#>gSAP+JY>ER%?Y@bcr5;qv;jdey3N2ag{QBPQ!s%W=-c zYPzAaFxK;aIs{xHY6u(gxE)Hi;*}NivRq8&&>~m~*PX@78&!~^(cQhpsJ86bB%YS& zngD+ePSv0vo~Y9`%QDoXd*C6}N_D>x0{B+j+xHZHEiU_FHR>CXGzE1DIl3^cJ?s>( z&)`Bv?ZF?5>_iP>Nvf0ZIs_wS5b1(VZ_+VlFU`9R#e;AIfEb$E)F!I2n@yhjwPo6d z_+>L6K3?tOFq8G+@Eb>o3JG#Cvc)D+hK$s+&sGX95h@DKdWQ`aT-{Vyr|xo7p6#`X zzRA$w(F7V0(SzTfNa?ErwJqoaRwj=WXKJ}~k69}^ptc*=o`-Hy#PRHHA?h>@ff z=81h7t|>KT?Cc1fGby?%-48SRx`HXwbPH-l3#xDH?!bbwx1y^DGabx@u&QpsRY2{X zh{ssBY&bO98h1R*945~(XDWGjje7Gj%G}76{aDX7(2MGm=%Tq}zzBuYeKe}s-sa|5 zyxjB$|KKHuDuxVqZ>Z@EJ7z@g;WVl0b1YnL-?FU@Yc7`_uP+QeB8M~_x3TfQE^tt{ z*CPh*)lHp#CjJeJSFc&@oskC{J_QGd%*4#?T3gjjL=&lrh<+GkQ914BvG4{=S=qnM zvKIcT-L-4jkWR&M%bVM~ha3&#h{PWT)jk(Ca1+j@+fu~9ZG4*Qr}7LO0fDPAbg=aK z7N*=wyi3a;WpHZXl2N^AZh^c9;9P9GvVc-f89=3d^Dy@u+~-YcttIq%*5Lai#O$&* zRgr~Q+vS3g5p?BlT@Q5O$^u=i+|7zq7>}MmyvXElbY}XTMw`_9IGw_EL@#7urDwt= z+D#-=AK+PMt^JKp?ovQ_xL@d17MD95I;WyPbSDoCDV7&t9$DcgR5uIc_wJuTLe+?*f_I z1;QG~DN!a_l|eU!`G~yX6Hkh0yey3{#j;`3+MDun@Uju2arqjD2?ypFDh73wg<-@j zXK$grxWLFMt7EXET;pk4M4`sPPtb+N8*r0R0eDD*G1u%c$9CSgqI035|M0kn2cXdy2uF%n+OkK$a*` z6Ga`-(Vl`wA5>q)b*C9mQ9U^MA-EdEUN>?ItZK`g$PgTxuXHd9XHH@W&Rl|OYuO{S zu?%}>>*F<|6i|5=&%qMx6QxqzH_vU7EYC_-%v~=AX%t;A>%U%s_k--g- z{uP8dEur$|1fOJPr$X7ooR$!p^|(VdS)ahs8F@DbXOcDb=}5qZT!X8=+n8>?7*ibez~zWE`#Of@Z#m-*&#{VR^>vPPaz< zHn5^!j$etzE)Mr_neTZjUm#uU>IY?A)U^F&H0ycp4I%bazeFps9b>%2on>-ckNnmW zVYtD~z_>%i2hlq0!cnCH7VAb_IO`JCk`j9S4z7`tz?DsjibMmtf3!ti%6u2kTXn>b zxR1z^enFMg2v9A{JkheA*qR1WUlzi;{xI_snBKzBzN28Z$;w6?=F*xgn0?`+HN%Wg z_^pp?xtR3{ydo*V{ZdNI_5_A2vdc`*SD;~ybsTAwe->&Oi^@9XyC;_PORA)_9Oan# zpn76SZ9Td-jo8~jfMXrpRBUf(s$?j)XD^4m= zS({EsH_(U)0k86~`;Em^zoT~oND{%w^q9M17874 z`>EvpJ8CWf>Z`$sBlojd%j>&?@T_VvUWT+6V^A#Cwz;*sSD@wgBCNx ztZz)7VdqM&9If5m`$Fs~^R?b_d3)2z`bIYOPGx(0r{}rQ!OfgKUGgqpy(j5x>eRmx z#phyYdsk})FAxzE#Jd8y2YD$ppTfjC>B!u%qIe!aV+B;?=@_~Qw2he;ZY43;7Z0QgX>pc>xNPF>23r%~c zfH4Ar<}68jKZFK1RPqny1kHKp$b;uYXnJ=GgkeFE(8;WN-=EO5HVX`+ENJErl0zL1 zTe@OdiRW+e(iNr47azXjh{HWVBo{AQw0!yUl9D4pN<{dChb8&YGKk;HD!&&ZMyg4sjPP58=Fo`t#bG5L)|C8s7UirdZiZ+ngv` zyfuezl~cS*%Bk&6x=A&T)67cp{8>6}d!lyYe}A2a2uVw)?N997;~eMBq3CoSknRRt zk{!K~DfiFH)Ac~iOJ_OGU3a@QOpy*IT|nn-?`Z2;dFslIJKH;3TeodIV)>#)3l}e6 zT6*}x#T%R3J2&nsUB0osY5B5^ElU=*c65}m87$cBfTMRu=k_L0Z0YLSf_qkQT7F}H zZ}Wn_o~9k`y&L;_`a8F6?7+dO-sWu^dwW_o;zE$-Z5e!I+Izbewm1t~yLz1kRjoT( zRxDcB4V4#Eb$uGK?adpznor)`)0WxUiCc3;S^4m12pVU>@g2^B)w`Vq>zrlySdWLa zvmm(z|C^UM3yw>qsxq5-o4QJNcBSxcZo%WQ%@&i;uda2 z1l2$9JL0@;-#+5y%TAkp>Y~S;Un}X+D@T&i+ux1X>%F}q9|L`ln{nklUKYa7yRgdTWI(pTom)ni)9$bJU`W`>|=ZkLm z%i?7h-Rhk9!aug%AH8Gs#|*>Ozfmj^D{_xOeF*$boBjVPh1 zBSWJJ`|@+2yu1IJi*HPSIQ50cfB%1TqSuee?keDl$@}4(yZ(vEdIj*sgGWJZFaKck)=~JCq!==k<+6TG>a@TZR+FE~K}0N2XQw@Or75 zNO}0PPiLPP^TJop`P$P*tStTahUm>BNy(M4^tYY!zH$FA&pY|pj=bx_6Mq`LW;h8g zJ$)PTAJ$O$|7`JXmy~=q{&nZv<8NQ^&zo%|35x;my0FUmG<{FF?JOI}7uje|c`& zs3|wUcEQT4U;gqR&(DkgV)O{i?Onq7%(FLM^VczFv^MNlTG~2o;|b9hibi0B%9{7q zC%*f)bDp{8_=~=Dc+;2Pydo66wRj}nooK|JeVZ4ycXpubdg42ek8O%x^49*}Y)0Cs#m-7TW_?EF`LfAFLw2Msigd+DGJM;1o!8;O&{R@Y8dPiH;*=(gW| zb!xPJ*PIW|UGT^Kq5~sw_qJ|>$6_)kx#xf9?$o6fi{JXnZ4W-#*?jP-=nsbDXH~WB zYUx(ZWJmFfXTGxj#`iX@x^GwZl>d7r`rJsoFnCjs>gyNgkNNZeJbUEAwhs#)eg3H{ zeiwayB<3AW*0tYV^|@OgnRkry;Z+4^U--Q{eiMCRIA$4UU^CrK?ApF;_4cb5ZT;g7 zAFbc=%#R<8zBe4Rw5mP?5sJA=Z?D~a%bJ-R-gx}?AGW1#`$4p1(g@YO4Z);s9d55s zedoWQ{PE9TF8=H3=XXRBPfm!=97)26y~3=KBs4emw)OS4N(olH^U!OzJbKWP{r49w z`rDCbd^g%Td4v*d>2Gf}wsU^_$a{A`);|BUyPtmaYj1vcYINST5xBd1w|3)z+cL>~ zzvt_U=Ffiaqy3VP{HgDl7tf2vM`Xv%&|nwtr~Yxq|NLn4{KKBRW8i=lx32wj^m8-z zEb}G8zH0V&kBR;IriXvO?%&&*!heZHk1p9W_EKTrotSs^7jInr*~`|P);;fsxA#Y% zI%ov;ZGGG6II5wBCtUpExF=?>`rTni9CXYt)7MA;HJsOJm+e#yZT9Z(y?xk$4^&Ot zeCiu7ePMok^e4xRkTtr9HeS#znm4}n=Tja&y#MTb{_(ea_pOVa7kzrp$n5kP;r_v# zd!{vA`SYU=&hHp^>wiA@Mf8ob5x8}gFBbL<71{a~mpAWs-UmgOeEGZQekS_;k=UX8 zmezJ*{?Dn!$KBO_T>CY1n=eajdgo8kL)u2jyKe`6j#zlV+uj)}U3tnKvmT!C>$&T< zRz&YekHCwJ`+If2c>1+vM}DvSx`OZDx%7>iSKoLy`udiUxjQ>lU7vKwp9+8V+An|d zFN}{Yc`*8*;QveIPt3cfAsn_m%esvbldiknN4@TeaD#a z3m4vV$%4pB_ea;f@l3R1BxZ2-V5K5i@7}ljxNq%q($^z+2% zq5t*HIS*abdftgg-+1SJe|oy;j%fIl5twm6v{x7U%yCz)Onl?=t2Vqk?kf*Y{Q3Vz z<0CPnvas^msd|PFZhz;Mwz+4NmHpwS{W~9>x-42XB70}2D)W(}b~cop6MAFx%QMrb zPdoa-=wEt9P#bd<+`G9&)z|XDEV6SXBUjfj@^{bovNMPckJZ%FDz`h@cIAiKYQ*w<-dtOI5K-zN1Gb? zPyJ{5@?%~sy!^E9FKfDU=d5o;|FH+m%_q0Fs`cqBr=R`UIefX;v zE&1(#E*cn!M<4t9i2Ue`+Phl%l>Su{Z_6J$_o2VWj=8n_(pO)f8C~@5umWVMf(?LX zH6VW&pL$gHU1#k2#S8mhd)XP+elA+8*gx@B7&aT#wxWImAl9jUV%(pJ4_VOFk-;37mjdZmkD}tX| z`}#@Y=^tKQH|E94Lw{R;XY}$9#HOFrD6Ks^GMJ=`%-O%Y>y=ZRX7(KWr}w&l9J%wf z=!c(9rZRGCTXX-G%#QZ9of%AJyY*~#_G>Sv{(klD&t3ZR6X`7{oby;T^q)_qwAKY5(xq!t?Ikec@RLuKH5+?7fk@RgR#jN${PAA26o;h3CKgi<+-)nbdN?&goy}5YvrDoWe>9B58%{C_9DVKR zNcP0HcjLb8b3^%gB~ErTh_d@H$HxQs9o&*f7loYhkNp=MwQbuoatGO21^EsLPbJ}u zBk++o7H^3_7(Ou;`Z-8L<4=JP@yHT>m6*4gQ8ehjK#p50@o_j__MEo0IFeTz3r#yD zEKJNKG``PrN?w}tOXPf}3LpOh=V4omL*Z$MgcQea%fTC_-PWDQnS#?W@(Ny;Ljh!sxsEeHcH<5=-@b;_FDTWwanvup& zf8m#XZHSL#a&E}U3+Lf|^i)fPKsyzNj^j|(N)@3R1F5TDg|-Ma3;c~=C(BC|Lk>N` zDeJ&56rPWh5#d57l;u4HxWxzDIlm{Yctn07S{<5HxeMe5~S77gNyAX(<#XGo9Nl)uMKyHO(hhS9P6<&ic{j+3F_F2((;~mP6B*IoAYMd-@5i4?T7b$7RBH`DnUB2f9`_4ph zv%b8%UZ=llXGYlxHJ?|Aq8=wS9WZdpb3PM@7l0^q{-38XBm7{zTe2t^KlCul(F}wg zdw)6IrJjxwe0-gh&3l7CRCrNzJKzz)c`h0U>bIg@QoC#JPiBjoi}w^j_=hixfO3gR zl^=_DvM+%@Z`EN=2UhAWc-y-UUNeSXbEM??D>@uQ4;g%=Pp~3PxEut(mz*cPVuEKW zQ2!Em(6!H!lc+Kks&q}x_jslz7{1L)c*ANN9gY6Yc(?R)?^%!FJQIHxz<-awxR+E~9!hix zdP_7a_s7kh>=RO^%3IJ|qRPt9&()}IU6|M@{C#4o64B-yhWQiUh0Y&5YOAna2|M?9 zCv44UhI;XfEjX6o9E2bwG&yzBO@pY+7^1FQcc~fR{5YIQyUp{<(s>x8FKAPp9QW* zVd+$ksb7Vu^FHX2u8Xa;qpg#TRl4}q#7(pqkM@9WoN7cxc(l{z+_?M4hT*;{+&JKzRe-=NCwro(zt7~HsmaR|b@QK9=q&PAVZa^VZsje7s^!YW z2vDx@8knV>X^bJU7X+#Y3SJ z^_RyS)9`dEQ$V$kpGqG`Vg$7R*AU#2?+31;94`K5kU2i*-p%gvjEBNIsId1^j=_rO zFrP)7Cr#iv%V?6 zW+4lNLCb?e5Wefl7zc98aY(tmKDjRKZ_txq#0Oy`HPMh5U0h1xWG9Gu{_2rohN*J= zI)-O*K>zBQQ>|m>ooul%&U-{p2aHFm6A*4Q;|lAilTvb{f$AI!o&S1rtBS`f)1GYh z1O0C%HtHUBW|4D>ago6_KS^r-zpQz$4@tT96WnR0dzNF5=3I|6smS>Z#q#E(!D8o2 z$^Pz968CIkp%pmC9ETcs(?g1Qb)4eDF>cG|BABgjmkQTX!x$~CQ!MU%L+^70o zFyKc^T<_Z#0&kcNkJHx|I1YMH$1lM9Yd|h1=QgLP zD@2LZFJ;Re%AV2c7%9+OK{jIdU}SnMG!`~pqvxS=gwK==rz&x>5AMQ6x%7JM#rK0~ zHBrWIwRk7W>|tJ-n9}`iwnSFIe;1cf*Vf6oPA3}|U-{RcQ38GZ7}w39ZL9`7Z$^QG zIaDV)Y3KZ~EC3^7om#D+9F*3}nF^Ua;(V0;g(FNl%$a9oW1cFi2_CIA$Jr)-Lx8mZCXvA9hN`X5h0&9+WMyasz>8M8?9w26ID zLo*)Hovpb!!0l#bUJ3_>8)z4XCR-$*S;)tGoq_yXl`D^H%3J(fPxi2)lRa6){o7+s z{NgZv*%iHZJ?_lpWiGOZ;SRg|pgf{KeNor^R32YNf1ys zKYLdmA6HfV-u)AYzoJQj{;H*!u9!B%e$fc+a~}*LTeOaWA4Z*w01kVX1V`X4v<7 z`IL%an}0(f?+i#e{cdPUaiE>=oa8m%LrRLRZ9QXEY}GOyk?$lg5E@TghDHm3O3ibR zWLN|P+oQc~C;L(v|Jwa)K1_*)f+-a;DegyqDMJ)(PL`E-0nczrqZ;AKN-t?9I`xXDPDo=<<>-FjkdZhwo_AiqmjaQ z!xi|d*yoOp>(r1_)6v?i*P3K%*d`6mR@LBCz?`bb6?r)icr&#nF$X;RjR~zf9}=b= zc7Ud6Ka5!5-0b3b4;@DPW+7xPj@s8l(V+u2 zM*1FNOjgI!J|?UuKP7FIYLEG$J%swWlf}Eba8Pn*l4Q=Z&ewQE-}VqWtONWmnXC<7dTJDLFnL4 zvRB6J+c;*o&NVQx^;>=CK=a1~d8C)~s_?~1Vl+PL&^1ruY$wUa?hv@0?{ip5@DHXC z_Y*>#jjU2WR^3pIBU{qkjH9EOzOTsjaF(x3Kq);>hgS++FaG{D7yIA3dpI;e`?f_2 zvBp0*+?qY9pwXbT-z?@PEZ@P4ywNjkbc2xmi`_`3Ol&$KJO%>hAOPg}gcPz)5~ZDE}75wPVc%&I4jC_EPEh!hzd2MEPS-VCtYAth=TiS|iP& z6g{Wv0Td2SEXZ&$k(1=1RQb+Vd_($k29CCb28SlIq=1K?@1vF)4^N+jN0jGb5;UYg z=G^z))KP5urNMsN!g=D^V4~J6eJ!F^3M}dAf=CSiVk=x&JwD zKua%G$C1fYM9jgE?A%mtW_3eu+ElD9$0~u~H{B#9Zw`GxDSiiH7dS7y37=s(`-d_i zO^)$(UbtTJc!w!CNnY5I@0>qJj+s*@JtC%~j|P-!n@GsEyY}z8Gh_S?#;V4V6kB;-Sli%yXg16tFw$^% zrPv0y=joM;t#JtDnUhM|l&*irtIvb8r0-1S>3wl5r_3#II#5w03^L-%$94=t8(8dK zD~MA9n<^Wl4Lpt0N%Dr30;k4U+`rgt$SL$rlAj?LI3aYBR`klR9=tpS?e~-huma_N zS^X0xdv3Y`X3~(BTT#y11yjLaP2|;#QzcoVh>}qwVxj%dt zBqh#~@~aZZFtby~1DOtv^2Y^?ndPMVy6#9Ye$6;V-~{S*ufn4@mzkIsuFiMnr;;;O z$G(EtuRIGt?b~!2Z#I4u4f$%yx~#YG%VpW@x3N5qC0M=hL1q;j0MB<8r84FaZ^(VQ zK4+XnoCzPJ8blc)kiUk z;Gw8~(Mg|T{94VG(Fj)K&~WSvvS!UWPWIVq*ORP4dy6etp^#FcvsvQ05 zR(4F>pl)@hARXuaKbaRFaioK3eX8y$rK~Tc_6=|ZNIp8Hg?j@K*Dr8RK_5QM)dDd7 zabo;G&&SPQjkW54Jtuj*02fNrni_t>(920^wT7f z@dU|uh@orUPU<9i!3I{^O`6|pqb0`)i%#;xf^fS*fb;mb=i$E0fiAW)D+FofR56O2 zL(Q(E1q}ct9X>Eo;QRt2tLU@805(zDveP(v)^<&~ddW%hCXE8;LteA0MXeCFH zwI4!`rQ4L&XPHRvtE+D*Z0&7)UPNs{_?a`Xqq9>?E%rIca#{xuPHEec!0P#l{@SGAavHtkVB ztuP505#URiuDW%Sb%J-5!GoyYjjo7#O5!cp|Ejm?bIO+FMH2;1p7fC3U5T|(oJ1^* zIhP)=^5m)En_Q9`B=_Uj7?iSE1> zqrjO=pW=KM@fF^C=Oo(&-fH9>p;&oTbAfZZuI(crs`AgFcA1wUI)u_LuVP!(bh9Ka zG_Eg8OX-8c!R5jLI9>c|`Bb=?YQC`^|1ui`J7Vs&f!#u^ z#jrrD)yRX`Elt}Xn6w6dMN63v%oYk8jk4U1Z+CS)l3XTb#%hqF#P5vK$dy(Ey^`-$ zm|2a2xj`#sK~puX3ykF6XdUq=-sa#WuM|W4*-|}2bQ{$e2&QwAj*AlFAU-*~)^z%B z5J@bE5w3M9DK=S)oDUl=-u0popi%_LqJ&Z%V~pKm_edDARK~*SO+34~z`0YhdmG)n z{o#VbW1I_|8OFeJv$g7`kbj3H{?OP_LfQtp5mZg>%%Is>l65eRHK+8Tn-JL@!<40( zGSK9i&IQg=sd2cI7R!zTIN4@&jW)ox_}Jm9PJyZoa7Qo z>VjtMH%D~7uV?H*zF}lR{ni&6+IMd|$#aB5u|Z3}&K==SLHM~bZes_&aZGgB4TZw^ zsUZPQ-p$-jlIPZ9)@}6mJXA_m_40QiXZl#hR1q~?`xj}`eRLbRUWiV$IHuljZzkQ9 z1_MRsU+0*5O`PfL?lKzUrmN2FL-pHdXo>H!dZWNqH~FTQwWqtkucyo0Mhb-UMAAtn zFXiaz-rTumpwA4f6p8;5Ln;XGBo^bGFInFf*F;UpT<30OGV^(j8OKyS{yuwvAA{m( zAIE=^Pr00|Mf365R_Xk*W4%9%*Uc|m%s2Ir{)_wW_<@#_wd9=loAq2LZ}KV0DsIdC z-@pG^;C~kQp9TJBf&W?He-`+k1^#D&|5@OGEf5QQ!Hv02Y{|sU!9&Z6bH_*Af`Y8c zh0dfKf`?T^Ce6SezF6Qg7YGPkOxhScgYV39N-S`$&iX)*z{}lO;0pYICI0^+{=Z87 zx>>Qn)q+TWwwM2cmP(1T*(I z;p-k03p}P!DFGj+s)U&$o0}I4+?-2YMM6H#h|NxB7ZxRBMag%S39@IF&C0iourXM3 zSk8&Y49s(KQ&Y*@yz0_9d8M=SYGYHHVs2x};dyuL--BZd5JMWAled3Q%lLj1bW4A_iYuPS&Q*5;`@wae;mRIh za9>(2`4~Cs79Y=J=Qs(}(b|0q96w<=PA11sq_qT}CdWdgptZyE*g4Kr96tw+pD`Q{ zCdbdD>3AtQ&QculJa&%7isKdFc$wiimmDuk)A34joToVAdF&i<2okM&EjV6nI4&Z` ztEcX(WdC8evDc9+?;3z*@jP~}%M{m}!SzPNbve1-C|twf>bJAEkn0JGE1t*BwL)?I zI=Ft-aOLQ2@T+zkw6799Smp9>kZYCVif7GLI`iZ;s6eqm_cZCy*}W&9#=R%+b1WtK zzBoDn2kEi-g4eigu=dJTR`PMNV}U)UX7J7XVupFPf!{d;B?j9a`fyc!7C z0s*PX5ZJHW7alwXNG`lmqDH4u zBP&aqM#M|isEr!k26E5{&tuoke+2v41y; zX9bF9|85q~y-1`sM^c;py9c)cp#{GkR7PX3WYOe%MMIPVK>VUPgNob-N>BvPV^`!4 zpaDhBgd#mNO1B$D9tId39>GsZLMhUduE?WEq#{RaMG`=mL`}9+6OEpx32{<2>7yo( zffO{s^Vl_c7BryAE@*PrjM4$4$#VdM!wdK+IY&9!S(%*dMIca{h<37bfJ7e~pfXmD zG#?{cs*jybgR_=Ng6n3otmmi=UFcs%XwnFPis|NM)*Z z(d-2ROXgfEqp{OUhA62evxkZ}(?t6;+=|?bmg8rK5}O( z%w5YGa-!n-agS$U!A!qZ4b6o9frth9q(E$(PaK?%bE!aVoasjrXZPVg<--JGQ~tsb zoTH9T&-H78*ts4Z0{QVm<~p&+=QZV+bO{d|0-3Z3IPY%?D9!D)i^bmmo>N`=#+=gE z=V+^62XN@EIZZIPv${De^!6M+@&Br2Z_Nq)cMeQ{J#YqJpR=!G@D2PyT5w!|lg0lq z@k>aAQ{#E;zA$l#$Tq#Wx^!xB>6BtE+a!QX4k{j;Qp`!}UT5+Cz4U|`0EcE34^A!K zzo-0=;wFF&0%-6cpi%I}pP53mnJPEi+v8Nmg9({hjE2`;x_=LGW&zTiwR~1_=#XN( z9!@gk#%baVLS_>o5W=(8F7VsAetA8DlOM-Y7T;PX`u<^Fb?HO%w6cSM4L&qasc^(T zYT_>5S3xQ7u#)nR0ETaiA6rRmP*We-+FBfaRNp*xwI}*w2Pz z0X`;I1&E*r4+5zZh#r;*WB~?osW@c zUnMHsie4DOAMz!E zY}+o7uI;e^AA`F5Z;-^IZb=NBiNHA?llS^!G6D{P&J=`dAn>t7=l+T$KHta0_t!l! zPx3KjNB1->QC%8L=nDHMzy^Z}6T$ zq??0}=?P#x4lIsN5+RlAFU<8)pX55;A>Q42qU-hJ{oBtqjeuG!a@NW^gb+DtXf~11Zo9 z%x%mdIbFu2vO-HqC7|L{fREh_6F>uISOzm3Z)`9Tu)*VpYI~x{%1CUW1~Tfw34XI)f6)#A}?Q^2&vrF%>ACK%(3*` zqO8feN^*u)lS&Pr10hfxyRs*P28!`yC>u+Z)){3R0UoRys%(oW+l17T2P|b{T3MCD zSGJL2HdD;3Wk#26qm%!+9d>{Ya%_#KbZ7Xhh=-dzPO=(SAhrH*|E4ZzskAAKNK(uKb94OrAKN)R~z4oaDOjJV6l1=LNz$%6ypG0K#j> z1P1B>^@0sQdc3dRlh=wsLg)b@WTpdT_FI8`504We;%@+1$RKxIgDlBYM{kd+sONmeXm>6b+cHOclO7T{H2g1}3?BzHibxT%G=WhuVU zR=ohq8@L3@o4hoEfIPd&2GLz%B)=-Us(i~lnbmvpF&W@1R#2K3Yx!chaSvT#Brmaq zJwhwM#>-owqrS;|1j1XkgqFZq@u51}1cC7yEc2RdlQdpzC20yN*)CAY{Iblbc=?o1 z@D+jSLKUoc1i}qT*kZ<;rUaRjLiLioF^@9nEE;yJz<@+~G%P4ynTmIaz*6x-8SswH zfLE6RZ*2y=Q#0Ug$$)o32E2;|M&;qryd_H%;?^kjf_+jx3$t~T^g1lm}Nev$(QFN22d_DT%m@fs>i4)uzS zgqnFK+$8L#F*5ld`_IOAFXJ9 z8c?yp#drvj5%|llGmUTw5dtB38@mnI+rS3Lfqr%A68tS)gg@E_mm+bH@34XT$zX$J zNQV~eq-X=~XUt#&k~TJwi74%$Xc{}POVc3QVX2~fIiO;PEAS8^Gh+vhzAa7&0 z1LH=p18?)HEY`%sQA4Oztr?*{I0~NSA|7w%2z7P>ow+= z6sEZNhgH%I05xZW%8hsk5nq(NiErdX-=V{6bn<|b@@57q+<}aZoxG*ZG-LYZ{qF5m zB$9*ZEnx#*1Xf-83;fkK_yOR9e1{Dl#E*V1gI6dho-#NFQK8@uNfp08!f(l`AsL^w zvl;O6!epvuR1EUQDtY5749FVaxWgBL#jlqJehjFX?I(B$ksoaIE3zGvBWN?+1!6G6 z??I=!^mq8H&2Ts1B@g4>lHeY~=rp3%7OKS@O7LZm;1Qbtj0Ev}FOeT50n2NA^u=l= z@jhS;5^Mh+1p1N=X!75@^2eA{w*h}plz$G~5aA+MNnJ?h#b;0qkAfS(j%;wuM}wQu zzS@|-04)l}VbV&k@d8BJFh!1gyFGyiX$!xIeu?~27!Ob=s;&`OnYFyXB2FMAZy%(H z9t0f}(UV|OUHTXNE&Vh8=yLiU5=;JucgT*lL)o0jNX`pUukoSEPZ$qsST(yyyIkgOq^Vr*@;zcDvkcQ+EB7^5<2S z$B>0C@h5UsoHA$N8o&uJs7!y>nI0#<|5LEP3?aZ03#75tYY!`Cm%of`sSJT17zQ7G zIq@Oq6Pop3@oQ`wn5=C3H;VHr>1qqn&OptRIuPj@RssHl8W3(&6S|=G6xG#kV_;7M)|`XHXYjE6U*xTg^eg}@)aUWb zQm{C@AelnM2EvQX`J#G$3D2Q7)bl^_JhJd_0x?ba|04my(*=DQ3F!*G0+`|aDl`6D zaefWYBXj=GP|mND0O2F%JfLEoUH+C5qph#wsa4~HNrD0pVi^|_crZjg6Fc0DB*3Cjfx^;5^ zYt9MLtgvJ*-i-6)F(q5xO4vMoXkVDF1ZGE`$fgMoD^8?a*M_vC=QBsvayF46-3pEe zXhcJ6vpRNbJArfpA!&O*NFUM&I_N__@eccti}1H}KmO=GqzQ@8xLN(Q;HTsgq?TNa zKh_4Kbx0UwUJihEJF1P>LZ36c{Ikr$WNYit24o2_0pw3nL-q$l24I9 z$wUk;RwlQzSEmqqe1wfX`*-JYd+olV@Z4eGIm5tZFK7ljS;OE5hJm}oz-gKkIdieM zCk2q54saBpgjWS)7^uz60io{GTVbI=T1e)d1+&X9#WSqh1~}Yr=s+eLa}Ert3Neb2 zf+SUzxj%;4gsdTwvFWlI|D+<_fpqwuynPVg+X_1Hy(>Yry7Y4VE&T%iXy5BZBGlNX ze!A4pcJ(6*@out5z4hX!w4A%tu2#}!hlmz)=W?7P}lPn$NGn_*GWH9p&ke<=Z+9`gBbT|dkV(#&2N|UNqdYLiP_XYEW5HrTy4;d{L z_(W(aPh-}y0$TE3^6JtbgF)$!@JFdy8FQ;j?!qfMs)|}Y$Yf}*ellqPGo+8C{k=$s z_C$-hH6=gAuOYwuKD>nP#~%ZhVQ7fpK_ViirTHpXEZZ}Otx$3K&yg5&aT$Pnl8;eH zXH?nrOh>-SAUCE^G2^DIMa@C#zb~xjU9}iYQIwFPU59Mqvv&%sScrPW+y+u(52nB; zqcG%Y%!RQIg~1!&t4n_k2Bi=1&oA&tmB{)*KEwR#CxiJPLi$MN|2@)Sexk+P4TGc) zt7>v7R-Ie^hv8_gRqchQMKpY~KS+Tgn)=Bg+9L->j%YFWR2X*X5QDK2Hkb^QC_d~> zJn5yxl}dJr>-uz>DZ&SZ!|5T)A9Gtx5h`#Sicp@$T!ft{!V9Gc9|wcdKk?6__@j#O zj6ps_YW0)BPJcuCNJaQ}q@xIl7IU`^l0J%1lS?bYe+)-U7ony_w3yp9NP!`m`pF>L zGY3YFXfd~Y)FSj`mV#4?q!pZ&MHgX@DZ(d&LvM)k$J{eb5h`#Wicp@$T!d$%2rrf* z{3jTczQ{k%^Ut&RqssA|K|aG+>L-J-UPJmw<@h?%QI155xgQxM{rwl{pA6*Q9FCkW zN==SvILTs=GQ%yjbZKt!?*pSnw3vIornP$cfAAi93x7&Ton^rQQHbD?_!XDG4GawB zl8AjWW*|#iN?!@=Uc_-VEiGe0UuJO&rAWG4C@9;ZW&c&g_kj3v&1f&4LxiIdr@SEz z*Nb7&kiV?5$r>1K2f4WJWn4)o?*|C(ByVGOCt10IOMO;c>K!msJ|t^X;CnHc3=#}? zQa>5WKkMC*-6I?wGSPCZ@se-)J!}!cpr^_edS?Wp;;WCf_h9Th@`#KNf zYKpm!1Q24rm zQ)W2*8rP*jLHKQ(M<_mo(5b@_YR^FE43E$jMF_i>q}oh%-HvoZ)3ij}G$G)+tYT9k zQJ+VsX9%I~!x2hkAau4z=qyFZve7^~A!DO+GN`u4BXs@{iOx+YWK`RmL86a?kb?$> zEk@wKb8_*L6?hws4S(O7ljFF7EcZWiOwqnE$7yce;yGBc>%J}!DP7}s#S;S)vq0_; zTpi(p%&g)GLS{y>Av3kuX-{p&rW8B9b}Pm+YbOTWz(K{%4xJ#yk(|MD0(JM{c}jBE zeQ2Ij+1l0B*4n-;(!HazuLrj#n-*=Raqz!+=ugaZ8hU!Ve4JUpaoxucgv#?Cm1lsC zbC0_RdRO)J4D?pEcDHwQ88Mvw*~-(BvxW9ksmMO-LnZm|2g3SgkM&FQoN#-8=MFh9 z7>5VL5GZtdzkTWPP$-8XoNsPE1{0GAl=QO!FL^hq9i!GWOPy~23=ohzK3 zewC4$HY;(sRE?SH*PWi2?F6Ks4<;OR=bhbK{1QDDDzQpQrCOkK&c|=S&2o#poQIj5 zi~Xz>VvR#g%A(X1kLXfObcrUq&?9=3$vT8+$fOKMbcH5*qWX20dqj^nS%(p4wayvU zIjg;#l?jKpBDc2pcl0?Iu$v1w?wPI|9!l}Uw$;{ZiY=OAqen3|48^)pC~npi+wseC zIL)JY3Uc-g^x?(?uTD}H*Il1*a7$D_+_%5eZlh{#Nzc-B6Pj+fM|azBbURb%HsLx| zdw{qlCDoTHg=6{?8r*p3;10{4zRI3W9sc-2cQ@Q*r!sLN12aUq?aWD})%eqmM`WWL<;E!G zW852M+Ei}8(tH~`Hv3v^(pht}vbeKIvF3Ij#hQC}3~O!$8iutS;O-zMRt?}-dpNS{ zeR(zN#4I<9`-vQN9j{86o12xxWohA(!$oZoIfpCc@|4Y0Xi3fH3cq^d?gRD2)#qtW zAdr>Ky$}k<_2;P^Ib?I=g}`#S%|ktL#|Uo9bhC1}fkZ|a+1$yYxN#9%@@8@UI_N;= zEG~3U;ZuMM*lKLT^=!!-;3grV9N=Ccd2+c*JsUYV0ppGWr>VEYnl7=JT$kHb&?(tn zn<_syz}*f`r)0uNPe!=?Zh$*doKDGMLAmL`Y2PZ~Jw(R;y>5UT2>=!v9vFQ=_QV|Z zA3Wqz%r%whpEXY|7dcG_bP=ANRXF@Vy=PGh>^I44TCGu0uQ-w$_!LulyPleQS`u?L zTgY1eflPtG#Z1@&er&4~&YoOobF?!j*-v|6==MdV8`&;5MABuWtGVtMOtSCcMzE_4 zm)eeQHU`SPFvoY0Am+&8Qj;>w*S#k$200P7B6Oa>S4@J-wH#A5xWiTAEWou)VFLFSfY>W6qBLgq?m3({Z8Gkb&8G+Mryjayo&~ztb3QPV!tPqKBWz z8vjFLC=oe+=1Pw8M=rz|5xJ6+fsZDoM&MjqP=0&UlI7&_FSzu_HI>HiME6E^%tCYduol782H%6zi&6{!0g;z*HH^6lhr&p{O?cUUZ z@sTdTpdRNiOs|TL@qhKifVvi#wfG^E;68{aBk-?@1p6zQeYg22ozH!MsVd3iYxMbr z&N-yyq;O;aCcOj0&q^T1wbc^?#g=Fco=bxJ1fGm&j}vKF(f-8LVMJpjdjwO9=U`Hl z#h9cLh!II?9s>+es-kBgRTVuWuL_UxT=m2trKJMn#!3YSCyfe>qB<>!jy_b5ertrI z2J?)Xs%kTg9t_Glk?w)*Dm~$k+Zm&EU51lK)l&+A!8+yIjNK{y7;9AeG2&*qHiMQ* z7e?BQE)3(1z|0LW?l^*zPQa}y^c|f3Fy1Zf#joqU`bxq0K%oO=Ad*us$qizkn8TRd zT;fg2FXS&8Ne5WS7bwg!xS(++QVfk81J^Vdn@gvWr)lIHT+qm}XpFbu#U9)(3|i0q z*7Jb(94KVo@kyl{@dH}7DHhGC7JRA&@3r954g92>={OdH=CJ+^cW-6OFbOMHI&^?J|U-+&A}$$hlk5oSsMx0w=~38HO5*R6oC|wFT){*mM$aK0{+i( zW;xJmhXIG>e7M1_$jCQb*&JOXw`=k4=jO<|W^f(~^m!KI=;%vyCi*)N8A2Ho9#Zf=#yUFae@k-!bpl5UoV0Mktn;CP?(Wv@ z9h*vV5B!InmXuem+u@2o<-}O6s}++X(mzV*B%FeUxzhuVlY2DY)9E#5qL;kOu_>;h z*_>TNbeY})bvfRM6$1cM=|0fN$Y^;IH z`3@Q<7+ftwj+Ws>1J^V-73KdnjTL+cjgDb3+b{f&zVjnSX_j z2#_iV z@09}V0Z=8J1k~>PIM&Oy=eWAJnF4se8at~QzXcyZWa6uOJkpxrwDh&rY?6t=KtlC! zd%&~MpYbGQ?1s`ng$V2wd5{tR;4PwuKk~6({nDUj;t3yCI*~7STW{W+!0b}XsXP}k zfi3-8ZCEaK?T2K*qh(Qkfqj+?SPQponZdH!Tgj7i$@CUvKVbCMj~N*?{&{$3Y4d;E zyFV`Y%7f`yewyoiQr^|vfoZ9E1J0+JuIZa}%H-3?axUTf3^&O632`pM|D=;Dcee9c z;w2w;l~3bp)No@{B%X5XJuF7Q4(PP%#whM~u3b+{5}u{uO_9o$#%S~UcuQlgNz2x0 zjj>pBRjjh5E>hoY(sFcKIy_gy!}XOlu|`LDzA{!7iAS5_E%mr~JB(XdB^~1} zk-I8l(sinqahy)aotZVLim^HoQprDFr$KC$L?qNd>QY}K;n$`pjYl<}D%6r9s zqJdS`MC!r{Hp#%E&0gNg8depn3rFh}UZIB7#wykIx|+`vli%1?XQEs|oo3r$s)l)% z0iA-ydDAgVllJCPlyn?pWU&;d7O{FZI;jv;wu0pEvP=tC9SJwLG)CgFijyLhxScj! zSre^aWh{ZQi%#Ew_74}4N7NL?qzAlo+E3j`%IwN(OkPQAs*hGzo3v~%A8ygEimi>~ z_TuKosEFL8OD4z1iB!ZYaU*s^OG90_KD;U-PDUQN9!^E1CcGvZYittUc^spt&LEQTHKo~I1@dba8(sX=9Vc$ zo=IN1Q8ZPT$zFO*GbWF`X1yLg7H*ksYFZm>tcq(>nX)bP@SDQbk$43PsyU|IMC6&` zrMJ{q#+$-xB2|>-FO8LZ$A$YZsRpH9@ydAp%W^ZD3(KYiR z4;Oc0S4QHncw-zT&#u0?MbVq-;jF8xrAf7n2YYZMPjjTU9_pK7(Ri~wyy{3q%Xo+f ztDqm^O5}zX$ynFWZ0g0K9uAt?MvC8pCKoM1Mc(wobW89B-4e+4(crCXVr{gkS+@uo zQdG-;(F8rxaVjh0)wr*l7uaiwG2^L>SE2>3RW%^M_qwJ^co48Gmh4oNVT6 zYQ}ZoAgwK)Bm5dXj;eMOZ#{{7czMFJVXYFw)MWB#SZm8MPVmC(NS|Y}0&SVg*-N%= zAxR8I*1#Ipn^<7E?kQn`Xag(7>Uebv1fWE)0AS(DO1MkBDpDVfsJaPD0A3&AP3Pz` z=t^<415GG2she4n9;>YyCLI=GepW|FRb7jgQ24$%bHL_cFm;uO*+rbCXXIJ76YI8 zQt`8#FKhg-7<@!c{5Y^%=*50B#~-aL$ki?N^=JYxUGZ-w_rTh|n7Mo%ykzE5f%4KZ z!>=0PR~&%- zhtaDRbxmEZ?kPaMGJt)(z75`@SK-+8`pz(V-Dc}mcmR5>$vms10#%VU(faDxaQY3C zto00LP5++OGds!H%-D7Pe!8y9)qL%COV{jVA$S~szQdGbOH)NAJu`s)a{PhT4`JIe z`{xhSb<_U&BTKi!nPb-rg_KFJ3}9cc9~-?Uja{#w45QbbwqBFQu2*bLZ6>`kfPH_w zOX~%HOrn_^bD7j7J@83#~q$s;lHV-LgL*l}t)T6-J% zdfGb@>}3o*U*J`{uprghuHn~<1X#P#QL!8GUWEOr+%X*OiR|R)g86R&e1TJ07hl!U zAFt}z(b?V+M<`d)Zbe#|No#2B<02XJd<*b$r>3WWwZi)@-fJpq6Xtyo@9P@z9_`-T zqjBy4EIYZi5nlo)+BEE^0^50pi=K6dhW$)n`*-5wl^tCg_H%(<_U}BxxQ$xFeFv=B?0Tv~&>i%4iAChnr`dF7M4~(5^I(XIu3W z_fz^CE&@YwNWe!p2ONQgn-MOmXz}B2Sqd&w14@{!-YXGr31c#(f?<%7X*ntlvnK{K z8za?`M#Lc^+Tx0*qU>$pDVT8xp^peV^)#?} z^Lj)$wOj>hX;@KMWyez|sPy_6f)ET=(Bc!d#s8!%j_^u7=32hNEdcC|Qc4E%Rk^wj zLpmy;fsjmn6%<1lB-Vm}hmj~?<6!1hPeXd~Ju81>q$=8|6SX$kcHRoiL>cIla2Cr% zm2i%YW0Ju@Ff^T98wYV|gJ$F8**Gb@7~GMGa+A?1-^SIUIb-AyBvmHJ!0b?S&I<9EMcs zIzE!fGRejfF&JxOYvm)d228f`#9mG75sAZ0UU?RA3T+&SoQk1rG{wddIxP(hSlVS1 zv~g6jDPfU$s+|r#76nP4W~ZANnzoTC)9E&j#1z3o+YMh!`F^f~D3PjR?01ljt9USE zP+RMT?v>s%Z9G|$@cA8Vr_mTlB0IFXRki4FXxmvfjzl!-n-OVhh&4r7v(dW2g|z&K z*tjT8#B&-W4T#kk9W>sdHeO{dJP2z%D&o-`MX=e}>M$EG+ETx|9@Wx!53%{-Hjb*< zG@{5p+fHi?ul2;x^|i=OM|rJVUxn_}Z#U-H=?tYcG&izeHvMU_on9G>t&TF9<*zEu zO---E+9*P#F~rQ+mRCli2t*rQ=cVE*S}hF{?gf_UIzJN*T3AHqm2I?rONPZ$N*JC; z42#zo;Tns*?8J!HRu2hucK4a zmo&s{BFL(Iw$x5*Qt@&`WSNL^JEc&8UFlA4_b!hL#Eh(QD97 zdaW~cIM&8tMXn96Pi=KoyK$V2CrcPy3zAsBH>O*ff+I_i2$iNc_ln-}DY#r=Lu7WC z{-fN+U3zRqR2CN4 zHsgCW($BZj!M~yBtd72hp03XJT}p>>Ryz0(Ngr>eBR^Pd?%Xoar@koDIu=+sppg-0 zf`!xAf$bA&z9}+Jw9;5Eo&4NV+jx?d)&v{3r`d0^l}`I55#{xA zN?Y64+23LDon@s-nObRwSZU$5o<8BK|Y_;+oW~JfF1y3B7)#0gWzBpRe z*;cx5Px+umeLti57p3CGc69W0wf6RQY=RPq@rzH+NyS0nrMIK6f0v{cTWQ{EC)V^3 zahH{*zoO-dd)1z6OWuo`^I%r%tqkFLiD{|ue6V?5I84;8;-q**xQSbjt!?yJQ%Y_<7IMW&ubTDeXO_w}{zLdh}uMEFYV zLOye#v#(;fHzqCuV29XI!2-Nx8VhdjpFEmz>9#Jf2X7DJdM;K zIc4ExxHKt+#bz$s(A0v}jp}eqty!zYZYIFYz75%Y5Ua-M-(YN9UC=b-f~hk=DpTh`bfCq_lP=;go6zU z&<3mi+?z>%c^TRu+Ow)QRuQg^H8jT~HF1QKFw0b3c!mV%N1w~=%QX-kdx^qzO=e+F zy@}=Fb6m|6pVKRO=^png(#xENfi`r1?BnTCuMw8t+t;x}c@p2t^Z5-KBfx5(>Fa=* ze=GAdE-4y;()10j1Ls>4_hRyCG`5*udpeACbxVWlZt+nkb@ z0+L=j+|c}wp@}%^(3NhLw;|eKi>6Uwry3_~BvfxPco^0I|tS)@6ODWWv6 zwl7wIGL?(HimJRO6=KTQ#Wq{6aq8?m#K&&6@4$xzbS`p3Sc3u5% zCG@blr3p@bMo89rWv=Tn1V(DZ4Goxuw8Z@vod@-aD^Q{jp1r>845eF+$mnGj>X^pG8uRSn<)m%y-w?`7i-_ zx%0uBa%jAXfEUVlwyMqK`%Fi*p{$?u_ep@6e?{8gM{7U4-7YB8(foA^=$AR|YRIhH z5yHxytr)?o^1-Mk5VYhl{+d=0#!u70x_pLd4=u+w`SorEX7^g!HQx4p< zV4giaH!I(rCi15CQ8NHrFdl6b2RwS@!uoj-;AMof&RX!9fR~R~eHiihzH+=SAG9MZ zpMwE2|7ymkR@7nJ5wrmr+8}x$!XDMpRV{jF*ANFCF4@>BPbK`1UEcMYY>9bai~5Hz98v#rj{qz`t$)t^h2vj_nJ2IpGV=u0Pit4#t&!@bRBP>x zEv(wW{b?(858u%0f1`0IB&%^$u)=ENWK?)K(i)t!j$f~)7a?t(Q-yCtJNoE0v`jHz zr*mF`Pd?hWsaA0TU|Z2!;J^kM0dXWS4mB?XxcS$MmNCOd8ROWQTclxThTPb|%~Z^6 zo=r&}1)fs7a7CUs-y@Pg)q^!Tr^rsSZ5IMMjYDn(>}%ueurBGXT4ezbw@-UCuzfpj zHgqaF@4bh(nwPHAu=Tb{c4Ko7teGd2LOLZgS;~~sr8G!G5S#sQknC(Pm&ENPq_Ee~&!(bEgWhM$}vjW+@myFi1(G&9KQ_jHF9J`WrZ2p&~gn<11cgSdeNAaJYmgFxS`U-OT{QE z3PC=_FvmKlxpR9*&p^N0JcEg+YWXPB>6jsGXM75gRN`|cu+>@H+S#x3Xxzn+r`KuT z+Q)H;ZnKsGmUR61MLFKDb=Dzh8}0AduD%r~y<2>k_iY^85$<$ZhCJrqH+B689PyCA=WH4N0GB)NA=mE>o1OMZe#ICLETA;9tdRLVS@zFq{2V6^R7 zlcmh57Oi_C(pO@y53IOd*G>Re9@@SS3i!i?Ze3in!t+(H}(GQ*opzM=i##4;Wh_J{7R8 z8cTXANOPW&5k@FTZq~JZrIbfy&-U#&&OnzPJ%56$dRVg`EeyOuSM~p1FE3vns~Rck z0iCY*un8;+D>sRRVA78SmR+}bi>{sWo}=<{6kuc!cy3cip9BUh9(hf>wzqKs#rIXg z%~v$+5eD@r99N5BK^acjLexXKv*)+d#$oi)jU^2<#gwfQI?f!|w5z+_KQV$d4jor9 zkkAoq)6x`;Q~bi4HuZ5wpwVsKILM3z6pb$Z7b<3;O6;useqQQ$pREK7D0Ti)Z^jAu zN{S!b;oA)_powx~ACLWfep=1y+B(>j@IWfOvITJV_v}ZhPc>v={8N*qhxl*w4)hCm znbt)2+chG;-!D^N&eQX)c_`lt%{&zGaPo^vKBf0e_$DXfYJQ`h!0wfTZlh~8KOMtC z6V2EssMcuk#UWu0_$Dz0jxP-f$7k3EtaQ&(aBgFYR%(0T>q6pk9affcX$#K5Xp7a5 z4>3|Aa3i1!jG8y8DWCDaja-8WDi-3`8_Doq&o6Veg0eVzxl?@CY20K7sFR!i~|e zzgJ=+VP+eH_M%CIVb4mm&fkMrNLX}{$Tmgt;6>vH)%#-eK2^ORYu=|xUZvx7l~!)j zW=NVZ&p|3(zE`8?&gA==7#ba=!@+#VhJ+@D@iqThgkg_}c|U~j{AelM*cjGjb0}ez z3P8Gt@tt2dVo4xc@3*^$6JFauLrcw>t=`uXzb+S!NgmCY^m)KG5CIp=uk~K z`J~~mBD}I%c-6==_XH`uqkP9aoFA%zoR&)I^4?_914s!kJe)$ouVe^}c5;gFZrR^i z$vo@1lSH*hNhb*i3X=O5^fz+J_ud06TFcKab!``38p7_)^q&If{x;L+73WPqR@dM< z)L^)Iq`svNwO2psR%{N^WK6U;*NU82(RA4};xwm2q*cNwp#k~lvhm_50j;7(56_&x z3hh~L5Uq*Ri1*XcYI1DK|C{j6eG&YI%E3N^X1*g|i^+#);t37?Jr`*Z#+GSqO8#tT zozB1Bezx2PuqVDx@uYkX z$M{?rsBCTDiij*_Iazr5K*BZ>=2o_`zVe-`5Hnp*78!&SUIdCoK0IZ-&DQ!(Po#) zfbLafjSx-ms)!6Yn@}HQRg$$z*8A+VC5y33hx?Dt2H;|nlQ`?HhaHHy3 z@a1M|Ix2FkewA!kkFH`bH90%U%8-VO4SV=VK2p)5 zHtHJL{cm6E!Y9S>wph0Y$e)&`T9H(Ev|hI^)S(ew6u045sjp(OiFK8CW`jy!gHOcS zl<4nfH3nsI9jy#o5JW)M#nsG|Y3~W`Xf5_r)x^;9anOz3UbVG?$9=0!(G3wLH)8W* zXi8HTt%<8VjcdZ%hB&P$B|TE(r(xYKB@KHBqLs4I%g`2^hz@Zn=M-Bhxa`tWaF#o4 zsNm{+i+XhefNEWBo9Oc|Ogft3X6$N1%(X!uFrj-C`hZ81ft`3=Ova^*(Q1Dyvh=`F z5GTc(YcQUOi;-wgCtK{xEz43;rk7T5o?Am#rTd{ptH_i=JD)rcf3{`=y4!_z*v$ z#|0=>@0))=UCx8xN9*|fMD3gOM&29@V7Dqx=288eM^nDh_G(v_2bUJh!_W5M_-3D9 zbt4C5ekLoEZ0dUsra$YYb5J8v3;)6+Og;ri4jK8IZ?HGR${6ixBsJL8FUo>5RQq0x zwit5+{W%USi`hGOp=`C|KMNsn@8JQuK7(NmE;^k1OGzK8GG@W0KPb^x?{-!JWC z(0CkX>QQfbSsI<1So3NrSw<1k(zwtdX^bEYO;f8bt05Un9(x|saWHpO`59$M%a1gM zLsUBUI;N*%5~k9y&oM(9zd=;#*yos@j?PY{F?x~4S8dBeyHc<;PonM|G4#QrnChmY z!U>1K;4bF0BYH>z`S|s@z00&8FnY=We#KMtXh@AraIkf!n$zzdj}_Ied%(cW=3&pH zEPQF0m8WGJd~82og^2>a52IK`TQ}r_uIcBRG&N0;Ib1i@A*z$ z)XW;f;5`BHXq*{>&uHOXENNJt_2#3NToW)e(806=j|V5O&@H#?;2SKQp%Yox5H)M* zjLOjW13HaU`gp85jv-D;d=|4G$tz)bgb2LPj&%LVPD^LMVCrU$PQ!#5b7b`mN3I9M zXuEeuN7e!9vR=kQnU4WeBp*gVyIT6(I9em>cBY2=?|!4b6)+fKG=)ZpWgSmXL?IUWb~ z7xC@MC}n!cg(zw6&lF2zMRU5;MnVPXUiU(g#N?I+J1X>uvQKehd1_?a&j70odGycRPh#m{`DC}}ZuGL`uv(UTz#`4Dqs>6tGP zB~9yXJlE)MzD5)re3J&Zm(P5R*O@O7{dCTo#C*cTe1)j^`)383uMPzsRdt#&nJ*0m zF00_QMI2`mrAENa*M^EO15`vaOJ&L)=4(U2S%*`*VvSLJdMdkq5t$LMx(Hqc7xE3R zdME!~dlc8r>}U;FLO;R0@J#;ik596lPXbOa{L~0}xISm+xmf49#N_e5s`2T4)}-mv zd~6wfT3ODen%3tHzDLVXyUe7aO{U!u4QBuY%}oQR+6>nr?#eC0e%a_f1?f26%&OqS z{%-0kKwrf~($Hnhmw^@StRrEzUj2HOa3$!mm-r%nY1^xe{OIwEkis4x19`0HnV$61 zl0)6B!9M*nc*lta18v*Y*GGhX4ls_)w)b{*U{iwhnqL5HCeIJ;ZKWfM1Y8c^peCa0_HetHJ9Ex0i$AkQ|0NxIS}mNeFS4Zm0>T- z_}iB(nHlTKwDXHgS()G{*jEY~jh7)t%R|D{x2X8IT-8*Z7Y(>xxY2!PKwzlR`nzaE zJAvaZ zpXEb*l_$%w)6A#*rf*0|Yp&AT=A`7oHYTlcZVEisj86;YyMB5NwY*trNuoHBLLC<% zCn?wv)+3zrtm-rl%;S`N(NbxPap$jk$4O;O56C-W8(J=$?yb_7;+$t|kIu$T;s8Xn{>d2857G|VmzXID)Qbx(CK5p-x{VH;2 z+C9r1?KpuI<9dJpM-gOJyWIU5+Sic3$Xeax`vSANi8{d&`8r_cA7^YF5~uI*XPw9d zhn}M4T+lFDdZ$n0zGYK>G@6`IB1cZM%y4FlfpMjhFS;x}I2>QVI%eR(>G5og1s~^q z8#+-m`O(T~Glq5OV?7`B(s`DM)Hcoo=!f5i)TnI+LG_sC4XUx#$lwoYJ3PI;8Z?l< z6;!~!AF!n}7Mf18{2X?k~$ln1idd48tz+-vd_yFqxO^aiBQ z|L5=*`M9@kASHjEbHC32bCW;wJ~AD{!_hXl7lo63IeR<_fGi!^d~P(o#;*3=%+T%$2Fb5c({g+?`Kb%v^2j=rIqFUP1E|j!MAix z#SJ)5Y22p`ZW?X2n!cQfG;93l48G^{*^aUC3q#U;o4%AG&Dik&Oj_n|F0{8v%!fhD zMtp?N37;2XPERo{>MMq>D8eFSP$(Q)4?R2&?S?A%> zyXcEJt)AbopFunmqfeal#0^*Y*pG2i^WmoSmzd+E;CbH|TPIotL0j({(Bx!NW9NfA zVjN@1I~92-Z+crbP0Kso$ZO4Ko|XB`O;|1FIQ}+h%rU>&dpn4Ce$j{7jLbQHgm>&Z z<{1j|{u8|O#-Wt66ZHJ#r%1ysL+R%xNWOcJwgCHUQ_n+CbBp_sR>u7X_6LK|l=A%o zY2{4wd&j`>p0I}kY@L)z*7 zo(OYZf~5T!Xy<$s!{(+X^uYm6apVYGtRGxnzEh)ChaPEQ5{|s>U zqYQZF0d4d=-Y@13@JweN=sYh1=Q4$(w^X9Y%{d1e=bym2R`mC#Y^i4)XuOw!cZ=9! zWW0X?@0*Gz2gf4ozX7{l%EpAjcM1G$!0(iDNrk@)`2Dc0KEpuljjIcs2Oa;g0NNk` z*dwY8JYLy=J?VtKvkHip3)r*RTW-!MAZ#39FY}HOkBuse0>J-GxX()XPXgR=xj#nf zZ=Xj%dQ*^|&vbvIv_6MG(Vc6Dgr+xl)^xF= zBk;$mSW7*-U?o$&hH-Mhxgx)=VOu;4+GB3Oxd!Q|xq*3u zs(wG=k4L<@Uh<8U`Q7_o1@QtRW(O|IxCl~V6=cXUASNx_X#=`hKvBDSnI}iDg7C~4 z*~hHgIi{Hv5~d-dq>^==V|t#I7p~La)85m?nXTcO?{s>y%8VB?Xj<@a%Xh}9RTi%> z(PgE5dYUN-CI%nd$}-|QP4yuho#Pw`*|BfrVW}aiJY*L?;S(J5fkx^bJM6^@Wd##) zG6c>Fux`g#%p6Ppls!=D=vL$s={DJp@a7A%5r*y!ygPD_id)$`_5IQE0oM(a#{N=>V33|BXMbt*Ltw=-a= z6j4(hr^kIaDYD>9L~k_~ciyC=aeFhwkvfdKZ&K1gHCFA_xzsdlXN7vIKE8K;YMP23 z!4sDIr|=(v(n-aV6CqGXGeA@7s-6pY<2XH+#5*I$-tGwI3FSe|}{e5E9y+?$1dm(}VzSWYsr89wT1qRX8tN zT7aFQE-G^w(s?744B&Xq!bm$qu?te^h))aTv>wXG{R9}@=(3QrcD*$8O6^BkRz}vUuqp&e*|Ku*nF?Xq>F?H- zi0Tw)KJ0IYb2G4Rj;??7YG^b~uul_tEjlRQ+vZ z3J@gNk6DptuHaPSf3_TIG@0d`0vQ-V+-NM7hEKn>@lVtEaf5F~(Vomgy-Z%MTbi}N zU|ZkOS92DQhLBc+)ba&ZhtD}%w{&P2GkzV(*c_am^2I(eLbz4+Hu;R;@66_qU^Nj0Y)J7(Ke)c|MYoh4I`Ypc8Kvm zSZluZe2n$%`I{bh`eWsAVc4yW) zbR6BIq1VK$l0&2MN`W3(a1S6xIC55)8Q}4fA@sfr3w7I>1M+dDA-*B>AoC%!vZ()09 z*F1d9&3^&>pXI(Q&-Nd|+0rE-^2~Cl*4pWO7M#v*0izs%bCx{Ye*_2T5%3>+DBzTw zEHBm{!Aa~A2!L*e~$9a77FnGEUn7SMHP#*T&FnGEknA&`y<6NDa zstEbQpr!QA&aRHW27#Y~iA%OUjR1xM*WrXZOaPB-%>*`&xH&CN}o>4RmkY*oFPk ziMDMU6MgL)5pizY7RR53?M~^Yo`h3cy=h1Lva*G}5Vy3tXDlQ;+cx&Jow2#EBYsvl zF8mQe<&Vz{=}zf}E~j+WE~j*@b1eR>!%LG>8ry>Z+ZH>eCr2Bq zr5ldN|D8^0U9&S~U*78-i`~muXBXrD$xd?I&g5^L32o?()=b1_w=dfwSDp0nXgkK}Av^2ps&9%~Gq%j_SdzzW@io@!k3^XS0jj`#&r zKYU4Jb@1}B)9mf*+=2L}$hu+L&&#fPe$la?zQH;5k(amqDEP%uRqgF)Phjgk4zd;s zO`T8Qwqr&7m$MfiykTKy@}l5Xqf%(?iql|{ed)djzcX;<#n(2yGvkq8J@JS6!K+8j z?hD|P$^PMsyZ$!LIrpC1j~&0`_%k04UNb70)-DmiS@gHV8s2^S>3OlD` z-M@KZXLlExt>1j}R})%;m;Ce4ueSg8(iw+GgWsPr0s%I9eZB1>_Pm_GK5@j<#d8On zC;nyb`V;blw~v;ST~*Ins+{)x{{C%`-!voGxO4tn`%3>YD>yh>?!=~T@K|`NaL@VX zcN#uZx#*vtzww?2yW5Uf8T`RW`B_vQJKK9zHQ7=4*!h25ckP>}ue^O{^2|T{HTdvo zd13I@KGn`I%o+dO$A5pq!j5F>k}1uA|Fu6>7frp9g<@_mhP$oV&j(EBfH%;GEGYjM^#` zk4B-b6&n*0n?!?Uul?-lFWo=)gn=Iwl)ZGqdEX9pPa8#pEd!mKjP0C1-}mNs9_T#s zoL#@W|K=CJJtMea<|w&)6I*+6UgELBeAXZ93yz%k@Vm2O_dV6W;;{>Zkx{c_Ydo?` z?%%$A-pB9QeB?0?-#U2MvK!Vs7u*WLTX+W%~84LlzTo>+8X z*~=ySuIPd*K6&k;b3VKJBfSfLc*{WWw{u6yzO8>d9YrXAjgh=gyKJ|rX!CY`_myL2-&H+x^V!e-t#Rx&=EOZ6K{C?tzQJ64Udvr7x^N| zzP>Wqxa@Onvo3tA;F3$fz3;=p?~j%pvTxbcDVg6syYS?1b)MXLWl7s-qo=?2RPd;d zQF!<7z{!4+_uHM_Zu#;vZ!Nxe@}ni|wpIpjZ5kyn7!M$TBe~E0V)%sb_Fk3u{jV)~ zw)XGO{ww&*meF%}cd4>I?Wm{nfBp0?fAZjIUw-IAZ`^Q7@Rc)0&)nYAEu3pNpZD3z z&%0;JO+egoAn)B^D#s?m`=(bBrv;Oj<;Ob`|3U-Z_89DnfI}z5q z4(>hq>j$0o<;kDjxAW>h9?=vm>K>hSUx#YYU-;VmpM84Mg{Pi)?bmL9>URaV1_Nh~ zk{RdzCA8A#PrPh-^edmceEr`ie*T^*Kff~=87(sk3p1XxRLk(zEwBBxqvX7B_;1%8 z+I|0wV}sSBX7BD+I-ihxR&&uu-Dk%=Ij8B|nJ3;8e7-Y zWJAcfF$3H&gb0y9FaZST1#FDly6fIrcU!Bbt$Wt$Pg|{Z)T*`CRqNjC_x(QSoOj%N z!-)SDKDqCCpYyEqoIT#>EP3|Ax(Q?U${ujZ{)az)VD?dKHbcC;Wv%4YqUKwl81lxQ zk>;;EAK&=jE6&cocyp9(%a;q~=fVfRWDP7TuWKe!#hxz4^m2-<95W-n$3Bcjm6y zmmIel>6%#2REE8Ja@*z0-#J~~mG#cQk6N%O`{WZgPraf`wL${d4L3bJk=Z zyhZd~W}5Zm^N}S--FDb-2E070XV)vAdMi7&MdT|M>*SBv=j|Wc554%H${#x(yzZpk zV%ZaWHmm*7UjLVW_Te{$eqC3%^TJsf9}Ua7A^YJ|HcO5blodzodUntJQD2>!*>LLL z{<`|4yibc?$$n(>4tJMQk8&9@$%dsFsDTR^<%$hO6Le)`7o zCp|T4(1Oq3y?5A%o6f2`CHwI$AaAzRBR;zDk+*;R>eq)}_|2*{10Nio{pc1@!?(oh zReD;p{T(O%?7sU;s;f&6_|M`q?mjTP^PbHb4k@?dYu+CFvuh*EDvEb_y78J*cAuGj z(?gpjZ{d(nEcc&f4<2?%^WCi||D+{Sl+dExz4xu zue|M>2XDEfe#gr`8uEv64{e`4ar4xxJKN#4RD@rb``TkK-+Rls$6qwy&!;?e-euW) zf3R8Yq4`Q{`QrbZTvng`*!5>k|NFOR_4bx!KlR~e>CqUqb+oL~`j?NmZooEqkG}8B zxpw6_Z@xV-d+O(#WFS)&EC4Lh9rE{OqxW6;s}t5f`QrAMo_oTj>$9sh`BpE3VUbZU zCvtfM4lcwx)z1t${IXvb?EZAY-{60K=<4kF)^kTQ+rAq8iecX+JGa99R~I|A%m4Mr z>rd}~tw1J!nV+b-s;Z`_wydHMtqQgy zx>of;)b1y$DxM!NuPH7rY&l}d@+H_4=!0mvk7!z1S@ry)a%SaTKJ+jY+tVnv(uY2M ze$~8^vg*=`!o6nt&?7+K%b*|SLobOJR+P>wEy8i~!lL%}$~k*>;=mU#i<`42CQYkw zcO}k1&e?N$>++7yb#wMKX4xI=_BQM~ee7n=E14UwtejU))vR(6@_#5#D5gm)%pRc`k++ToEbLA!&xp;tx;wsc+WPxSNV9)oL^H?950(+ zSyAbmx*ctDOV6C5^wsvmi{OYQr!uT5GkXJbU64v<$W))Wy*OZo2m6M>hqa#4% zPscGnqM5bDRmEjx6}5%+tCsgAeZxlGir#&QKre zP>>cH()B*ll9Iwo=v+O&e12i+x)sehWYyf>j$)194jg)Bsc%NPThZFO7~vVFfaQW6 z&n>VK*yv+dTw7QbFRQI6tDaXlXK(Aqh^O&bMoVkllDcRe{5Z|ovlWh41C@9J7}EuO zNDZBYu0d5{1M_I@{h~WGAey5R>(M4A=FGs)m)N16@Wj+mXw0smp}P{hx^;QeL9I9? z))N_!3EWI@N(`TgpWU*s5B7OB^JgS~#_(q!{uJ`3j6VnRXEA?{;?D{E*~p(B{+z*|i}`Z{e{SK=Z}~HHT^i-Z zO?^Q7In_}7P-H?WbdNAY!%TH(BSS;4f}*&uVNoSZJiafn#9mv{qZ}z{>UHZR%qzOF7J|#mFx6H0K964*$jqr$@-@K@pCP9*pGsC z(J{M*$t1iFI@?eQe}WM@$LCWK?iMwzFC9xm8iFVE#j&i!e6%J$^=Ul}LC3`{xh(DkBXB~;3 zf!ixJ8*;-UkNiVJPjM;rr-edk5?)Elr5G}zXUP)v)RFlKZ z<@otN4Ts}h4$yjm@i4a`gJ)e5aZ+A_12TzIc2KHd>2O_hf9WSFZ9SqH7w9IXcYjho z(7_*2E&-+1ni-Zk^m>;8(woGl3V6-*}OQF3RH6r7>AxqOUxeZ{w7 z(MT3WYw$B{NBrE&>NufkN~GEebvmK7yPy>czq@N_*|hK((?SXvKZM$C|4S6dC<>`%k&Bg5?X!tBe!?3=>uZ^G<6!t4RU zY|F!Jfx|=ZNKs$DqBX`}K=p^6h@Wq${spjr8dx_ae5mLS#i{L3Y8#2J-9^kNMKHI~0wooWw#PWT}HOd+O`cca=C;aCV0{&po6{ z@Wfq|&6#G6ob;cNMd1_vhY*VmsmAK#6I6rDh9^sH^L9vIh+9-wUuLevRf#5vd&9)Z zQCT>fg9rWwT+>hm_iadRv)~k76XK_UbS8|$&kF!=p%QFIeM+Q$<7$*xEKHVsX}-v2 zOXq!XsuHad{n-e5-^ZubnQAyx!bwTog@sS18eC62qHs5gQaGxjY(7(Z4sV37jivjg zOf}kN2ybuNk1|dJ&eJ9kj)P&Pxo^Ts@OM^P)l^Y}#aD4t*xueWb?VeKB~VQPpnoR1;-H;pDYZh<-+iY6u|=*LGzf0n6^Zs}@Sxvr_p=3E0Jvec8v=34J_E}ZOE ziC;+4dneU4)WTzGSy2s~o6N0?H`XHVa*6wkjx(;f;KLEOi{N`#mAFC-@-JU1=|)w% z4S+jAU&_J|zG{?Qc%u?sqRU}OsQom`|2YcyUL|}#@$uzV7UIdSA#U8=NnH}F4F~V_ zHs`$WoK@m#u!(X^qH7g9y*|G7HZ|)SN$!2Aroe}9I5J*^hq>4dy}aNaagi*M-_^N%ZFh)~kFvAg zUkvyd(wy=YwMy_Rfh@J3HHb85scnf$uo=lzpZSbDw+!dsQKR7iUHm_=QnP5+l*D;y zlV|a45Pt6?6qoHdSzp_TOF-)2NvXkKs>ec|v#mPbXX`4V4e{e;V#4~Rt5@Mr$O`#5 z3L_~o!??#K4hq$v1u;?DhgICv@x~e{8}NfzR2;AK*Yga{CD^W&azU!9bxmu#>PEMQ zih_I8qGwEFgIC?Lcy)WLo&y)bzJqDsT}1fzuZ!?vabt;AoWnBuwu%<+q1v&B)`GK_ z3sJwMAKM33&s4u=x#H&K~Y5& z+YBvM$VS7KzoZa;j*-+t+|CM>EFC&iW|o?R#iCOt7=Ocz77F>AcyF3 z39~K<7>BepnVAzt2`bSejK1-u8Ls8#H8j-vYQ-28CX``F-?)K|hr0QnJOI;dxze$IKB86+l@fGA zld1mcOT6xD&^+^&1Al);PA7)Cuu=wR*=naOb(+mEuesL^9KIq&AEB?T69*FL>*($l zEhIY%qi&`;JO#^+)U<;q4;%NPa(1CgmbSJm!_-ea-ALb}5*wxQe;Reo)U=6`rs2Wd zhlA?0c|Q`#ALo`LaZp@Amq77qT#ex?P%I;NrEBWoIbVCn_Zqr^uvG6z+}|=6&J)$h zOf?~>i}sp}J4P^CmF86}k_)OQ*kUD>3VJ)konEK_wQLpAdD>P9I?suI(O)aBF}|^q9feKq7z@B+g`Os>iEyW+pSwoGT)KEQUF!H^pa@%B1t1#y)5;Y zk+rtD<@cx2A2l{d62UY_xs+qo#5p@XSkMN`NxUFBjSXg6Del@SX<*Oj%d_z+%JnJD zDcLoUN%!9*-H)T})JjifuGd1^>5U^(?HH6(SG3UfhCV?PfH)(FC|79l&JSEagD?Nn zb)9>mn-e?axy*>9T2x%Q&cm;=Ca^e0Wp}y;9j2QCyC%JQugO z+A)qE-bjf87cREBB`Vz%^(8UQ?SX>n4QBm?&nv04(d7Y(K2L1%<$Rc$wGJ@76D^UH1zaOV7m(d_`68QQuTHk1n(u(G98u-63MJlrFWZ z@GYobo8ORuwRkM`N?W$wsK8h^%2nDVc})v3UbC${*UvHGw0*MM`sz7hruwZdCuS_n zHUmvDu66M`t^r8%c{aB>&}vFvLGo%4$1o>bT$EICr3dXl5j|cXVMZLenQCgV-KuRY z#?lb{8K-NpWsC@}Igc(FiFQsda#SO;)JI|_x$SBJcU-&~$A=@o07`OAoARGFz&8 zPZaf>F8Q+5CyZtuc_jc#j3t#opcl(bl@T;SV?A0~eSJtty!Jq!y#@n0Cx}c3)#w&5 z%Z5+t1F@=EQYIJBd1L0CKyDWaphy_#Q!i`XR7afi7m&9yMOJEt;s7R8tdnAX--YdQb*Yen_3Td6bpRE zO60H6V%A)VJ5Guzu1XUx9n$XLDlhg_`;jdNNU3b^6D2?NDTy@?tiGpRsTu-(U$B+I zyDnZO=x!iW{l~`zF70r+4QeC@YYWN_Fdd&Siz*=%dnXetma&iK{4b& zOjBUa=k}o6gW(mEP}kf(4sq0r&6S%Hek%Ycf-BD;>oGSXogY z_btWD5=E~L6retqmAwMQHR4E6HO$tzfRtv@i6ie!Sju-vdPVJO;ApoTaYQ4{oM<)0Z&^fgj?^7MLNc+lX=)T#XSjW=-~bdYGb27z{}% ze5}tLnj0=|s~Q+q%&XSyywe3xhd9M6q{}p znftNZ*k)23pxTR~Rf7Juuzr|EYovQ9>&KS|VIj1+vk?~%buP3kFw>;e?;bRF>NwR7 zKYdN?G>BU}aZ|VILNI-3;VhRe5J?q9Ngc^jRZ^_ekJ;&QD^q>zvy$B(ZYaY+S=mOD zWp`imvpp!rKW@5yd$*L==~Jag&@7-Xn1%tG){C56$ib=tc0S6BaCwzVylvYl9ClHQ zg6oZjGjI6wRvS4P-ag5kyj>IfqIw^_p+X4UI<+ITiLgaazp(Qv6u=#N)`HTT$V5cR zMhUj^gTiFL!ZyiCI~Gys_6xU4aH5WJufOH;Dj^45*93R7?J)ott3izQwJ%d}zXE*W zW4ut;gwdOEpX;E12w7SaYt_ccjHdCbmhw!BjyrmfaTL2e8k-GUmzjS39Fa+oRp zRRbQA$y8sVtSnD zAaft9O3*`Clt=gcn}emT={5&jg4Iax_>^M{w+xx)ZuM}abGt3}-u%qJh^rFZJjhhP zNz>{zq0{!a)x4{)PUooYKIyzNOZ`TgXzX9{T6dhN5n#28nK~NfEI3nL5U>*T^G$_4 zOAQ2OiRmHgOVaMX<=QkRFFUJ*-UIlfm6S5M&={HO3tvU7udix6z*q4`VgKGO`(9?6 z0(XPhZx~xWIrn6zU~)U9ckYRUv^%UCcEX%;?#D}Z4(u9&3De$Uixmm6@q;$uY=rDU zLM1qcKrQnn$u{^^Wpj%#q35uPUb1C#)E(fA22nIvaRN=DJJ`bD(`{|oMSm~(pE8g7 zK`e7kAkpZ)`Z^cmrJY-Y`9Vcw<$|4R9oD)%=~IC@>2cFdp?YHn(YKbxqBAbY2g?cv z99W9G6_Z;{+WRY{!@a!Lw+887KIaNgrkd{#SyBolM;J9ovnVW!{i}oql(6w${Ng_(k+yY1A23?@xe`|80I2Z+;)eZLD}dnQ#LEnh#u-FHp-@7khR!FGD^EFP#AsZ0KLLD1X7mjUa%Os z;p+o45%XoR>v9JBsJ;MT;#^#V3MV7 z2;sXyv)3QxNnCxVXaT-)i_0f&n4Lvcp-RjUR+G>T%A{W$h2oGam_)a6H=TXcvxQ=U zvr|mqo25$Ge$yUkTnN?8>_2tZ$y0XE@tlp>{HH(7D9_`26S|Z!0+)27JfE*|yd_~@ zTbiYYy(Rsk9_R4dSeT{-+%wfLkuT={bG!ShyG=1Yk2#g=ido-)(PCh~jk_j4uzqi% zLCsVb2aLnUDzLEUm6E|KTCEEi&V+Wf*zUhgOuRjE*K`J0cdo{X7kA%-rR(}+A--jA zPXb%xoX1VmhDGi=TxZTV^^9om7gEzMd|aCn}-WS+@yl zE5vUT! zN=>=ht10O6=AyBe;ic3QHqU44)T6^Gt3%4XRxYX%tZ8FW2fYf2jR5b?X{n3Ch-*}H zb%iUhEyr!_Np+4BxiMZ{pd_@XZe7?$Mft&wZVSA#w5BbP1GW4jNXPS=2LIJn2J1K} z9o;qqycWgU`#m;M+G5kBy}UI97ZocyI730FxkSn&7A4ZGnd;5IUKtehu^;{(8#I1W zq?N=lEM-V%6yp%>H3 zbQQ&_Sju3Pvy$rqN%mGpywq|t_lMxh1I}!4>j3RXyb;S5zGA`Y`eHfp*m1buKNbDHBnCD(be;UNhlqq_K*L>WWpe3YeFxc^t}E{T5oqy zi8e}aL+Y=Xv($T58Dz6>u}vj-}(~IHXEZAd=TVoqNae` zuUTZ=)ybdJke>ujGrI@2d6+r+El$zn;IjF&LuOP50iLO*1qE~FP*rqbUq^~&Lh`rz zbEBjy(~z6zN=oi#kDdGl54w2&qARhla}6K1<(eD~VorL-Sl-hP^`$2HZL702Mt( ze;+8vz}+J_I5Hwx%$g(nhx)QNeAp|7c^C5Sc^|uUSzXD`y^{B-XrB8gHEnXFi6z3I zfdWOQu53OQ1ASK787yBK(a5g|l*+|&0)y%Um$5{ zF-8h!ee4n6ax|h!l26|&g;{D}x3w}8f{TS!2f(^LwxeuF(bMHIqiS`71juEA{JLvz zujlX|7|T*+U?)vtSzR5*4$@j)F0{9?oO(k~@YE-uSK1M$S$g7CbeK{Bs!w$U=A<}C z4M$JLDHdm6i7N#?!yVYB-Hu&=XuV&b+QMEX3?>K$)e{DiJbjj|aZ_u`XV;rWFW1C9XEnfUG_Qi*#cK0*d!_&C=Y zaVD+^Yj#{_U;=vuXD_jZd^G(V0n}Kj^^L{V6$bZr5_MbJ($#7STs3{=`g69cRKeuT zb;9U73zfT`1pW6C@hyvc-wC>z(d6dVJk}B%EDuLl(?ei;+al$K#J`t{Oq&c}Uip)! z&UAmKA2509biV08@)I|p(QB8A%s6&yNskAue4`o)N23|~%kEGp$~)EIfk8zES$A20 z(Axtb))y8abo~H`b#w&?{XnQlcrb$W2B9Jme07zf=oCUlcIUV9Io9`7PK)b$Do1;s z%8BJnUY#>#a@V4^RSsFujf9E}mj>z6|YVN?nWudIB$gtsR=(XA7ipz$M&Q!zV z;fq2*I5JxeJtX@`zLVzQc=&ij`cyW7zX-*{7vt{|{9TH_%k(o8iH9#2L_$N+c=!tM zEh`?rQomgVYz7neKzCsfN)%!a6c1mm5v~COgU6f55{ZPc(4HbUv|T*>vPPu_435+h zV??)5Mm&7OK&DkRWN>tRLLxdmClSv{{Gd$`9W!-@OrH@B$(}cEK+KwfH2c@r=k1hH zoL=O$PRB5R7z95cgc27@mcQUdGKk2(c@PFi#lwskXQ(a`suwlR7ZCC# z{>U0n3IixKAs)^dDcVd#VPJ5Qj;M);b0uQyN&smRH$X5lV*beT{CV)nz#@>i5wPBQ zBYQUPhJvtLcd;t!E-t7f_Ae0wt0Ua6tQU!QXoZZb1j7zM-We+<&R>XsN3q zwaZH7&9uE;N#%77CBCO6BHVw8A8U!nLgG3r@e@j1mn88xO8ityM7aMFztIxcL*j{6 z;2k7liswJmTqG|CF?!UyL;EvYr zOh`Q4N*qRsrzf=pXHnvC#Gti9xc?HzXo=@R;yG60_LO)|QX0>v#2vImg!?ZsS4+GY z5-+k6ccR3LlG1nyB~H>35$?Z4IPIoYuY|@H#d;csKFqEuco49gnE z!SxC}@(vz7qq`{7yKrPj!sv|{sRQ2rpy$wV}Zmnwwj6YQ6!Zyq6N#?F-*`0;D!Vt z-2Vi93m!<&dL-z?(fP;Q1bqiEB>aF!-bS4@CnjgjkBDSq%1zd61OjvBcqYbRC*=%L zf;qE+2~pchLJ;nMLiPaw;#d17ZBlbwva9j#x=rrJL-4sxo+bgGwy}z1Rp8v(f{LdyDt6v4M^UcJ1m|Img zM4WFYGQ_{q+22fbzMBZsUk#kz&n9*k_kMvN#AOc(bF%m~BdB?Fku~i-tF}SI-9G>;OnZq+o|!XKXHB$CC}Eahf=qkO@QxI|!T9 zh5x*hmtQaL-M_r})oe-cUniC4KR3xFwimG8=O*bS?A*%h9#8=34Ds%$NG;7<{|vlcrDVl%AFDU_L^ zWg1h5QcUe=;e&sQ@M&835D3q*!e>!<7KF3CnyrNlb%lhvhMM4dqFGtJM1p^rEN%1s zbGEXB1VJb<@leU|hvt;$KQM=8?|ooScQKbKk!Us1eUkt{i64K&xk3gMPQYw4qq`UZ zmDq+9Jf6kH&4=fpJUl$dmWMDEOq{%@tM;X$_T5FI_B%!KFoTJ?I85UXR0L8j5HlTH$f^(ce%z#Ju+?Rs$RSM3aXtJzIfyheuWs-!O(F;Q#NDniZ_yv~r zUG)U=7lG{BDtH3qZ2?IjW^kShi9@sS?n8i6cZE|B)+@i2qgCjYOM$ea}t z89oXN=LjYq^VH-DI21Zc5XynTV4k7ANh06tWaQR$Pozn_403c&qq@rTv%5@%eFd=I z>@K~!&JhQO(Hqo+S!23rp1&hD@5_VkMMs{P&K(eqxltzF9DHos1*}(r#nDNZqpAKu zst-DaYHv%WH*5?A*G@5r+kw=tGaPonsb2##N!k10fs{=^%Eoo&kF|;W55T=+QxiA2 zt9M*FD3kmFX!7>j<6hK`#J*HsV@i?@FOz)Kn;a(Kzf3@+U`m%WS&a4}IegM79EvOl zBwwh-43_dEp>(E@3zu1825{`Z8Mq7zGvvbzyLRO})(qbR-0P$!ct%(6uIZpO!w;az zEA*K`V`?*KUY;3tX9Cd5&{8w>%gckk5H#za@H#O5v4sV!rcX-qGL1=MXAb&C|t>2fp`S7h_P z(J7o~scg!GVuVmQb4Z=daM%I7|0y%;ePu{lNmqW6O`I(G6{RMwLK0U>HIKnICMt0y z)hy{cDYx;Y++Iy#5{b%OPBqI!<$}sCM^l%R`bS-vAe7G0^=VF&R3+vqXyfQ^oUjn-Q0JPugz+EhE7Ai6$* zSQd=96pRf9(H4dc1;oW?kS#v^;3FhlVtp>PtUev09+ z15W)<*x$ed3Huomwy`UJy-nMT0Qas>P1|W*y&Ka(>!Hp|pvn7I=lsD`USsN<*St*f z(KUB70WUKFk%BY3oYTZ+uaLu_F0WH32j(xS#SE76??UOENiMH49CpCbm_eV)cotn{ zJbV@~@Q`67hfwkGQENQNKLv8JhIFsRc^d>1vt@uSB>xtKyD`DQ=?$|w$G2EKe9Btk zbIEZ!n1~G~cSa`86RML>5Cnl-AdtBU=t6Y_rVoJ3voLTE>lYmOF^h%zJ#nQdBt%aM zBNHucvT+(I(IQYG{zzt2d*dToAr{!j0yCK^knaV;14%ey_SA<4nUg~O zlDIB|Iv5fIyIEjBqCN(eEu}JuH&$RlJbaXr!f$38yy`S~3)A2ong(x48oZOz;GHTk zCLSevDn40~1o3E;e!)2@Mxta^+ep3-kB4jQdz^tV?Iod5gKI1OzDgpAqu){Wjg9oX zY*$-;$O2<5%|F2bgG*pw>)jlKdgtLoFHu^!nO7VnG;DNq;wFDxHn3U3n#sXz_It}F zgzp3G>kc~gBe!yLN|uQPB%-zFO~&QvAbBdV@^Ue>A1=E-@$MG&iFB@It`J%d`AzWA2YBfnX@A`p}HJv%-RF-Q1f&$!t)F~5tq0X zPmJe?$~``^mZ1yj2+;i4Cvi>cOivOg?7L~6X8|fUI2!?nf*@Z`of(9m6Cv!#TmNmq z-Uc?<6a35bXW%z~8h(ro&PQY~-(ds&NMnQ9h({{eNzn#8&zQyrWNmFA6H(eh^R#wg zmu5h;!(N*2F8~!gT#SH2Vb%@?feUu9gS_?M4qP{a9eDeEdHz25H74M(i(bC>Y@9U* z52Wx)qT+cKo=oWtcoyQ&tHxq#W)*78s}1Hg8dHk+emd$}fEuFUavcH=@g0^Gm$wkh8+T#A)|QQX zJr$V!W^3R+K*enLBj8XTZ1gn6_NyQmGdu)lFvIiUQ=b19{2DVn40zrPc=u`W2w^NV zlB^|67AdsivtL9IDSwm<@qCQPFOh+-)OhIA^-kjB!0IJd&ju{?B@}q_-=tYDlhU*S zf7P7-2waD7(JQaok$LfvRKw*E3gbjJBxa()O>19c%qPK%igB1!=r&$}NE@cv@ocxN za4&7)WznBNFPZTam15Ej0xPr8_i5sU9eMjHS@bOUAd6mykn;S0;5Yy8_%ZqP7ewa$ z6YtO+dxvsp={dsQ48ooV47u`G{rDRmz2t&I{x%-HWZScG_P_CP1fU}gd;%-y8;Apk zmq6+W-n$-QFE!xtsrAUT^&uX%nR@kzS?_6*mqEfJ@d~ACN$Cl=2e8lkn&|I_=vB)5 zP{aO_!hkszP7-VO9_CD#^%2N|0)Zdy10Q`k@uBByM)VtaTHA()Y1{sj>U=`J#zM4n zYRW&|90rvPs+J}dIkU*eW@Ttks8B%J4#80LP1<8qdd&U|h%6bt4Ez^UK)6ks@CCQG zm|RnAEbQNaH4H%H+XxhVPT9st?*PC|eGgCOf=|NxLgWw|2>&7Fe{}c*gq<&R_`e8m zTKO-5n56uNWI%Ybq8}k5IYA!-W+i_@!mqUCPZ8d<EE*t zITgS8J@_$wNIfEv;s*U_#3S$Lh|N12KfVJ*2Oy%Cv>X7fSGtWiN*_C6*105MwD0K9 zK_GD$0rm%L_J`=lq55%{el+2ccP1I+4Z+}|FtMDyI+ZZvBOL7MS)ak03ezSP#TbT9+Hef(XJoM^+Pt|Lx~Rkwi1uL%RrfTr!FH$vy6~c zav7Q0oy}rNizi33sB9vdC1w-RGOp>HIm^!`s9B6Q5zW%HiD;>BX=D%F`J|0gPs&Y6 zaI_CNOWM@#Vi+fnu4h;*m?yeen8MZxQ}@!;QrPmOLAn&L$fzzvp-{-1DHQT`C{{SH z5DYUn(=YxRn}z_7Q@L%oa!rOb(@}_S|AB?*clgb}2S2(H&Fm$hyJ(+#@xWK2=m__6 z9+dFjy+rHTn8*7?cI!C_lPR7kn^kb1M9+2}mS=%Qkk7U}%g=ATTUOOCc~kM(q(85u;HM z*fz#wBQP;WRjM3q+ZsS*RH!AzQEDXAucn0gUx)l(h1n_znf1K{Apif0 zM?BPk{BLw#lJJ6Fq9Oms1gx^K;01|3zqa68nX z9p=0yXiXN4w}yM%4mW7c&KrWZ$fA`6&{_=IV&_dkYqe-}$M11F!k{g2-V(H>7L7Oi zcxY_~?MUZsL0e|gc*DGh)^5<2JMRkG3X4Xc-X2Znc2i$M||8MGukd*=+&BwPx$By{NRQ;e&jmgGv3WN8vEg<2B& z7xs}{?IXE{BttX_7eFn^EkP14iCQVLAUaHwa1j(OsLb4-*I6YWm`4OTk4+ugYa$aX z#xjFIIL16eAQGeH5s1cUPXq?UXe9&&#@Of~kP%}oMj$iBDuckF7%K$=gJUdF2xP@r zP7v58#*&P{kQkd*1hQjn6%iO2W4njIs2E!|1V+c$b|J7`jI9#_V`6N75ZFG(76ySG zVr(1`7#m~tM_|VoD>wqZ%L1SZ62Nd$6Ytb8sWT+cD?jO z4p%i1w*$z|8;k#jsN8IlrPU2UMXII)uZjcmQJUYKWHjp8i1PJ!ZW^1jw^=)DPLF{Tm`gb|%%320M)y)@l%y#d^^btF zBt6Oa-8Ae^2q)!8T50(}PZIMK*$`gfXkPzE!0tNy48jogEZMWDZzeH&q_XFk3WspZ z{y74sYWB~Q?+KgdJ1v#(U&)4W%l8EUP{f#sJX#7xjA7?| z$0Yql>JzMx>CDJ|%9n`RXN5Fb$P>&c#PZhvLd?_0D8v^_A)X1v^QYs-l;77833dL7 zM=#^_$!J@mG4WrE1Blo@GAlCtfO)6QAZ|!pxgFTyA7-2+m>AgSoxLx_)aUJuU%U51 zBUk!&wE-9?TiWsg92L^_O)?G81Qxa zgqwQZMF+V1aJ|d|uX%nOGYb z0?zqG_%Vg!LqtN-M|kAT1sEFGJ)lnjv!z7Zy$ZyqZTA>KLYlJ-VKDp*#17%T6owT7 z{XlU@IukIvN)vnz0=8LSP!r$j2k_P91aV&?E=kT;0Ld=e*9bV|CFc`lUvJO|peJRS zR)g&-ZT>BVm4nD8yPz5`P7T=@uq>QA1osjmWg$0rRvck4kn`zy%7JtpzfY}>;(2o> zh^NS%2Ee3`k=)+~iWzR~$C)R()i*{$X+tsMx+xW;js zO?Yt#35q4yisd1D=WwEIg;;(?78JV(99*$2cyR~`iY3^JjZo}jqHKj&ej^wZdjvSR zVwd2>AtWf4U@JCCu}g`v6=K;&1;ri-4zAc`cyR~`iY3^JrSBN0ohVx&c2>DCD@A1q}a7Y*$T0>DPoTS2UqN|cyR~`iY3^J9YnFm5oIgHva<^osT07#6?-CH z972L(3ASPfQ*44LTOs!F6tNq?!4@POSrmH`QMN+t(iE}X;NXfq87~eY zL9ql|vHXn3=^@Hih+UZ?_Ed0i#h!*2hmfFHf~{D7Dde0^l&uiEHbv~2;NXfq3oi~K zL9ql|vHS$dIh!b3Ay(GXQbeBvF0SZv@!}8?6iu)dJ&dByBg)o@=E_-$=nKHb6@4LI z972Mk3AUp736*mZQMN|(+37@I3@)zdOYq_l5)@6a70qw6oJ)zaHKMslmXhkr!NnDQ z1zsFNf}#nwqWLM9b0tx>M)Z~GL|+XquIOv<;t&!PO|TV>kAjqQEm5{c^o{96Uk@&> z=o|3j5E2wkuoXRuqHiS1)`-3%o#>mu#T9)sUK~P#q6xO5x25P?h_W@Jxh#{C*SCR- zEBbc4ID`a66Kq9~rsz9}vNfU~NGJN&;Npt@4PG2Vf}#nwqPL^yJBhM2qMt}7`Yv#B zMc<7VhmfFXg01K=6nzg-wnp@`=|ukyTwKw=$BRQqP&C0-^!60}2cm3^Xs%SGFAgC=(F9x3J5clkMA;hAucs6J5V*LaAI6JANKiDvR`ghkeuOAnBbu}5lvFvr zM4zh?lMwEE;m|CwOa>ATlySD7SBoDkW|9?o#2R!U6gxl%!m&eiAQIyo8931xXRQbf zh;bf?z`z)1b_is|R_Z`zY?TfSimlaw!Lj3XAS=c(JCL`DaTJZfkQm3c2n>yJq=~?= z*x5QTJa(QAjEG&N1KF`lbzo$SV+J6Pim?YrVA~k`Qv^oG*t;RHUF;4W7!$iw2eyyh zqXRp{{-6V6V{D^`EL>1ufJhU)VY;F*8kRx$Lrt=88WNa}3mAHl zl~vD(jrn-YA&*ZqkHR!O3`voXgnkB`&ooJC8WM<2OdTwBJweZ-Ksd&HKp+yMF%gKyXd(m##F$0|2F9o|0vRzXQstPOr?Y}ymM`te?OzC?2#HgI zup@8%FW3iyHwyL!S;tn1u*&~|qV*=-L5R$Y04N1tmVa}&%1S)Fwn}7kL{0lPI)u8C zgj*jQadv+o!WMugiKpBy;L?9+r=+OiZd3wSHC9fLXr%K{AII(@uJcXpSzpw%z90OB36}yR zZz#26+u@mzc-n+S4w&#rko1zons5Zd7La7ZU{s0;84VLHqndcO`#5V;_EPDd^~P=M za>O%hxaBZJldb?rwgNg3aLBK3Gq2R-vSVS$k0N>4k+=Sv`Dk!~na>t8kA@EUqxh4J zA7kdVz{uO4+6B!_JZ)wo2h4m7NP0@)V&-ws!5Ft2 z@Ls+nA^MSK$0--_dYqQD(X>!D1`8%29zH*a1{0m^v1G+W)yE@ZI`^JHBnJq@F_HMb z-YNrVrjE=ok*5YCw+T|7hDaERiuCW(JRWvToCPj0(l5nGJAs!m(%BTvchlkL>4g5A z=pZ`>PiGemJC~^LM}~!L(Jqn}ZL*F(pSZi~@C5aW)iy(dijY$gr zCB)Cy_?HIpYm0Ta9MI=-;_t5UuL$BFUY7>{D&p^<@vjczpN)!|qR+L&pQ`b%3*uk- zRYofQ4aA?O@ox;`-!VKh75|sOK|j4SDDs#s=%*QGp^7m}5D3L+Zv?_I8WMp>j21#5 z8e`HC7!YHc5EvMvvIu0vs6~}SZph=CA*b(ZdkbPgBb|`R=v%26z91)g|Euk>h-X zkOaH>LNo~!*|XkkSp>_q-4gEABzhZObNM|v&e7pNY#B#e`YqRcQ@P$xuEm<`16#<| z)Dg?|!BnmflWUpg`p6b?H8sg{eKeKpz~NAQgeN33%QzF zX}La~%Jms?tx$dvIKEH)rO%1nP|C-A61%Oc9XM=AZi!rJ@ z!>oHT7GVTJF_t_8!Z8*W1R^o!F9OjRvjl+wFb>cASkW zq!rVrVKl+ZR17Ci_}2gG{u;QTy5A<%eF1poH{i!q_ty~#)!xvLf8xp=(~K}M-T?-C%XjevrB4Ac@r1M0dQYSH z6YxGjGKl&B0f#K}4&=`n(`4MeD-_II1OW9nGr$jlnRgJ8I`wDkQ<(}A`4J*}8L3Bz z6J{+&IPDmRpS4$27PKNBV;rJE!%xVY=JtOQ&!aQ<fNv&2yj+{QQj<`6e#8Cz3Q4po zz(+uSKH>Cy6cUPmU;s6Rh}UuZ(y5}Zq<~(L^!&!S*x+|K^;#3)m!elRJ)fa|J}b$G z*MNI^OKnOM^dF!?H zq-EG4C7LbGB&?3wqO{S6y(6$U(=U$GDE@wN0zeM?CbUF3l*i2XtyNFlJl9-}BBL2I zT-XU9jArDm|D%~aaKUKi4vuEb7-naHO!=IBGPEw})~Y*zI|MkV;wNZ^KE@}f0Wml} zIh~L`#wWW_01*l(z#*~K;|zphyfsW zgkoS&LJ6LEbyH+yRfbBRLSVa=QXmE+eK}i(ND*9tfI|@;D!XD-{8?vf!SjJZ!IgNX z7idGihsx20549n{$BZBtpEK(`ty&{6sM-QN^Ue?O3Jy3H zrm*tKIgr$T*H5|$L~@Xm9HaJzndxaS0KC4l#iJc)X)8xs+Ib_@QV$`^BJA%X)TBpP=pr-_p_>{< zRVcBI<#4EraF8H`48jnL(BdK-K2ohrqeGjEa72294i}+4J;E9np({PYaW2BT^avYV zgcH*voZ=#Mk5p|6Yo*!_Lv1q8auH4+sa6BSS_*eO>x?|##W-iAYWG;Umb%16xCktO zVOhAwzRJb8oN9KnurN1Rou49)iXO3Y6PUY ztJTZHY>^uZA3R#EGPofsl#Oz`$Ys=&!syVx7`3Efbfn8@iDuM8g8I3X; zEi;UO8xmY-)af$nNMW?RFGgKy7#-s>I$ATb#Q`>2oy^GE=-4z#+u$-fF-4=}lNs5h zZA_!lX<($#z_7&#e>V{W=};v6EgBm>znM5dg~E~0*As2lelbxsG%s-rSZ*lvnLs3W zZL!N85*`u(yRo@hXuKlf9dfr3HluSbn~}MyCD@FO$W<%-tylz_3<-zA+vTb?CPK0! zF`D@V?x7bZY0X2S=O(F==JxhQ%`MByR;+33>{#Iyv@y1T|I)4L3qCvMD|4QDA8|jiRh19 z(H~4wMJ=n^)-sV3Jv0_#0T677v{huf--`^6JpSdhQ-V*e0T=Xxu1YJ$G8T9=m zRodP@uX)Adc3&I7EDnXf-4a#t{I`t;sJ%i^-@nHG$3neJtn&M-`OcbV>LNmH0QHl{D8a}3j% zeufHMrh8k`KGdl+lof`u+@&n(QYA~9JDXcpwRWnL*v*Ai=%`SrD3#-Weyc4s92*VC zI+tU-502HF;dq4M*n%hX;V_ru!JzC|-Pz(R>eM9^IrnWoVL#3g~)KBOj$)D!eGbgV0N?Plz7rlCB|=-cg5ZnTuX zqN5G5-p2TfP9VGJO<5{Ph~ATJ)u2me)!NzF(OJ^5xYZk9nC^z|hcyx14O=4mHCA0o zHlc50wY+tCN9Q`vAiB$uN=6U9niW0vT2^!qoWhFkfj7Y_La({HuG3?#W=apamMIF898rdLxdnod&t z5FHBBZz>~8SFe;2tBQ;_Er>P)ITX`10w_Iuur56pu0a&c>sL}N+?SI zd=eX_??WA;Uq&6GU%pW)9F9ckB~ruanQtUV4pF+K6xaYdz|w0XTx8FkSoUvB|p#32m6}Q-yPwUQ#6#qW``Lpx^|Iz7|#e z%2wZWiP;ni(UB)QC4bkZ^Dh*pA4t_EL>TGG2zON|OkbU}ks(%{t7r!oEf2^~wHDIXvThv|S&ErC3?)m>`CK*a8*CMH(VUKqO3 z3z^l8PR!Ek#-bJq(Gi?0Lz=XNRg8|#L`oIPp{o|kJ)L1mS&GoFl`aKzhowVwgQY`s zf2Bk8h^0gHmZd}Vq$Qy+{bET83g3&6l%Nn@V%d5`FJ`KI^$Lv1I#yJadJR)3L@#El zwzH$9Xz}9C)~+tEo*pOWWor`|hK&fV?+}Ev^ei_t$PHz{lXz8O7%9cSIJ)>ypqY$#~K{mpDNFUCq&E-0sWJpzwOhrhieGeD5yTH&MM)FAfzob1tHz0?QHSFlO)7JNiITG-yDR~>ANZv8qcWG&bBqJoxb9Wh#eWRnS_K3 zfuviX{oK&LHWb5SD{6xCLEHRUwZ5be$QrS2p`H#pslWNV0u z6#Y9ebSJ_S|DscrUjyh6&z*~zqx=*>!}ytk4n6P2@*4>a`->amDRxc!j0@w39U6~^ z-E}O#D$y{0aiT*{xUrABFn$W7V|jF5(?0CN_>GQ^^?X22RHWjF6?)1 zi0Ab+?cFZyE;n?i8_RFKH0NKtp*!5z+g;dgZipWVXwEmgFn&3wx!mZ+-r&OcNuQ3r z){VW!gx*@bnxp_AO$jV^418%nsbC%Ui`+|Y4u?6EHF7&o-mjXm0ht#L!E z+}JJ`*6D^;y0INDY=s+YcVm~iup`~jQa5&q3p>IMEp}sDT-YKvbhsPa_Qi|zzsFn*a*KY(F49(gmmK=M@SF&Y7o)`zG{RpMZ$2f3Lz<-VLDII zW9>48Y`ay0aN72fu0uA}WX)y#5i2Sdr;MG-ZA`_A#jRK!u%koH^1ZR09pm-qiGjs; z5F+(7@{Jq%(hYs)hCXpaAG#ram!N6ix1sPm2ti!Yc zsWOY**r5uAUh|^8*4-}j@%sg}$Se};wtX0=WI8qw+au#Sa1VtMvfV$wGT4N)A2ub8 zUm&EBhOzVrSJn`ptSsW2r8bO`S7S=#ttIoU{w5U3@S;w-B9rymkx2`UX^iGgp=Vg50~i(9&pnko~hFzo~hIAAdlGTcJN>u8{%HQ z)pY^Fs;;%GwR27D;$T?`g&G(+ueI5?D`)F551puGt(_}c+hffDsH~wO zo0Sk2D;Sq}q9!DX@@)%&@h6i_FlX+wq9+?&wJR&|GgMIK^ z7akg(?F+B+g;%@b@Nm)&PUy4|KWx%A!p9Si+g$iaAAF?`zO9ANAFwU1gr_-t|C$7 z(Unw{71cD>HqEVzH`W?W{2)(SMyE2)veEMc1lUtRo?h z33oIcbI;~gtt@|g4FFVycM&*wDI8ARclC-D&C6RC=dWsBvY%=UyqdI)*Yc?+rn&9S zSoS9WU4>7V%G!M(4|5IN4e!bP8q)DgJf!>_Z6~L-=8j>e-bIvDa2s#9?UZFdP^X%^ ze`5mhqmH8uT4n9$}UewJFTvQQ&&3N^et z-tE6a)knokDmz|PH5MKm%Ek~)agUg#pHG&Fso>4hG7V2@5lt%>HLb}E4=(iF%_2RY zq~DY8px?{G3$&86EZmgX*?8w4d9Y<;4J_b0cJ5H_#W(h_d`ZK+Tww4P zT0CDmgFM6PK!bab#Wg%xgDIQ(kmn%=?@$kK_)3Y4U4k%w*7bQy`LX2WNZ z#fM#qW6G?Q&BKY~%ePiTbA+WylEHL~u2L5wYN^3*OTy>qfPehw@sFrw2EX0n4~=ZQ z5;){LO`$i-OWX3#ZNxHNV-p{?Zia_<_;} zeW1M0koTj&FH_!UD(ZnF;^9uf?7!hk6bR}8{d0go{dc2mV=r0DH?;oruLg{DZVjG# zH07m#2I)R~z|K*PCoimyH*_ahT*E(z7g7m>x8CBp zWx|ua(Z;3koh$K?degk3n$oJWrV8}-bu~pCs-y#ZdH6HS)9BSrJzUu#bu!` zvIUlx@73dRrq#>j@c2g5 z1qS~@i|^Xsi~EI*8y(8#rxTQEdGYD-i>gZuze_ho1A0Hr<%Z@8OOqSQ#*r*n4rQ?Z z=75eP`qcsY40V;EzuMBLACWGss9`CsFKfV9xEAB{G7d@8K&8A)Pn(}{6tb$K+S)R< zNZyN=m)BVx#^ZD!bfvAX1y8Je5>qJi9C z*@&uJ4b5$q#*{akpC13Py2If9DjjaX{$ceSgL|ioYsV^HdA!Sw(=$lQWI6ZCyvOkA zb#W~puPpxF#wC^OAg_qJ*YLW};``DX#0{$l4DN##w6=-sR^|e zwQR%7<8{?Cee>!_a*Wgyl-vKae0}9M2W6Ij&mhiAUsOHIchLOV((Dk*9soRB2Gf`K z0qQwJ_xz^lQp)@Q^@5@Mo2B#BOX|0&dij!}ec95wc`;DgxWA{wd3o`VO~k#viMW5- zxIX%niu$;3PF?AH^~&47ERR0Y%QomO{CRmZQ2m?l$eXt?QS-Y6aq}pvw&Up5&f1Rlww85P$J-HCOMYqMevP;T zNQcdZBifd%?$l=kMgQL-?r_qjiMtzdOJ#i)TCQn>L9`yf1AL{}vWF0(@M5O8{s2OTR~#TJj_{cN@W>ekM6E-q4m!;M&Y zF*JV!&P5tW>&PtcT&`1SaQ+0GD<%D_J3Fy1gsj5aF;p>kM*Kup#U{vzNHNWKK&uK@l8Y}>q8SV&&H3fQx1VQ1T_R+sNC($(_+B0Fsqn^7UE0FwEx1oS@329=mnGJ8E7g#&e}cgNTD)bJin>9 zsGbXyZdma9n0a7^kZ$&r1`IAJOKhdTfxdPH%3aS+zXmLtdqbBpcWUN`iGJYwz2)17 zt{m$WRWQ${WQIkr?85Q)atrU@^$72wAxemotrO_VCoqrnA&A+@|vBz#uG<^md9Ci6e zX!-*0MR0=_m8EfhiL_#^o0?a~V{jU@G*DcfkZV}B@gR&3rHNE~(m~ror@DOu=8G)! z5mryZK^DD7>pAXQ?Z&OuF|8R~6>!Ew)lLTLro3h1SL98vU{63hNFV=utB5pbsD{rn z@QF~soy)5#T{A)ba;!5eqV=!FIEw*i?QYxgH!S3Cd$$z zso59|>GGy-L51GA-TH>8mVx%d?x%(t}xoE2JD$_zpO zfJ}210mlJq2-byj3w?!1wI4hSjsvXum%A(N*QY;Iq)=H)=lb?eUST1Q(SkR!!OTQs z@lKp{CT9M4yyuc<9cuQVw%NnNUj#|$bM~-CDS1P_&}#%$I1~8}zD&Ze@TCt;ONoLF zBZhN1PEOVCIwqSsv@Mk~iu<`Mj?pVazNb6YEp66&Cf=Jm+NF)mALi7oXv2!v zXw*H0PS!(y_z%6Iq#B<8k8W?B-9w@XXRH zyXAn#9uliE@vD=SR31{&C9P7%A$93wqz#5%+SIbHdtEK=!!~!xbui`;Uatl>;GW0( zJR2rGhe_SY#J^#VvHm7owxE*wu!ez5$f%J+ZSQv9wf!#fv|jO`f5UaL2s}b+qBWK9 z3#mLTLM_4-OHk*P*HuPvZnE5@r|I-qq_m-~5+;v^I$5u>3^*Y5)kUNAWzo`x>IjS+ zy1qd=FFAd%PKU!p1&oz~J42^MYD%MJu=d5`4K=W5hS4#SkJEm^Qx-A#I#=TwqVsFR z^%e2*x@ff!soFJE=YedMMIbFjSvs$}vfAatFr5~Q)L~*$_=lUc(uzoRSf!0HX_fVE z*^xS}ELt6|tWj{;I;|>Ns_d7V<{VSr@KqNgUqd?2=D{eP=5hx0P^vLnerhnC_WD9!#VpS{kp7 z);82uhik%%A|hnOG1!GEiByD_R7UG!f;+=aFRP4&OJJF+UL1#stv*@`hb1KynJx_b zrK(z59*N^+F(|5$dWN_#M)pf^qNsXxsGDbqSI$I{Wis7Y89Z4o+!BnovT%JQUIS7W z@qq)0?HK05xOLH?Vk(t!3PG0PUS{A&x$yPjl9EVSyreF=G)AdWeKy+7kHxAQmI)nW+%(hI zn!R-NioxhwretDlFSx46qHyVQ7_O^p!FE}I>XEsd3yVVs7fxp3u?h^BG8n^rUAZJ<%ml3oj@Ft$9ehXXbx&4R#_F|3NRgv71H7)3W+*LdT~R&GA7@E3b7is?klj<*eMDZ!!dD z?NUXC8Og*^yVRy*h`@!HQL?i3&KQH0pXkU&a0UvIRl*5y3Akaskpu3`sZY1ucYSh` znD5#SN-JwQXcouI8$ci_28WOqE-i&P;b5Sq5~s3E2d9u;6Ilv}0KM0VLr=uesWNuc zBtKeJ)<-@##_}Alpt`&Yno{Zo*N|Rc*MKv9)LU7O8C^R#R@Xvf*VMEOCQJ>F0m$1#Zzf!QdlJYx((r%6w&qKtyPvZ{C`?~_-yb#@_|M7*e|XeNcUk1X^N zdUS@p$98Yd$-0c|JIpWoI;h&`(kc}M-Zj8!{vq~KlKoW97`gYO@y|1~N;1&OY@5ou z3Rzn09e>$xC?)%rV}Muozgv@Uvu8Qnr;_GY zi{|WIu?1Lr^5nI78|vads@>3|&y}WtDfAICXPq1cd?qK4)nz(N8NKhA0(h1qoClxg zbZPi*0}o$7?k&W-xep62jBcr{%_)+>QT7A&lABQfo~YL;0gtu)L)m|n!IEq4jevm< zRr9J9u*B2EVN5NkgZZ10pRJw#xvwD4u__84hjjBVyJQ#aPkpqD&NV5lo+*;OcAa3_ zl|Arwo!CdaPO{sTy$kJHl1koTEAf1Y`f8tcF-p$X?F^-jN$7T_Cur>$cw4t5w-u)+ z?8B{AThkNSz_APMgzrdPWSKp40lEXNOJC zh+Uwk4>^Z%I=Q2%M^hww{eK2fOsj3^f8f}K_NDf-k%rL1 z-d7`2<)Njbr_R#tgpqZ?Z9F@qPo=r?fhbBiy(;K8wQ%Sn@U?ugK)p;_ysc){jSeu~X6BwOGNO zjQ5I?s!sF14e!h9@Xm924YM6-=?R9Zg>_4(oi1sN&I`mk?FW*^h`G@Xtvc--Nn?;) zq%p*rPQO6X85=j&wGL^VngKlNFP;z~u>{;JEG&z6Wr&%FDa#pGyJHncj66(Qp?dJ=>$F*>aI1i@_{EQX}-#$87tWoKBJz+(DpC& z_oMb2bN4u&=j24wro_L!9U+!7iz16*2;hdeI#OL?tYg^sczIfEV5hfZ^!)6m8SY`9LOk%cLg>BNn(nTZ z?Hk+FUJSOib_6L~>83(rZQrn;DBLDnSCxa%dkV$A@D)vA1tl9EXXj2K!Nu;Z_3pjb2KGGF86@9GbC zj7A)-jiq7|WS^)W9%RFqY#!fOEvkA~WC4HOR=q9bLc(OUNu zBFlz}p)x?#MGkF%_1wKV$LeG{@_RJQ41p?Q>@4?I>4 zl0VwcH+D$PBh#m2Y#6c20)^%qBHDU#t_)3)vOf5?n+>aQ@N#Tbm3#c5+MR2|$+3=y zZ+AP7%s>{=LGR)|Po4DlI2%ST^w!kF8dn>QRdQrQyFr9B{o`#|bSG?Hb&*=wvrHQ_ z+#WVuX%!?0=Va>izP=I$d&8>p?#8_R~KIDlA*_I zo}G{WTDH6lQ>v#oCfoTmH`dnIac(wq>J&S_G#Xu8NsFI%GPkEczZ!Q>U}lcOu1H;8 z8o|va*Cs#J53A~Gs1=hrprozSQo%sO;)Fx-M)NnnPdL>G!{5F7gsY42oXWsW?-LG8 zgU#H)74!**Tj#L~>65+tgrT-vR2ME&v)ev4oaR{tCP0I0Utj+0+IU3-MU~7J+IcZ` z<^ao~@HCn4Gi+FBl^9L6SVbp;Q_t*Y!}{xu!8Nify435>A{$op8wXFFdoDK9m(Ppx zzHw!gq3~>$4J$&7TlKY7IQfLd7ne0K07X7#+i6*j-P`T z*{Srg_oqv*@?6A{42qF=iD^E>q`D@8Ts@srOZOs^LM8sc)8Tc_{7L1YO6S+}+5B zZ)4Xcy$k=Pd0z@1A{qjA1%rQuv}FIr)X@YjG@vfk~XgUxOX((3wsC$?&i<_WsKEepI4m&&q0Pi=U1z$d5*AvIL1SeNqN_WUb< z2e>@T0>Ss`#sYy><6dd-KC9LAx8%T2_FOlECOKW?G4V%VYZ|q|z_vRydfjN*B$WMO zV|_c$-gF`9W40vSX~Yc&S8CjQCCnS-G%DfHH)fOt!^1b&Y4PP7d1ToPr*U1l3n7;q zyStjT+%O#;n=3ZS9UY7iXhcTNc);S!5b@dijvCRG4}J5`eb+ZM6OHL+&o13iUQ<~H z7kJ!_(rYt)uS?S9j+9P^PdK|x(v$8=$s7oOa5ul#eJNcB{K8!rT)?rf2*`X3zi>An zhR9y|@C~=~y&l)=FZhPL`8*1PQJQ%z|MIEOW<-<%e5&>=%8{O7M@c@{;dbvFu1IpZrU4-%9Gqw&2W72bRyV z()+l3CFMiOa7s1X_pbzQlm$nA^>MdKU`Jc9z%Py9{bq4d!_Ps zv+~);$@#ffzI%B}%kS=1o_B#t)jQ70lRmX*8gJ!!cehlzJ*+(M4wuTCVCC6&x!6|| z{dpcan$}5HzQ<4dUYEj==ZEWczl*pg`(fNWUd)?f<+;8(@JPYgmsp)1fre8WpQ?kN z5AGO*YFBGG_XbqrM?O8@_pHS^8uotwRUW-Eff!@vvXw{j3})wfGufjkXU}AOcV{x( z^WseQ2c(&QW+wBNdER9zJ56RV%+1%CdD@+u!6W>W83^ATQFAQQv>z?fDq2>rQR!2V zp6x_et%ABRvklWm>okEx-=)N?`B zEoXg$okn3P-H_>p%vL^WwGv-6<17F>(ziUfapzL+#`SE|r*58(z~H`nkrXC_2HB~& zdFjp-DDT_FfUEAxTi=LaFJlbpD-q}gtndS9)8DN&rMqV&_F5iYxRVvWd)ojwcQ@_W zJGDmykGhp~t0%~VNW+V!O^A<1ZGhY31ds#c@~ZG6SfXoaounO_G}8|KGRmmKa~Dk1 zg0CPDWF;=?V^=^w7_%$j*j8g$$^J{I-Rua$9UUvoO;n~YM7*;(dL~TMNhkX+ctY&Cj-XX zJ9#Tz=px^#`g&~lu%Evkx^gsY;p_3=nW9LIUE@GJ94iVQSZX$Aymmq#P|M?}xogU3}g`!zMZjWZgO+n=4!A%h zyhG|M3zNUe(x81JT1(@^76Hb3B) z@Pmn_@fGB_NUYNS74M03mbR~3hc77UIYp#A;P=9OA8^?Lv+UJ3pe1ga8U>Oc)cM+v zLekQ(ck1jENY2!fmR`MTwH`h4K1h}0_Qud4>4Rg4mg~i0khF~0=5>t>2T|41rfmH+l#*D{TnifU!*4K13UHhr~9wHF@za3Ae|P zlI~6`HUQJ|hA4by0yk}&Is`Oh3!}lsHv{4u{IBpC1@Uj{P@l&g2R}Oq3V@=kWi;i@ z!}#I~3}4&_30KEh%zHyAnV;xIsjP!a+a=qVK1P0#Q`_AL4jNv6!n91~L&0|Ny*N|( zSWt^`Jb#Kb^KW6M!knbk4M9oCx;=@HeJkB>y<&0|w&5%(%>zkTF=2V@4{~Ahl*Pj= zwp0XDmVvdytxx1rOC$5lYKoIXth-TVTdOTtJKVC^7<9Ea;fkA;pXs!?`Ap}$NlV!0 z76-NE!&@}>vID2e(wubX10A!dkC=6qNa>Y~KgCGQSD;HIW?pKE`5O5WVSu|`EQ!cl zWrdVz(_-1dIw<&!)xL#V3u%!~<%?z$lUiahchlESXv4F+@;XM*$=!tm&nOd~!}I}f z_2yZzWH~=iM}z~j5;AZ>z`hSd^Rk~QV#Mno#^`JHgDJ%U-^)fWqGc#cENA3L&*l|bFg-m*fOOnn%3yZ zN11|)h6t;!Xnn>`lb= z38>G=a3U4Gs}!%fvc#^(Hychw+37U0-^b9dePb2v_$+Tr=NjzX z+szr3OErJK@?=6Jbu6;#onbKr)s&^)2g~+q=7zqc|4Vsy@mM&dJ!|n}w);slUI;hz+Ju{G&a6H>f5#FzImLbetWmoe$ zwH{@CH+pHld4*oxGf~F;`?(%JNlMTRilk)CeayppZ_7B2y)*$vubU26UY_XJ)#F}0 z9ON91-XLfojk7^V+y#}hkNk!FHg@xhby^P!7YJA3lyt9xluED*Ez5ae zL#+Z@-bh^1#JO(7 zi6yY>!8LEWp%m{mygzMv1@D!!#DbOP@Oh3rr}Mc^Jr9!SVo4v&=hEf!oWW(~M)Ima-8{gBNRM zwRbZin`xCZg|-|igBJ}SQtz|O`zZB3$Gnf0vZ{?^R9>;k8!LGpJ-exVBq*A5`MxBI zrM-IJo$qi_jL~4O@sDE~yhhFYc)s(hcet)DtovpUrj@D$O4YnBk9qo zBMT(H`37l~RSagKN5A0GDO^_@tFoliJ~}j7vq-KpRW9O?P`!=w9X}l0(cx2#BUMD~kV93~qv;9W2up&6D>p*WL`oXe z6%IqY7dfIjd`J{;v$Ry8d{Um0CVzTmjg~UDp$@8wm$b@MObJ|XSmZ`TQu#{|fQ2HZ zqfTfD(h_iVV<<`3w=IjS^)&Ook-96Z;AvYC#R%Y$1pI)jssxTV8e)t$CDM%Bd(u&) zrn<5suFBLc32PqWOFX{(NQIY&GdEuzBHLD$iVLu*TX-UEh)X~Fc%{66 zVN4X1AkD9*8F-sEb=!~mZ@BrK+=ObupS_nUr_xbER){8oNgcS1b&m#8iy-~ta&U^v z!RuWMOa1a#Z3K~YyqP25=rqoD{4kxCp`b}O&g*(?q?vTr8(-<2bd!$j4~sA@v2}yo zG$k$~ExP`}CQnU@vSP@}&yaOG*Le-9g^D=UK=rI=h8(lrO}%>&wuxO@-IKt+GdT$r zffk;yE(5MTffFjRk0{nK-Sb1I@h+#qebnV~&yuswa@2uchjCeJG2W$zAwA)KC>8i% zgAHP=94_!I<2dI#RP}It`8Iy#i8I_@6|b$bx+QQI)%BQO)E=XDUXjVuUZW~c`Jza# zX>U~pf1J^e z)Ve&*o`jl_UV>KyZ>^#?{VD8Gtip<2Z4(Nb6%p8o8>)4Dw-n53N)e<__4*m{z@2aBFDbf?H`Jb0byCalnhpQF-Pjs^po_bGn?lfvU=d z5u0;aq$;NHnH#4j4{`jko>6t0Tc(m1RnghZjZy_qwGR5QLt^ilo1~Jb+ifJ*wB6h$ z6&TzpgxJe9EhBa2CaIUt)s3)EaF|=93cnXG)7%=B^hzjPJyOg~QArn@8~GbY+%5lp z#oQKEc)6V*m@y71ewf>$0<#Q}>!Nj)xH>G}P!J~B!8hUoBII?V((c~7mMB_^WCfs4 z^k`*W$+FOx{BK)9nvqT^T(y%jv`E=y*61=Vri^RhNq0@- zDNvEmsdx+P8Qa#0`gju2ghOF~L$;LXBteYAK;UNX)l)s9749@5(RJqwIBmfe6f+`DYXr$i93 zSJwb3X5L2R6*);?v%pCL?S7k(XZ|fTJlfeQ&G*!tPD?Iqm_EPW$w*1JqGAv?(*~1% z+Gn|@fPESL8$8a!%b0IFw=bIrC;A&`bw*0CBW55wbr%>H}m)3((zqG-QvN%^k_YZyeCsVuFm#{vV|UbkwHm(R!~A~!r)AV*JCEi)A;-EH2;Ny|gAUdR{2j_xn) zHY81(y(1&!yI$e=f&A!8J^~4%ZVYiO0$!NT@KGg&j3y4AFcDQoyttZ`pj8QHFO$C z#V*Hq@#v_EDfGKL-zLVH9k)|kSymmZ6gAU;B`!aM=i2#`@*+#MEc(;2@2#q=HofZ4 zE2|5a8_O~LMtryse-;}_%!zsxhKSz2d_*j9_o|5M?aSlQ1IQ6cLUeCm9%_x2yFKsE zgJ~JfQ®$^Ja0Tc8)`dvQe1MsN6`#Ag_ik|LE71Fm!4r{ygh``0X-)o85)@6qOt z@cQ-ebyOe8Qscd+1#omMN%T{9DGVQE{Qv-=)s2Ndu%A^#(7Jbn=69 zYOf7?-+Okn!Sf$6-kKaUj&%!w<0ua)IBmqPT&=0hcpN78J=Nj68G+`^mE$s-`6fe- z7QL}N+A52Kdl}=rZIjFIFUeII%W+KW0Nzy3OS+p(dh@g&vVE$_^y$Igr=3hM3et-} z>jZe+&>nQD#l>QLtBX3JFRvTcA!}+#BHKy6%UXAdz2aHte%(Z!Wv_F;Zo>CW2QlnA z)Ynb;KFn#8ubYs!e9v~)wXclhhEF&27HFhh;7W_e(T;0E>1|Cx&$=g>`Kf$tDwbl? z!H=29FGN}-`fAj#tc8|0Q3V{3Q~40M>9ti2ix{IKF0S~VK7nP#gP{QwQEm7cP^`8X zXiD@7tRNl?H)&#CLTs^^+Kt+)fonmX@)|I01#>g)!F|(gNze zS0bvQPO!eoaW75*2HslrzX<2}ti%;qsj$zl z0R+cgb4SHST&S1vpyY&U)yz!zE78Aq!Svr;0tb7weC}bZ(Xu zs8hgfLGXM3KY>}PNPr9irv5ZP1U0YY>^HZ#D9`#gbM^tn^JdOHVE?&RA|7WJ70sJB zkH5t;4=85d(NO*LXLN!$?000W`0HN`yY9K0t8cmV={u+7$L`yHeZUztEW=@5*L490 z7CrfA^P36e_P%7i{cmWt;+5t(v$6rRG6`;>lf6*dsrgR0m+P>rOya5wr+H7fjrhN$ zfluB)7f$n^IUii?IFI)Qr~80#8T&ZSZ~nt4@1I+r?g!@l^bE&&Xq>+xgabnhDV!~> z%^mZPn}5W{mbR5E*B-I|yrQBRGw01No;zda5sfWvM{FvdcSOsId2^0vnl)o(YbzaS zox)WPN_1{$TekubtJ~XG<4dcE;&()MXJcVk$BGRtokw(abhoWNq7`8$Ivdv>(b>^- z1U?DcxHjI&uq1I@%izaZalkO6$thgf-su#UuiVgdK+%l#puMoXeIWI>G#=63c+9Gf z=J>`o1dbJ|`sDGQ7l`!su%JZ=B^69$Hyj9$&=>@#?Xy zy%s(@g@^5r|1C~ob-k0bJ>$R4vjQh^FwesOkxpXBro^9|M*_j{x6<)!qnr69(SHo zwTCY1ua3^{^>BFZ?37BLJL$N0jz8?0X9pcN``P<*p05j?$m0Lsx-vWP+l_l%Iq01S zh96Y>NzSjns4fp(Ja7c-J6bkiFDQf`Hv0EPSH3lK&e_*GM?U-B+IvEm_1o_C%}t#M ze1ebkN)54=*Y4P`ApVC*vvxmhMoZ$1(B=Ksu%b0i?n&`^+n@MF_oY9)D)!abXCMFP zU#Eqx=(o5>fLBfWuin}G@(}052kxFTbi@9~J{`KU-)dI03IWc{mnYPI{n~3&qj?X{ z9veSA^y7X@S_E{%w{VrzbI09-uXug#pgku4`vd2PpFeVV=&Em14>{V@B^5niaLAE+ z{^$>*&)KrqIe&aD{B`J>omE8b(z$X&d?h*+XNx3FYI*4RClh}f`t0?m-tgr9^NT-Q z9=f`}T9Rv+{r9%%H{J7x(~dc$HU08n&hJ8(?yQEUj;QZ9>D<9%u72(G`Io$S!M}E-haMf$PvMq! zDfpMCuDbN?p(m}ZA6HzwGWUqXL(gXQQxGKUve*9U_IFSH%cX~%eb(F+7rb*}AareZ ze`Pmf5Vv)$n$gnM3LW;RpFciqMd+M=?{Q1hpD!3Yu`+a5&Q2(wyXkp2A0FD<+3lcN{jy(w|* zUtbD6-CtQSd_{*+`ZER%ee?TI9XO-;tBgmU`SXP@gr4cI@P-wxXn(YD%e4#yE<1&3l8}3!Pl;NWX}V;@5w59_rQ~G54DZ%rvGhp!)?;BbN05(urY39esZW1BF8c7RT??K+Efndu zI1Y_aTuT4>y_3Fw@2b7`d-~>{2?t!eh&Hdo++JO5sQug+iwm|XxV{e}F(8%ZVm#rxc-5l$uED(3Y%ps*uyexd+|E<3~ zL-6W=;Lb-550d(|Am{dW#DSK zYSl^SU3}65ITzn^@9USI``RI)wd?vXY}EO>4MT&^o^i)Hg=zn|C$#vDzl2)*D~ysI z*u)6x&AYEZ^ryQW^^=k3ZQpdoGke8Cd2Rip?r2sD{q0+)J$UxY(~dm&s$1`V^~tQ8 zL&0PFDU3THox0H{55H)B<`6q?L zFaLOtwnxU!36=L-ysb^O`M|*&>+?oc} zUlKTBiA5KM&hG4|I0*0Dpm3j=yZVU>>n7#S3k|yT(4!w-9y)eIKZVyd zZIYg9Tyg6o!(X~1ZN+CD4{!VTl|Kw!(qGAzb?c<$*xk4NxcT%UH~+Au?zYN|5&MR= zZ|VmpZ2j>j*nzbo``h%(?%e*f)9S7``s#beH_lCjPVcV*taMg3DP{7rW#?V~%Gbwz zS@zTO-(3FIS^I=8J)s}$s<7IrjC|p=mMhl1ai();)*G)KyQDF6+DZMFZtGOKWYg?P zdD}icVby_u`Lz3^$4@vYv?vkaZXf;8%RXRssX)%yUP>jL_wFNQ>mO|^K4-6qGdAD) z(5In_U8-P3CqjD&>*ri~=@Xe#>fX97vU2p0*1i80`rejZqM)-yHGkVvoA1gB6@K=w zydS^3=8$tYgbv@O@|}8{_03ahtB?KZQNI}UeDRKbu6pd%(80S@yltgwe$Iiff75#8 zC5J8kru}!rDTBlB(u-G6$&#bIb^+o;Cb z-G_|+^o-2x+tTbpMI$ps#s-{HfQbt*tB> z_jtoKr_Y!Zy6L`ti#Kt}C!Bj{?eC5{V#TyuFPgI3#C2cX@~6<9{jFMHdvcc!Wl!dv zxpBhPb9a02qt6bU*S$5g{h@wwV*=i=zN3AEp#RTDBbUE)%)-hY6K-uSJ^JLap~w2K zU|r{?b*kUqzUrr+|L&Hb$M(4Vz2WyvxNrB+8JMp4H ze?I-b^DhtW|8Bq3gYxx;^Cf?r7Kw!(y8i50fB)j_o}NhPvH$d29?Gbty{SvlU!HT_ zpketBzFn~3+V$tY^7`aZ(MLP2K(;C{05qxz`K!p-gVx`6(xykB-TkujPP%MMs9F{O z);2MiAC;kz<_%glxlF14)9|A&|H=FrkI#RmBwjM2I~4u)wL{Iec4J;K7F3BdDYf5r zNkQ$pe?9Qx;|HGf+KX?D|0GoNU20dhTB-QYOI|-JIR2|kYKA^vw(sBTZVjFPx$yMc zGG%4QhBy}KQs>kcZhPst6_Yy-dG(X^zfQaLgwR(5t5Y#~WpiWq>iCA1=8bVIW!LM~ z?9|s@to_d=o41_%;-6xx4?p#>P~eLJ(QV;S{MbHoOv_hKWuA8D<}7Ea`D0i zQ%lQ>ikB@oKpy7wdYH9LGVr4y-1mjf*1=ACVCGfR5^Xpq4d6`a3L8h+!o^kL(h^+h z0gj5Qf#T6^XwnEc~xt_!6-jTsWe{e_pmuG$W{*tHmJiRG&)ptSB ziu>2iE90$*B_h52gFDXn?BcyH+vnG}EnB(yqWkX~F%`Y+RN>rWqjK@w9vGCK=Ok`L z^AZbYF2Et~~!JmEcS>$~mDGE9x z4klo%t0P|7S<~Ix8tsUzTi>NT3j)6fXkf%sEI<@x-RqkTEq`NyX*dB(9E<{sQ6R0lAV6w#sjt9I zryHN#>uieG@H1}P18F$4OEBDI;?*+znTvC^@(LV|jmY>~U=d?2F2RMjX7Cs?aUMYn z%kifZpo#iGMRt%_ge=w{7%{^uS;=)HgLyf+_)RQ+&tm-98;8M(rl2YwWbq(T21cw> z#VZkxI<5j*8!~x!GO-?qXNha^5!~eW;U`6~QbvOE6F2kmL7I4!AS5*Qfq zh_B*Otj9XglRQUGq_dvOa6p|ndp!O;hSDEh;ZGi@vQX*9CIgbWv$!Us`T7_2K!qT9Puw-oylR% zb!8J+*`ky2XXa%5`3fYmvh?K2-t$!^1gaXFR~pAD)9OjA^4Ht=XA1s&2>Q}f(f2~{ zDrNL(${5u*G4o9PIVc~0_7AFRGLtEzxOt*m*Nj8c&NZw^h2GM&$#}Z{0#x+#0{r<0 z+6fmr=Wr}CbR=K#jic)o+$80)jFT7%60)2b=&Qx>uZ`ojXar?vNa|T1+t;&@{AWmU zmNV@2fQl9yu8T!4*dEys~8%MY_Uyn!&_^3@i%Fhy*h1Ue=+3kL3-bu`n z^!qXH<))bB!sjGLAurR(M!oQfLBu4uN7lPO*@AU@z)26L18A%Zgu6KEE-Ji}Dim!3 zH5BA8dIjX;HcHBmt2>E#z!z}X0|*0-&xG!PQ*|)Y2_%YzkXn>Z`jERSBlTyZ{`P6O zy{SC0;0NX;)=0TgE^Tt12HsjR#7TgcbGSBQ5txAr8o>6xf=uJMTB`d5)oI?+f1VeT z&FwG7u8l<-aI;A1=H3Y+AoL-U&%h zr+%rIE`JnVQ|t8&;%z`rNKVhx+WK1D*NlW~8fxQ<>Y@#`$ZG+SSxvF=U-MEc!^WR`{S3+L{Nn8pp#Dhi`XlTi{n*rsZya-!|<@z1pZUV=o&3y zQ8A6-HPiXPs+y4-#OSUbvCFkd?uR)T5b!)nPw#ZPS8R+cEy8Pz<4`K*cG-d$|i@=K}nd#F>Y6m6zmwGalX zW1Vv1#gIm2na+PLel0@aB90$i*_H?s96}UTe87)Ecs=HYQ1C0Opju~yfW3N|D+<3=CQ!^6OKX-Z?`|yC|m%IQ;XOJOOnH00^xJg$eRrJ z5LU_iWP_7lW%c3iQ560KExIL7Vy$Y=|bUTrS2l$H>5Lbqy~Jn zItcomOQd9R$6C%6cg}s8&gWK}ae=0yzP{Fy*Icx+!0@n-Rh3#$WjU7{IQ!EXhSg`Y z(b9+VSqdld0@#)5>;~*=j-ocRlzJ92NBE^B`D2!zjN}0LJ*yoUN%c`&>5L;dz+!%G z&uY;Kz*cDHVHQ{%FK4tMnZiWgNY#{w5tV}9b@hL%Rz`;arGqW!K=`1h7rVD5ox~~; zfq%Fn;NEm$v?V8TjWE3I8q9`}tT5&=Am%)-)pnM%30$gGq9L)wc?YMivX&8DusD(0 zUzk=^>wPBz$qcBU<@_h7whUL5%aAZdW~h&HY8n3q@7;LMbY8ajqjb95VfIfQtm))H zXUlQTxE1g0ndN-n^l7-Uy+c0Uf(og9aCHEBUBw5N8#(T0m_@nk7G*j|_kuDD5w)7~ zpm~w@aSSLuoF)s^*?tl5e~Z);fKi}lf-6dH;C>xJ!&~v>07uU#1aVn}yIszxOlOk6 ze*4>&UhPv*>Jh4%r0(XY2oT`O^jWG8TwqTLp!Cl>WD28JY;A6%Qj~?lB98JLca(QD zt?4lHTMe?ZoWD%7z6k=(^CJnF&QX4z`aY2D@e>;06A!IX#)6kB1WS!kwMKXGV+QHp zC}_^JemXLp@qRX0pC9$OG!c~T;fJ$7Md|@g0^n>vphO^IsEp)qDte{nf#RoAOlmT+ z7>qf~c~E-RaY9%iT!DBn_BXO+TGRtP%UNOi4A-ere-6<}ye_?aG$40DS7$kcC?F}m z{()Y5Lu$H_lNdrdBu`=wjasVKlE*?ZDcyiugkr0)FWr%lR8f z6%9*0-P+|D9-PFx0&ugexA+kdl=-(LML~7n-^lf84CS8X{8p4* zs*gvYFeABRj2Ufeu9DNpAl-PK8eD@mGBSFY@7t3lS#YY`L z$Y&q~drgGW?5e{30%hvjngP?6lQ>djXSdNwYl|+U`51dsHlVN>NRv-9e8x0`JG=-z z=OlhFIWOjD9Xut|De_Brim#Mo4FlyauE#xcWe=At?)Q*A zb;qUpdm?tYbm9+&4w}CZn%~DN0eNPgiC5xgN?1)er+_n=&S-x_QhtKjYszjw*$SbO zi!_R*48y~q4U{@YY0q-51x~d!!k(`bGiV929Qa*lIk{l2ERHOacs~;WK>>Inr$G&u zy!16{ovAgdEHlfbGaF4M-URGbhng}#MfyBGkckS zF;kjaKZ}+bg0?IsAG~F&&4;U`f{>rJCTN6OMoTr^gC1cd5z z<*!68i26RUt3O@s_0c$#%1SE5@1vXOKi-FQy)s-j?E$v3IUXPGY!Zf52?E)RP|(Q~+@Al<8#nxtIKjd5>*F0i5Rt=8f%C-^ca} z?FnZ5-5RzGC*gis2IeQB@fwJ!;+8jr82dicc^@jl*g3eIms@O%nZh+^jEh8L{;-zC zBc1fe#FC*GAw#*zK13-1SH;L@)x`|c%LtPR#2;CR5&NtJ@!(48qDy0bT|Nq}`!_^d zDS$GDFEji0-^l2Fz@6pAs3jBpIYP9 zbMoQtHv)dDMu!5g|$aJPZtTzT`#H;87o=T>%?02JTC0eGk6=gbKT2z-uB0d|_ zIKclcry*9s?X@#G%Q@D_cyHY~TAK1DWz!x6!XHMp&vH%>p}`VE?k$?@MB>Xqu!p7G^$rJ?je1!3#U`xNjPSZ&D*^{!6Fl!&cyJLMfrJp#j|R~t zk!3n|lGU4J=h-Bk_g{N+WN(r8vHtN@6%Cg`;<%JhCF(4Fy1SFkgN{`CUAD$rzuzT- zc;!?K9!Mtxa5@g=bjObgk?9cY5wz3%M$3n&GVWuJrM%funbCd*-_CT>{8c~|a(_yi z8SuxdhAX~IG~J2^V9ld*q`!Y_`dhQcm=t9`Wnk+}=ijOLO+|0eTHGE6_{Dl_ERmy3 z;}OgY#%NfkXz10A%yh<~YPENdVbNgi-A91*e_;Em=II3ECt!nWWJ0e)z>znE%OAhV z8Q%+x44XbEPoJ3KV7JtU$=%rz6q8??2vD^qP$Ke?KvS1gt>S~E89ktKS!N^86@fTsl2ShB$=?}jbLk%Uw* zyjLG{9B{3uYjI_T3$(Fjdbht!i}OpVYCnHfvOz-VEPTwqvIdP*7l=LCn}zz~@G3&Y z5Q)%%Gh9@Y<^0M_t#Y`kD#yYCU1GK@DYW83p`cQ&ORH;_CNE8C1N;!$NGbB(QzfHS zXF6|L+>}_2I#gpS+YFBahMD2+`+R|uh)6?vk|bU)4fjH~qd}#7r1*tcU6lnXew-fpZe&LgWlTn|rUJ%+kmjpff@2rpY^tdx`1~5vm>2 z#azKzA34TBtmIdT7^Yq+GO}%^^M%Dlb9PZ5slsUy&BkKvvIg?*C^7M2Jyn^wQr;v* ziFg2`4zjDq9Vo34JX3(j{vM+2^0dHbI*oqAgRYs;{XDb7AmH9TiJgp0iQ@rv#DkA~ zuz))T_5d|$RCK8~&u^h?5kJpxP>k|=JI13xoHF^5iIvbOwI@x3wbAqC^Ooyv6f@%IC?T?~^3wXwFUVXBNs ztXi+{XP^z&qkWJ>9TXHNJLraVp6uI`bXjv#ytnPT$uEz}8d)CZ>}E+MXVRY;`N3*m ze=F1eG_#Ya1J*33PH{+u$A@QtB>qBl98Y>>UX4j&wF}vMS;9RALi}pQ87oa`>YZXJ zN&iESE-pYLQ^{65~9VE|=Mup?U!#Q3q!O=#smrUT2)L&{tkog}vl6BoPb&^a?gW25P_4_B zmm!W{@_^0*Up@sv?kBD2Adq5#%I#>TbBH^I_L2n7cs1x~F?pDMv9-a*=u(H*uUU+S zqJ)BDY(ZH*gTb~^O2_f9?BwjVQ>JK{mvTzP_}7KC5EPC}J^LzYgNfyxpBI(-3k9i+ z0~65575=e^=$KgUfcre^6-7dez+iu!*6KH9zYjr?H>`%2U`4;AGK$Ybc>=|5JJOFE z3LAmpN+MYJyV#*qjx3PR`^XYVpGr2$l5&mGuq9xpS}+N{+|hpGSB>T?!Jc;H0J#qX zB>4~;mV@#rI*$>7vz%#YLsEoQ)p2_9nAZYY`Fs9E!izn_cWFZH17w zJ9w#;8cbHz*fP3SwozJ&+&_(7@J|JP-e}tRMNdaN)7dwGE7MY z&Mk70%np6;x3O|G9ZmMhm&Kd}!(C=Mqbz-^od3EzjOPJ^US>MO{KSa<>}!WH67Vfb zzM-Ghr&qi+1P9oM)&P^QwuBK+p6gw(7au(HMj8*#N)2&X$$H>hz_GA_MnqkUi z3E}FTAF9?vTdL1oxUElz%^Bs#V-$Ep04M%la9$Y=QW3Ytis!-!@&w^)3&LcM#;Wt(&S zqGaNNIZx2mV#b1Tdx|fa34r}XG5iKi6bn|LEqwMT zQoV`K=_DAiGt2oim}{SNW;u@ux47L(;iGYu=+*tumnx1qe9p98%Ea^*#Vt}n^HdO> zgK(QEBE36_t-{EgJVtukNUn0F4z9t*NeB0BX7nRL0EfH615KI5+Eazhx3|v?D-pJ763^yFN$I9y}v1F^l zs@c_SY)Xx8N@Q6C^j4K)Wx9x4KOO$xe6Q299&*h##!tK)E%NY5YcbapnaXj`Rybr(8`R)PKy7y43! zcSYOIVYxd{P6c@Z1Ba%g*aj&!*Ysi^p7~CKPWf5RTZS0)HgBGEw5;!H??CMg^opV2 z_J#P3st*SFHtJlbP4cf(QU&$*)+^a4Fvvd)^el!kmU6GfCD(slU7(Hh%5RN_OPS6z ze|2V5iPFWqk8ki<3THZMyPYEAnoZ6lBR}vtB)NW2^hZkn0xo6nJ<_g@a+-e_(lecz ze#BhHR)v@IKr_|y8!@|`FD@6woD?b-{ASSGEN6)6Hd-`%=2+#~o9RawgU*vl6AJ>k zM z3^39w6m~HVs_%msC;vBr-yHTD15EYeR7PPMQGPQuzSCtE>?8iR`+B)9atJIT76bM| zmCxlg(4P+HV>q;)=JQOXw;EQjHn(l}g&#?0{5MCrDRyT$gV9hqxs-P5Z~Qokiv@1H zsfGi(1#uUSYet7&B6$y*Ja3ZrZ@}+10O;{3F0Zz(;1>w65btiq5<9_YyHF~lq$Tnh zK~4onamB2S(kUIT4sx}bUQb^p^=vW7Y=>jzI@Io}aU%z<^8QPU|)e=O{#nElVA(RT~vKh|D0s_jGD&X(yno z(*H@`vEHQ>q%k6EmUEzi*Aj7sqz?D<$b5g$Nt8zWS$|BJP}vg$}>Y=_HO73?GY7aFK@@#tJ>`Bzh!2jTJ~YL}^EY*G3q29d3l# z++PaJJmHL7&$&YqY7Ev`LrHa|hW(Xf{WPVlHJbu1nNq!y@{c%bNP_MsMiI_(zBH*4 z)>**sk&G`W{Czj*W@dXkW;B9h2L67*^lpYUK!7^Ody)&uPTI_AxO`kVt!R$>XV$W5 zMYH&(9+H2Z47q0Pq|HA5+ZH_$p>q#Ul+gq6fB*i+f&X#fe;oK92mZ%_|8d}d9QYpx z{>On`=0G%fVIUfCqO*su3hhxeW$@5QAS)|vWVSQn+R%iO$cV9U1BnJN3IO1kkTc?l z&@p^xnZu*O6LrzYLQK3k5Di{}|Ci$bW%z%&`VFK-gI5S3Qv>PI;FaE6Ry25(diyb; z`IxvHv`Ynn#6mdnM1xl=fNKE2#}jpCsbm6KV6NZ|>=q3^uRuuwA4jQ-T%j$H5e?oj zm~9mb`8YN@DUqI?mx$&izE&(q&n+64X))o5P{o8n2OBo9%%QPZ{+=1-g_AQ1CuLMc zb7IjzUH-(3dv|O_Ko8iPdM0P=*xImTYtN*N9orgqY^w_I*gAh|Ml=ws4;J7zw5UE% z?+gHOA{`9|@=G$y3optn{86St&d~Wz{soyrzz`B}QKll`N0}Z0mu7;qg8>O5@T`eo zmjyDT!AFOpgV$!eDSSk?Ga~`pBKXSchDL*T<_OGPInm(V z_}`;`S?w=X4*Q3Xs1E>v#D&u3PkWhsMCLPI3Li&DgUpzqOI;+To>ed(1IZ`&&#LiD zWJn53iU#vW2{n@;41AobGHRm1DU$K+B!FcSHvlm@;*e40g%!9mND)Zfh_s%HQ9HKn z3qja-dx;a?UNV0%p?`uLa2?MB>UzQWbA_=M7;6m1+laA7Fm3_HFffMaA4-h3D~xy^ zIL01@aS1Ti8;rjs#`;m$mq;6TY;(dpw#{EkjK5MC@jP&h_bZG?0OMf>;{(Ka*r@Bn z`|dy+HO3=}@j-7j7J-ce*x0OKly@fl)V zm4vZ{7@t)b@jP&h|5O;;fU(tJe32MiEsXn~GQ|m>GG%@{vA(3R;(6d$-%wb)fwj|M zeUn%_ljL;+F}|fR;(6d0-&Yuq2gc0?;|IjJISJzl#Q34Yi06T0{9Iw&0*ogcj9(Dr z$ri?aPnitPPM*J&Sie+Q@jP&>dJ@2PmvJ z0PA%I>wIFpPOyf7)zh;#66=8qE1n0AwM1e4DX`vRuyXa*bBnEmwwGcCE1mx{Vl7ix z@vO1RWS+PZ11K778!Zz$r}xBbh^Y51*HTjMve6>c%g2@%E*)FgFjmjvmm?XqUWuRl z!^h6v9uD*@9lIT~&sJylj;)ijhRoU?UJQV%0D#;?0njhp9_~3DKn?h97`tPeT_SJL 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 literal 0 HcmV?d00001 diff --git a/libs/libusbK/bin/lib/static/x86/libusbK.lib b/libs/libusbK/bin/lib/static/x86/libusbK.lib new file mode 100644 index 0000000000000000000000000000000000000000..f5ccfdfb550ef5608c7faac6769f63905ab5b927 GIT binary patch literal 1079964 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 Q)4!|Jzq`}_*$&qiv10k3PXCXpSC;kcQp{vt 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%0DIcJ6{uJ777^H+ z=B+^WfSdNqveSMUl7^k*z%FrM3}4gT=)i7uVBd9McRR3$9N41{>=_648wd8X1AEnh zz3agK;lS9(((%hSZw0E*ffYNjxekmsS?f4UTR0dm+>*`4DW1=qP$xe!P8I}7;?63S z5@nwKjZ1~Z$2+cMFY;^n9i7xsp&vH>lkxizDx-c}1r{`lV1#Z;x?V|Y{X|W~uu^Lx z>AAcQbeV|_9mbOt7;T%fX7A*o#A{d zP|Rixd)K^~h4`EBsYdLsPsL7}Q%%2Z@sr1~^EC0whX)=`*L`0Mrt9!a-H~6(F!5w- zXGs0H6!4>x>IePg;8%%X@~mi}kJsyUw8chR!c13OY&mCwF(2E~E!3ZiEvfFq%M9Z( z1E#|`u`Vzj^YG)-YKjJmS~~F?;WEyfOc8CtyDlQW=_2A=fuf*l*d6ArfU^n)_J9NX zjRSk$fw?2E)N2IZ@%A*Qcm5aAXQLZuGu_3~*_r(W@_{B zv+3MwN*YbCjI(>-a#+_3mqWT3+zPmHxQsJ8($Wlf<6V!l`KHI&d@GRE0u6ft-x~I! zc^j)4R4N?4^RaTJ)%#ivl)p?PdF10)D-fkHZz%2QOK>Lw_A=aMaFIu{0p`ze zDN(P&t%v(MT;|amaG9nUepI9wQ~Dx}Lw1}gZ=EX*>r_ zr{yd5pM(+L;8XH+KjZInY5gVG&rv!iUfVWq93~rHwtP6D$REpx`Im>>nMxXz&oo0@ zkvd$ls%|e4&~}*`wW;+4pd0o9hF^7Rey|*5P5!_Xq_KpYn5!1-@|>QO9`3S8PR|U| zAUy{gTFi`3nu)Y(c{A@BEF=9sBlG?Ds#Vsc@sqREA@GAb*WI-{9Q}B%&8}tU$ zmA&2Z9-Zd>0UwtD*V7J_O&uN0I96oyfcamj!c8r0RUI8Bj054fSox5HIL3^iY018A zM@%tICBWf=#r7_o{W(ozEk}vZ9N?!zi?BXI17^;}w|z>|THj5S9M>$b&fjF6b2xai zZUR0D3QjTK-8zw><`EAWn(xvj=)EHid=mV#9x)Hd!^$FcXCB5w3k{z|4j<@2(0aoz z1CC*9KN;#M<7cVylN^Qfm~CM*9x#Jvf4oK^Kd{$`RiX}TrdC{XCMgjHI)QOYKrB$H%lmSHC8f`uW= zv<+kMC+lSWk2K${(`3-!N-u3Xm|Y5V1%Df1X!>xXAZc%6h} zNUu`D>!IdYz6eE()B$Ec)oL8g<%9f3K|ubo;y!5Wi#Aycl|N3N(YB2a@534&dz6Fo zOG@WQIEsxKN42~rPN-lXcC$wu{BP#jU8ChUgM+`#0ytyzb~DBY-oITq8M%rO@66%*5j`CpT67Z}6X_|J7w<8?n4VO%s z_jyy~9T?0%Z0^lI;bY9-nk#+O#)V#MSU0acI=h^a{z<^kT)E;VV!^Qk{#5PTP zRk5_KDO(msf1?DL7lUKpoZUv-MR_S);(XCfHwhZZZ zD;-}RF}<~g`-)>Qu+y>U8T5DC*T|dg0~c$1U4pdT{ghod^aH+7v`m6_T;e50ZL3(i z0ni2QJLs=F*bk!G4=6XVD~t?EUd)eIs09b9t@^wcF=Z*T_AO*VxwDX2b~An=)x+R} z^|=`B1JUPQiZEp#|LlCvwynTyI6_*~+o;B|ZOXSjuFM!yx;=SxwvX60-KTW>^XM)^ znCVd#vF%^3beAg~aW)MrpZFla^s`{yvO(LG=|J^fOeeW*Rpt$HsV8HTZCB~R9L^r^ zAY}>CkGxXiF)r7arj7DtiQTWTU$ajKeLLb^1sLn=YJQI!9P7$0)3u5t9qWg5#paem z=2aos3V?(Dex0UYWRI3-RN0g+-?*&pE7xmU#rR{q3ASRvU?I3o^9D_m`w?&Ao>t;o zlc$=L27@xbLDM*2+naqCPcR01RffI}_%bg+LlQf&_(vg)%zZuJm7eRB1}NPx-3S~! zLc%AHfssEnPvj=R?WcMg`=vca=7QHEou!`f5@GY?{1EkwGbq^jNsDa~pY2QnCU5px zT9&aEGRQb!Fy(n8;-BEP4(-8wW97`v4!;}GhuIc+0)=v>0NB*;+F*^zY0kG0Yv)JK zozwC0PP!@myQA(&ht*a%FUM!Q`i#$rKX|2|hC6skcRIe{ng3LN;7K!y4|rKKa6ia4 zdNb)_)E7c0{zl$L4RG9H0C;t4Tf%$I3SZ1-~Se&F1;CSAC1lzN{5 z&8t+_ux+vXp}fP$1hlH|Krak(u)yq)(a4wfEzwmtoDkQ`3$h?FXE+E2kmP&(O5l22er5$xyGH2eeAs%6omCz(|Ah zDm_sO&fLD_5Ng4CMhP z*x?=16L~&~8)?B8^&zck7Iq(q^_f#%nnNA^hu!K+U3f81Q zl_OZDQ^X0Z)Xmf$U~T`hb-V>W+8bgWaX3%jl4#-&I$vi#vnP6!ZA`Sp>5#SsE;5B? zj!zS7Xn^ZC$2+d@GuOvkpSKy`sV(!E=i{3@a0x;;G2+A-9-z~7tTt&L>BH*Sb~txSc1pz7Bz$+9cuRencw0w`?DMenS)6@WEILZ% zz{4sB3i)j?@}K~Qasl%p`wHf5xL>ti%T2zH*L3M`aEa}@Ob=k{Qk?1J`AQcWxWNt_ zrE5RQ_mj@JAs^{V7j}hi_`>|?dNP+hW(q8}jqQ07>IGT@A|JnwdU1VRY+dh!Q2sOg z{SiHhqy5wsJNYT(aGh|}gLoY;;A~xZnZ%{Ktq;Zz`BP`QFTj_&q%$o?>Onms&wM}X zetk-LF#6Psx`Crk!|+UJA_Ld5;?NyKrxEpBrS<$x_P=7zM$iF^pwI$l&FM`zI|zBg z>2yPgB=^_fMxNYX6h2FIy`*$H0mMd~aDViO#y?5dgx^IN@3*)14R(x-;h>i5FT%>a z-Sscwgmm)h?S+*Tnw}_)0y)8wG!?N1oCB9B}(NAvSeA7AqGW zlNLA^DF6=2^-C=mCjA#(u3r@?*W*sPDrZhzt}UpKiDSU`oLJD?A=-`Q!}(z$v?=F& zwBK*EoRM+wM)v&|+lId_Qr6!&WsQti-Z({R53*0SDNh&xFPfhxi|}*6;iq!$6x^Ub z$Pdq1*~iB#UOYd)FT&5$4nMD{n3^B98SnMTPuaNl0LICSuA@KX@pOicyFWTSm5o;- zkE!`$J#ACI;P323^YrIDo~$f5==$3IzZNOi z-<)#2X7<$OItgnM%1oZk;NBzKHJlt7>Vctu$W03`6L`aZsQdKwDEv{$AG$H4=4|Lg z2v>XdNm1NCd;THd3%v=BjwS7%0Jp^A)Dt7~`~~1kz2>3ZW|Q`>5pIaJjN0%M2)CSz za01T6mF6kHBI6y8;r3GY2TbP~f$cbelXD;TCxQL;Pc%nE`9!*B0V^AS21Z7FLv;fG zyTJbnTSw{K0PnbzISBE%toT({IXzbPjy ze2M=4W3bo2RNWNcj149?TCMTcy11SRVa*-j8saVSj<}-DniOmA01ub(Tt(Y`64u=z zTtj<(XDhZ$qBe*z!ZkMbA^}ZPye*!J$(@m|zXM#N&2HXhFNw8wfHOaNg@KK%Nf-N+ z0N-l%A*--Hw)Y5SHD({;6X6ztI}tyO24@{E)4E#a*Hr=zW2}2bb8dz+nxT=NY_AWM zep?~yQugNxlb1z{PesYig&@CR@6(1YIkuisVw;D+&;YDK1B-Y9^PT&$Z?WD=4O~2E znmQJ`dYpX3cz505?6b=aEz(SMY{zz^F%B=j^>M9Zlc(VPdKDNBIO@4!Z)*aZ@P6HC z5;gf(nl$0kJ>Yewf!Qt~=~sne8S!GNWtf$RYfQzOBsIm)Hu$!7?M*y`n}adK`kra( z+jVUz)$IUK+s_`HUupK*C0^hg6GtO$4Ja0lBicK0@L=mS;?lr7V;idxry{1lo%nEY zo=7QDc`b9}*2SBUgB~lfMNC_kyEGP!41_|{nc>nvMp-hKroyEO<%Q-*LIf4jsZJx7SnlusvRVsd7XB_@4 zS(me2e0>W}#&BS_1tVJy#tc7mT$W#zh&L3ezr$QwlLu9`TUu}`=F0CSE?q+$XNf_6hr2jd22jin zGPa=w6AbJ22$x3O{}%(Jaz?@l=av`G?1@2B{y}W^?O`VI#URn=kZ19QgPmOSh^F6 z(xK9D?rP~yEJ}wr5b0)Vlaq?lP+B&nVhv_)dx=Y@b=HjO&*pV<2){0wX^tbR>9Z?c zT-uyl;}BTtG{4?gxwMcfX*ljh6HXv!d!FLbhSN<$5vZkoYtWvnU0RWE96Tww6*ux| zO$bkS+M#h}g`w2hT9;NjF???)TVjbeoGiA+IxqmGf2?!qlAU#MLfi~F=}TvpVZBSk zf!q??9+tX>zf)a0xk})jjGVdqYq$*|ns^E#3&)oE;@+fpT8OqS(b$O7(<1Z7MwfQO z`nrT1@N>#ff}S?Sf5qAvjW%G-;ERY4QxBz#d8V8x1K)5!}2a6IQJ$ zfY@~C6>>7(SOId|L8f?tgX<}CM!n6_J+WrXQjZKD0IW5wz~7SXK__q&F8x;~Xic0dWjjK!d* z2B@G9Edzh->sB`?D$Ew&|3^VzX#Y=rNa#~QA2QHEXIe%_GSD|U8u6>0a{`7J>Nx@H zjJoH`0kfYadQR{{^hUp}eJd)7bgStZ(+>!P_Ic0+WcO-t%Yln{dpm}5UHuwK+Lm$3 zyzaKK0l&wM+I~e`xz}wv*4T)=0)y7inAIsF9%lAKcsFi^*F6x+!NFnoST3u5j&Uk! zh%h;{mwGvr!`$Z|>pkdgvTq4o zY`rNQdYV4GzQ3z4s1`G?LO;{T>k9+xH-l%(~FNA$Utjh8LfYICtZ$KCB9lv^Y<{UgjiMbmY%XE-sj( zjz^mA9L2DmqxepObJPid*^iy0f|+*mcM?`_n(JWR!*TxQZ>w*>-}YQSTo2Qq%c5W| z;&tPZ!!Y%6W4*ofpu`U^BhSx1pU=Ngrc@IH7 z-c?RLRG2vlCq2n_)CDe%^Ohn7Fm~-}_X8}uU5DB`loiMuJx4E5sF!5!P}VwmmwA~2 zD_cy11)w(11zPu9@3Q|xk2T#1t{Y>WE!2M^4En2p`Ol`PaMs?|vR(F75$)Hff)CM% zOm`Z6NOo;%NZK$mWV!7AWKjFISzr5tRadb=eM28RbPrSR+{17@K~IUZFD{l$9O_Kq zox3kCtx)BHn)haGFKlBXF9pngYAXvW(O8BG?j8OflA$kHcK97rCkbB;Kz2-+ zxUGyZ>tri-MrFSgMIo?8_R~YJ_3xUAvvP%7x%61KK|68>Yh*tzCY;<*58Qe<_)4$O z#}m$d68B!4och!Cav-872&Y0Qv@p^ucAnrW#~6tphS>g52RXu!jJimJQ=VFkUpKeB4#0jf3EGq^&iUSl{OXkJ!W6!JsSg-a3MMPf1+H zr_7yNzhXq&nf!TtTfuc)eOJ$JedpaQc?Ce`p9bt|ufE&%YraW*UGOGR7A|&--59{l zq6K}_%J>e4*Ei{EE9lwNJFBvKi>&*p`tDZbx76z~bB@kKghjpGSfWzb#pvN}bNI4- zw@9DO1Dn3ewg~#BR4o35I(c57H}R;mNIg7jBk5(}!>+few`PCaa_+QaRQL_c>>YsB zR$+s~)^N_8E&%)l!a05&_=SL6~6=8p)7Gz9zAs?3YT9nVs;X*=-1m>wG`Viq|puwJy(G|zZ4%bXAnQgdB_wQOu zLFbJJbWr}!bl@zzz0=%#mW>}eg!2PG9mU~|L0WWhxG%sEmVH4FcrzUPCKGHtuy1rZ ziXa}4jWH`F(}8@3*X?AhbRpu_tYg_|`#VR(lI|yTQ*U zuVXhHdHa2=AFviL*ozJ#yu;fDL)nR3cEGHenBGMJEF|aWqP>O?$9{Ts^yCRnTl0Bf zQ}S?vsQ>ZK2S_%P89R+W9 zjeQ@^WrgIBF0^oO)7px?kQKoNz&72$P8Bwt2R{?YWX7R7h84bIV}^1WvNVjt6Dc%o zlfCPvt)@_1sA^ao?J$LKsdy_4q4;;{w3igZqn)V_lrcHT9t`J+VHy$S=B*&l0oY&n zp{~sg<`+Q@c|s9U1v_=D?~%5Fb=v`$bVHljaWuQc+_zx&E3mzwt1htzi)y7otazC? zf{!TPjZ-RH387@#LRZ$hbC-@y374CATo76w1U@639of^@W6$vgR*~L6(9J{Qpx+9- z(xl}zG zyww+_0P@K-8Tot#_{13k38+SD4i0Pxe7@0t@45x&3sCCVZuvsEt+U0RZ$vzV6KiD* zmCEn+^1F<`Q|5QM{N5<=8T?(pU4B>aHx#bo%5NpZbG;hZ)t}(FyX@)hH^`q$8?(i5rjeC$cB$(n9odO zsZ>ncW+`Fy2EcxG6vKSAiX*>7TObdQCcGudik3dT%!IcRz<9L`Loo(VTqS%g!&vXQ z`5#AErv)0mHxWin6)uLgEHT2MCQ_&2I);%^Jk}~{*PC!V)J1(guZDmIN+J4yR_h^d z=>v?Ep^MpGe8-C9lq*w~L-Uv(K!$nA!>bnhdfq+D zxQ!z0)W5fhakf({$;gUvZyXRbBz0j-T}H5P04&kMr?fiOB`<|=+OhMRz^N;#bI}Tn z-}O3vUy1RHZXR#zY{l5sUn*bR^9j5Dq};LVZL9xqwa87b%gj7<4Z^NXD2A;~D6Xd{ zYC1>Jnb2+PZ zaqHGXABh^V&?44;1s(Zz=smgdsp*o6rHtIexpo+jZr0w`B&zs{CJt272l4hKOb7K! zX!qbD1YR-A6@=+$W#hc_&!dHEVm(g4>pG1}vgJKxJ3Mx(=e8rXR{JXA=iy8r55p5} z+V@$86a*+A7&Mr-xKP(^>ae<>2EPT5(%I4VwXRZ-ml974!~P9kwq?wIhPXqLcA^EE zW6kXtmt3krudSs;=%}HaPMjY%eB)?p+MA8!tDm3g>2q+2g4 zZ8mMG6DdPR+BsBL1}^$&2F`Xz9U6EeR3S0x7@GrT?7MZ63F9FoI-tJ?y{#m)-to)I zdG-N6O>X`(t?ja&p`MraH|#6?I=}<_b2A;ynC&uBNvuz=OzM})+0s%rZ3BlE>SlIT zc0Uhi%N2`Y(OlLD*JCWDvcvs2wuX;}k>=hJth_MndhkrOZxGrXTh~v9#*i|5;5Hri zGq5fee#Q^!nh3Ls^Jc=cYbz+<#&ym@qxy9b;HlKi-aykEMnAN~kBd18TDfum&4tYh zj~<}PX~$NnOAosamcGn~!$yF{AkR;h+H_pr%sUn05BPXaxWcu}0oBLbcm|FbvR<_B zzF&_z#yU)i%rZ;^e*G=g`g^axUhLSOPR8q@FX_)^C7!}K|3V$qwsFM5ts@-|_jWZBAnnCU9gQ*=I_VR2@fmNm?A=tJC_a-DgTDW74^6wmxd={P4@ z+lNK=>r!cA@XqM`LU`wckPvv`IsKcE*9znbaVWNa@GF9#^VwtUYiDv^r~lK$U!`-> zn~{bmdS0SR(Pwp*-U9fz7ue_KUKxo;ZV`Hu1H0AX!P3kWra;A)<%V7F%o0bsZ<<#3uqRf-os0dxCiDlF>^ETK+w(RM~vLH@1|0C*P;6H{&}~3FC{qh zEI@R(?c0V@)xj1#|0A0;?zR7d04 zcTpx@ER#%Zi?^gre)b)d#nrdBU{zw$v~QmT*KTaY*mq8bp5ht&VfV%MvhSM&r{%VN z)t249aS|H5bU{a##{;&X+4oHWo@*4TKFPzrZ8G_z)^rTmw@d<0m@!PA?E58w%Pj@# zH`CFcx3{rxm`uLhs*ubcY?}J8ZbXI88hdMyAXyh*;x00(SarGeSl$IYCUkt-10%dX7dhdgr|3AzWESf)qo8R5Bsot z0mB=&EL0)0ehNB2eGIrI-esA_OkZYSCYxb8Jg?)r;N!sA&n8<#SlZUO1!c# zuEVZj%R_J|?`wHygy8KRc=Q7sKf#*pep5y=gSX-48LvFJbs;D%eM6YKPH#_B(QM5I zk!K~IhGEZ#_=tqD8rL?!ZNH)4upT~jf_u=Q)0%x9rpQ%?IyXOx{#vk(cgb zk)E&;&xi5Ek^$wzhoi{^EcI6!(6hBT7=<2s{xMH?DR!4ah0x$dj(?X@0E|S?o~#p|iBRtH_xZ?|zpcI22N3=u{sP$- z@xDYF(0*BIi`iuTiqbu#bXKM^zbM8+Sf-bH4=erGls?EazNjJ5=<8a#P_)v)qrn6Eh4Ao0r0eD#p5tbCKhpevtogh3B>ZYRZaqDwaei7X z4$8=ScH{h9f!$*EQ#a28 zn$A-`txYHBOHV5sP|3)*7#B)GYg;HbREGIIUmO*m7?Y)+)x{Z%*a8=YVv!{=)n#mY-Lu>dq~nHDk* z+Gdf)ErdJF#|3>pEb}7X;hN47O6&Fu=1cmptS|GHYMi4q4t0Ocd@S#2a5{vw7c7wQ zVik`>d5UC}q-D;u z?+WGDT@%B%=fU^lY@h4hFQA{(Hn`QVc@SZo1M^jwtbMj>ivHv9@q z*SOyVZlU!-6R1^6I^O|q33O<}FT2cI`g_1FrLLy?JOkw{LBzt&Q^e}itD)WzgLVFRD{g~Ea%1iS6779 z0JabMWA?QbVT%E~9KJJxS5~GimH<9Zc#xIke#ji}3>4SKv%sU^q93 z*)yaHg>|-Z3O8w1DvX;8?vt$Fw&PKD>_NF#VLE1SVM8crFb_mLyPjEwK5F&_b{%Eb zY8RphvW+;e;vKrLKSmg3K5QLL&^03*yp41Xj^b`uuV-~EQ0~qa{X?T;%5!^wA}2fT z#kV*9y|6uwQk`8XmvGkCLhWR_NH-Bf|DXWn}q%T5FXa0{JR*~ z@DJgr+5>i^-@%rD2!~YL8~uI~#zC0_#WQ{A&?~|?v)kvJj=;9?TC`1=N?r@0Ulo9c z`j=V%2K8?CPYm<4jD9@!Vf{eeW3x7(PFZ#&HarX+GV?grjJ=k=?vbvM{VoFii9AMh zEpVFY^A1H|b}bJG4td{W`+2YqCr?$c^6*~N^!YQSPx>>C|Ne~cKuYi|=S<-7uFfn} z61aw*R}Uq-0B$xB)Chl!IfueB|32kGD-M|*aU3=IyAjVd0xV-CJ zeQ@rTXYeh4-@w>_^DI(i25?*(LA#GnA`fz(LVnJXw1LD2Iv_7@8lC(rwf_V&(bQ);0Uu_a-L2(~3LmNLrDJf6?$~W0yaaQ-z)=ru z8@3zHHN_Hx4b#7k)h{;f8pv**b5Qp$5$62`opW$6(xvmv-<4<12Oj&c^DZO`i1stN zm$Y+@vH4)s)a~rTv0?GE*$*v3l%E4!wb+aBRoo>G-w-dPpEG#^>@1jdu9^>C@$M{S z+l2fsRb5(F@0##vWTHMc;k6OGaT+o69p9$#?!LvT#}lwV;e2NmqwR0>I;YPCdsL>G zKUeb%#_bokhr%;F?gaz9IrG?}ZNT}{^9H&u)^mP_%e;ZUK_^^^aL>q)|0ZO%H`q0( zZwyFZ?F|g|W-!cQ*@IH34^Ah%)4~4HhbLP)n`lo9FOyNn!F&px@PLNOEwI2xGn`O@rAbVYtxSJ)hnN-pngh|DBGF3-*nU*~D_1`*mp8!n_@QjL`g+Y8{7wMh3ZOSvW$lB_L%C%CnDNJS z5n$DT$#%1DWT>mRr_1_m?E-FLS@=$f_JVmQ)D4{f(YL^py-CiZ-q?@aK4s?(BhLey z#O$A(H+DLC!2a`u{uzufbIu%ugF8d_?O<>gZ`UH`Tr7xZ&bZw+fgnF<aTOY~Jo^$j z&d9kOPhn`|VR>BkHxcl|wiy9W=9tVMXEvUUv%>x;Obq`lURW?8M1q_xU6ez*D_EtT zckuPv??j~UhXz!8_RV8`#77T(%hB$Z;>n%I}G|#iD%E(?fGtiEAx0q;D&jw z>xOx^9)!)AU=TKE?m@WB<9XUkwGLTM_yrF6$m9B=%nQ~RtShtT(3(J**^ZEFk#VQY zTraVZ#oN)2rQoi_o}H3ES59u~!L{|OzTTPpuJR5Y!VvH_?aX%NR;^x*(XNnHunW?Y z+mmGp2rVsH!=Itgs@`n(*sj_%f#{>4*>|q_6_BmU(N(VbkcZNeW%$n&zma?NXNKBM z2V)O3Wgy_~6hG9XGauskq16%QM^7ceC*rwzF^=Jxlp`lU_2|UB$NWTGEP?S;GEXTVUieKliypa}koVWuN2c9w9M4bCA2qYraB)nqLVB8dPGl55cm? z1e(qe#N`lLXy9-*@QnNJzSBQGkwYxdL32N7EQj-a4sj|kpLw3;a2$~50b|OBpVui3 z2~8W@0 zrl!0=@^VvV`ASPp!+(-|@3V6*pP2Gup@|}8+j|%JDK~4%i~Le#0HHKt$}>VWf0(56 zR;0t0tGX|?VPam;DF;9AhY+CL1=5gp}d)4m?vfljMDuu7CN&l#dn~ zj&9pGj`C9;(3FpwkTTo0v;>o<&_4X@MocY8A~Xi0LgV)5Wq!)zn)0#t)m@ZpQjyAz5;0sNbAEWE!$PL~Skr z#;J;cofIT&*hmawJJt^)3E5txF_ImCy}^J5+?I{1-B<#LGO6s?sKcV%-ig;@Ck`H? z=duEfZGx_s@Rf=6Tsqb_lHCOF=@Z!|ggn(sZPad9zZ%`trPJ7jikKLblG`LqZfZ}H zNjBiVk14K0iW7<)-`BIdYj9USTbia+6KhrMeX=aI{t=bW>1lulfzxd!Y&$Ik~cJ<|iS1tLP(@^JrpUZ2kbbmHG z?6e)90rV$^0tj*px~X4<1#ao2sZBQI0KQSuup`l*ZSTGqOJ}xwQDl4{E2-AHNJ?dM zBm2>0YfeL#lVUT$_7Q`Z`t+f(!Cu?etY_0$cxE&(+@H-!M-@;ii}MK<%8%II-;3kX zO>0+sRi~V`VMEmUtXX&Z#tmyuJ^l3c4iG=rtX{o=lDn7oy!syZaj2t9xauhp4G2;1aU*SX@HFp9@hPsgP*{`i5U@}kw% z7r9Fm!ntj@5H#IqFl5Bprs|35y#%=TgXU4CE0$gqh@XSz`7V=3 zSM~RGuP6rQ{^TJ38nIaE@=CZA^)5SO$LOBHfvElM5xFrIpbdb2w)pRCM{bnWRI z-H{s^8@yx(k_GIN9it;X{JmqS`{JD=+05R3!H|*$Jhkv-e@4h6{H`J5sUj;l2 zz@Js)UBrID1=q}d-|@d&dB{6Dv@;hyA$4N3eHfP~eV1W0M>(+i`m-b6UFB!jcs+Z2 zUnGBCPrrBm89U(Pv!P-0j?*@*UcG9~hIJcHUA1OMH%dyD`Pb9GD!wi5^$hfSD;s-X zWL50xIeqo2;ok1(%EqA=nM9%5L~`}fm5CRbA{*pI$9~Zfcf7cmFFaP?U{C)T1T10} zX=YID=*=Ik~2#YU7L=?*-Y!PNp_P)fjE zJ+w279vj|B2?gG+btdgE-YuNH8pOCaTetRX%qvW`tz*qLq$>d++B$@s_oD08@;?Bp z_pLs4HFHJ~76*c`QYGR9ZCJg|rk#O{6g&sU6$(5cwMl|dwQDgcXX-i=Ee-noHIq5p zj7CIlOtuSqZSwG&yfw6FoL0lt=B*8z<%J6r_EI2#myw2qeG{&1tzIidNv7ctz(;}k zp6JT+d(PO4h1WV=3PN_WxRP5xOj69 z{x_xguMvOg=*sqe_(NA~-w)vVr-7Z#tqqO1Ly?#1#xMiTGO#VA_6(Yj&@Ep+diCki zm3w>FOBM2aEt1ROioUn6ABi_k)|=74cI@pM8HAi%1$J9IrqSCvAVRiz=+fS*RU!G@ z<3VD*Na4D}N<7XVoKNn=wi&N!YhHnal&L)4FIT!ryxzlrgd{bYn1T3R-M>n6S@p#l&UyKG|}<`YA28~U-Z zR)trG7|k@$)0u{9s9|7J0u~Q_C78nFo@K^97?pHjY&+yokL^T`?aNUiD&|p-wM=6BlvIfI z!7n-vn^b-8ov4)dVQGHe4yk3+zBd)pe7|}eF3j0JJQbom$9lF}?88!_u@CqI|4r=0 zOv=756*AFbvXA-$T6Rp*+Bc^{Tfl!FI}hpX8&sh~Rfm1(*^=59s6lFu4?GGaCN+th zJe$s>p7NGzI)z>3tyJtZo#okvpW0uZ&9<<|JX@br`OG_6*_)oLtv zD+Q+IYtPo=6wdZ+t4!%f&k|1QNY4^Z=}8an&7|t4>z2+|b#ZrdHpS^WoU`(88cyfz zn3&4%oE?Kx`<}DXXmam!c8pEW|D2_so(HP$6M!b@LVK z+EU|cMA8}$+Xdrd;6BMiZMaxbFUtgCCR%G@TEyhrYdKQk1#Pw*4&=RvRKQpcbu=+XpFYFszVOzjGZ039A!PKH0v_O=8zTD04Am?GhN zLXeHA1SS~xoUpM<72%udqNNFogkqt@f_`*||4iB@3GHh^`UuWJWCZHff-pn{}dZ<>g@BEc=o@J=9iNxzW zQ}iIM5p8<&6|Y4nnBLi7hu-yYZNV_&MX-JS&fG~o!Ot}Z0}-yHYYv;Y0Ty;j!d50_ znMpb90-J>(vX~ESCQ1AZWy|=%w#?>vx#j>OalWH#%RxbB*X%2dG|S{*yBT$yjJIpb z-%o;|xEUF)yT1U6A`kv+fPN*=u;&K*PB2i}B5h3&R_gVc)^t5~U>Hfz88MUsRv61l zQh0I)Y0Q$c7ZMBuWi$~A_qwp($qFE_oWRCpBMkTm+!DiMJBYV4FGGA4h~XL~k>u8I zbEc6-Kw0HX1n%3BVREbC_y|BrjY5E$R#m8+8E=F8Vk`m-4r~M07T*eUENX)hhK6A5 zChZp(b}1xLEu4*s!Xc*E!^w|nGe$v~IQOgAjx^$Fe+LfpO~xoMaAMnw(cx6tI7pU# zoGkibxkX&1%hr$OKvf_L4m4qluB8!nL7M0lR!t&VtMC*ABt}($xU)@m!LZp9tAod5 zk>tdpOymq3H6&99873RC*8qd66@$m-=}q(_IgsG;sPod$w47o@SegTQF8%OEuPSNt7Q?@6yVLzMtA~8 zqq9$aP6|QG8)~GMgNX+lI5vmXIvBcD^EUDfgS&T209&|9K&!eGH(LzXWQ-}mD6SGv zzWV2P!Z`6Tj_cynbT`Wk>`obmautu`IczFv`30v=@cay$A^x7eJfK3$!8UJuvNLJy z`-veBc0T4d!>6l*>+CIwc6b%AIaT;LyQ^>A9PH@r=>e2)l^-#5XAk-i*vu`jbQ$I} z)2FjjWgX5K{3C=aA8pHnu}BM&+jOUkeL-anFDuf`?4t`1`V5i{Y3Nl0_$~l_l}`x2 z%9=4mqV-ovVFd#)k=cX_udF$dDd5D2a)TCKVEPNDigBK@Wes+pl{M6PA+ba_9DuJQ z0-n3&z4C!amCBljfhzDu2^v0?HPoVSNs8HA2FV019%eeQRH&@Ehg{fN$vDhfosc9h)8vV@*_9^D$5)-QxRt z`79(?p@^?*P3T}$%3;)G<|HN6yAcnTi|y*gX;&7Gi)#oNdH2a`dB4fUnza@_-wRl> zzEg}HlZNYB9x_^k-K;vca7Y(d8iqX#1=7h%`XCG4X$B9661$}7k&6)8i&V_*US>q! z?vNH-zq{Y|gNF z$gy`TaBP$$Tb9gR3TCznGi-FK$4Q?eFUwh&pq|cPX0WQCYB9#{NJ1$v3MYCX zeo~|YCCOV6p(W|W;D9d19Q#zbmldf&cAlHaioDtrKZ|TJ9xwQvou^S)L{!RB4N$Cc z+i>?PFRIw*xnTh~y?ZRzJG6ID;8lRL&r_z6QThmHO{HlWh#MF+PsPkQQ6hdY*+Jq~ z)?BMG>Unbmt1(TfcKpZAr#{{i#HVb!#!}`LU@Z*ZFSuVC#t-0qj)ySilY;a9yod)>^tZ|qCmo2Zz3GVd@5U;Da> zt3UW;?5&$W{hBZR^`VB>LeW6rtIDgMy8ioTuF5`N@$iqnd&|!~?+pU~+oo6E`PCE7 z@t(i6;_BCa;_jb%-lqhF1}McFZ~7NWT+S4+LKO^Lrn^tZVtmxxf3z@aIeK zxg2k(1pfFHSATQi%q@R=>T~mIKKO>zb)NTTf$v+lEPB;*m+w6D(dWkg_N~jI0P#72 zKYh=!UwK3Ct1meF_IvLC-S=kQ?Rmcw_`ff!KJVVX^ZMR)T=&h1i~jOEXr@NU&;G;- zx7~32nwQ_a`SRft{_p)5MW+e;GsoVyr0cC;JL~xJ{yBI4`(I!8yo&_h`NyX&edyG& ztMB{sA3k|_+ljCCyw?i++51m>^(7xU?N>KnUVGW%M(#JU#!R_r786&;I>}Pk%b@d0!RyhHD@B_}JTSygmK=;vawOmp?ex^9~C9Pk)=Y z{qc)8C0=vXJ^l3;y#nf}M?!*Bmz4eAGy8u%)4Srq``1_PIqlLPLWxA+&&L;^HGJ=t z`@a6;!{2`Mm2ZEgu>?|GQoH{X2Txh{rN$*YFFWvy*PYbod2bhbZ_TfdO8)nWCu-ZH zUtPC2^D^EM0@wxqF?}*fV5mprh z{?N<6H~yWfAHVmS_kHiQGdBKnJ1hYT{ED~7&iusiJ1RbP&$Z1tl{LJrS5^k z4aRnL$(b|uc0{i!IWY5A%hOjZIr~9KNP*vb+lk46-#+-OZ=HGN6Tdoeurxzu1Nj<-gxiAnf)h0 zj=e$P-Cg%QJm>NIO1u6!^3|*U_^um0?>>QVs{PnGC;sH!5B+lMKQHNu{QgAG`-Q*< z_EbfF{M!3&T3Pyw&(7a`0IK^ls>sj&!-voN@L?BzVBXEw?tABtj!#30OW-X#ue|xz zD<7=6^|POQ@@;Q?;#^Gi0)KPl)>nS@z!Rt5a`b)Uujuah5WIm1{Qh$nKKI(nj@SO^ z2V++s_m?{G`96VP_H6o1=R8*VrprIIzU!X7D?aFX-xBz|pTD~AodXA6=Y4Y4fhR8A z((QSF7x;JoeC73@+j-I{KfL?XN1cA>mZzZjHj8{7{?S)l^Z75-x3)HHd#3k>Phng% z3;gNZKm4yRe(0m=rSJIjoX;NhrNcdMNZ>VpzU9Fu4?Xv>3vT&WZqE#^u-_u^_rL$v z+e$8~IW&)>Uvern&b z|GIYNZ;!wfDDd)+emwcc`Za%i%UusXGT43mCdgrd@2P(56_0Pb{T~-?x_{sJr9XJw z^X?V+qu;;%ZBJKS+1qi%#*Mv8cAy{rK;YibzWR@kf3xqTm+$}H!|!|MV~~6Q75M9x z?0V#u)UqWT=9jW=tU=X=6C$&znA@|;lpowYWweB{}Ru;L*TVf{3`jU+xEZm zjlcR%de_UY`KIUnN#L)T^VTyGAAHlT+kZ3XEf3aw?E&byL$j{B+KqWD#uiGd%AkFJ4Yv{6WtJ$D7$lNy4)Vv zDVUn) zM|Tgy4fn>WIYiFgU8C7)5oT%ab{dpc-Dk2s!qSY64a1@3=!E!Rk8Jk+(P{j6%WeaKJ$$292Xz!lP zv?J&^#*2~Zj3qeX6xHNO1ul~u8|jBDyvcbbUC%BmTu+(Y-v2?2Qq|gwPCeL~Ms|I0 zXqVf2iJ^QUa@#7^T4nEPHM3LHBYU-x5K}Xy5_`?GDc4U;$=RoO z8lB9{QqvGQm@EeSry=bwfh~({|1<^M7pPfc=QO~_S*=h91Vc5*aLTBpoBHymD+|bm71Ec!}rkJhRzlOS| zH=W}>N`K$3=~PVj#nW4ep>C!w1&F4cbXg2^102&%qkTtvFTqSVWgldh$?oeJo?=oa zS>H4ogLBoiwg)K3=$>iR3+$a`dSH#o?hsi1VjC)SnQ67L>8z$rUdYTPZ#HByk*8Cc zJ$>1|8SHX~r?b()bJ9^ee*cF|C+|rj9&^3YQnekcqqW)Y;po};>Kl$SygvGp=!F6R zoB$ITHGz%5g1AL6t9rWAU3;>4m$(a$5(rNUoJ7DSyGFVOMj65Tf0YqSvrl+fiYoe&g-AK>WWG)H|Nk;<)KB`@q6nYc)E1m1Dh`RQW@?FsT#x6OPuw2 zIN!v*cko%JKZ)b#6*x@5`KQqGvBPEfTkTczKHC2<4rz|W-)T%iUsc{6KJ2|d3@7pu zW0v=T50fh2a{XB4HGj_?cGZ6m<>nt6n|-mjHovO8AN#PM`7rJIQ7^ab&{*_h@6g!N zLt{%0jV(MhR*eSnN5j)q7jL!W;({+Nl>wkuBaqfC{1qM?8-d|xsri~PI5?QrQ4LG3zED^qOB{bJ*fZpsLzxH!L^R+7OxM$TcVYX1;AV$%w z8us=T`0E?Y@ak96SfV5})42dNECgu~Hbjd6i~_J0i49?b?(Y&eLL7&ruSS1Wc}MxMR1_s=Kd`=#GgrSE!L5)KNY-q*F1o}^~3Ap(X)StE3>hs7nj@+k0u$> z?{OeGQb-Ps{m1k?bWqy`pPmm6%CC<{uPgP@7iM1eHS|o>j2Fe<49BubC&CnaGh|#G zEx$0Xpo~D+&G>J6@CSStM>PB9)%dfY`|yL^#O=#CX!b~piwy65_;c|GAc@KZYi#%2 zQ2=k{(gxu66~wc3jill&ZvI3Nl!wN|A#|`V={_d zsZ24FrP_uGbDTh%BPV0>nL~#T@d_TMhdE|yg-g#n2Ox%9HEhS!1sbkX{2mQAYj`{l z{~8U)6%UaqAC5_;&j#d&cr$m(82zY$%74~3$LIq5-6;@}Q{!xZSRxo_k2(|I>}|Nv z8()daQyA8uTOsyH0;qi7tSF z-Ri^c^66-wir6ae6F%(IKI|(#>}x*k2R`g4K8*SUCXc6l*x!8EKYdtr#L_L)UsbwB zduDZd-2+>;-f+bM5kx<|`}!+tue;zsXZ{=VXjwYF?(dCT(nd&J7k}=|FOOBMd*CTr z`?(>0AelBZ+r^mPLUY?S56rvf9+b_-s}-S?!xZ?O6+E@($J6(oe!p~+{g{_N3MGAP_F9Y8QUo-ANkAO^FA4mrqk(*ms}VBKCsE%XGK?Ff~`D&yeI)@ z`58Vv=i>d_l1Ruvz$nu7vwvzMhQ-B){4nUAF1-#?aqK@g#A_in4}_%VTtC^T&Ok&| z4FqNFbrpX6%!Lq?QI9iH6n`_=fz$+4FMb(8xfj3KnP+(8_;1AHjrc|JI>Y-0{<9$$ zdOyH_6XQwzGIW2(FB6xFDkjDX{4#=u6?--C-fD{d*|HWk2^=rWM$ytDwGPs;c?h`(de_0G&&nvf^PZN>M?t4Ya^BW}0$ z<#usMODpi_ zFHabet(4=RGR4Jd6k+~}$@B(@zF8t_UC~?%G}H1$^MOD#SA+gP2r}7jTEc-uoK^D( zAXE+PqMr_{pC@9K>lJ>i81FDae`(aMVJpVRG;GE6l^V8Unlg}|&B%>n`%x40Z2aG8 z*wX(=!uMKH-0s~ zFUR+__Bwsj)S-2`(OCJ72k*O{Z4#yQTc9s&%^h7@J%C(@5MK(>izg$hwr=b%|+#h@y#XW zNAMlP_r3V$_yJEcO&yCg%{0YdW}4!!D(~l@GO)+>SC#h%A9m1(J@3OxFlJ3$s-&5? zH9qVpAGX|wt@L4QeAwAOEat;#2g#&&o)5dghjsa|0Uvg$54*yLz0!x>;KOe6Vejx^ z@AhH$_^^9@*uy^Tn?4M305w)pjb7xHz~D6vNOLb(HO@g|oM@FG%)v#2vu2P*NQHQC z#;CMR<5DM$^1L)=6iA~&)2MXPD0R}P^5Kzc{+e2l$x+oJ%Li~l8!sh~wSH!V9`3Y&b8ctkL zz{4U<%eD`NIsXEKz!C2-(x85pC~XnPj`9FPUXSo)koacpG_N8;z##77cs zHQd9sYQaI8OY_Qe6vFxCIhr&m&oZU0^2+D0K-HT*tG`RwC(Q4oBXj_79G@&l94KE8 z4eqiIER1356#`FYM@IWbb1)ZZjb9&Q;6_aW{fx${(Jv#l0yphl=AAV*IM_9i?Oh3d z;g@=yp`a<7b-Y48@v6r+Ab+f+Gm7J*8FctE<2Z!#)9WaZ-j}pICcQ1>duULN)Gw4Y zXmQV!Z85@lT!kx?!Li|{k)g3+13w(_*&(>GMpxg}-`|aE8CwUe|7tGmw0&p%?4PQGWwj)7=ZrKob`Q4%R#R261IG&wc_7wf*Pr(jH!cqbE&KD08R3(37x6kf#Ox})IT>8So&ULw_N zH2!hO-!9R}1MAZL=A#oH{g5{lhcjt=BYc87S)lx)N`L((&|{WqnnsPlypr zG=cVS#HAAy`YGt@Z|>Wrjta<2Wu5_Z!e%Q>DAf==dB;=WA$dZf{lN5%-C}`}{e|^4 z18sUbc(R{`q1O=;>#K-7D)f}4v(Uq(O)6K<)OxT^5zj)Hb;`fh_$}>^GSH#c*`!4s zzf|MQKs%9N(y;s$_}ip3F{QEXz%sk-P_J|iN@w#Y9ov>|Odf(bcvYuynlz3pznOo) zN5o4g?YRYL?Oe>fDlikaC@qhi*(Y2lz~q5+Oy7QU!5;8c;k9dg9t1IdVaJ|%Z+AMw zVcQ-lP2&jdmu9_yd+VKjyR6qlrjMmpqyx0}lP~`Y$)Yrmk%s++OG5nINkdplBRjj!_C7Hn%y*ayu^>;bPr98vXHTOZrq0u(Z~3b9&_C(c!)eRj z7no;TsGRwApPyepY#NVs?aF5QdUftG<0z;f_5p~q$WDik>S>gHeu$6$?4E4Dv>oNr zZYQnj$R*o9O@E@^Xm%vG-;@5%^e%pZ>0KD&?UL;NOnyCa;h7mS9!P>dS!w#DMHuHR z=;7K|GyU1YT{)})Y@PKxd`+j$!t2?-z=N#vXUF59lkRlt&&n86e}U*Wy&)(cWG$Ta zh5JIKH#`LIidsd1j2U)#n9f)T&sP)EWIK*HX-=nH*0E8PV#YeG>!7$XWg`54b!5jn zr@YBIyj4!4|6dDdp>|wD2Kr6~3F|~!Ww`Nl=WN2a2psLR)5y!M64nV*%d}l!;d$}` zfnlDA?-QAtk#G#UT>-31(}Hf(2;~d&>k(L3?qvlQ$RX105*QSOdPe$&b3yz*g~OYT z#R>0m134^xxZfQy4-KX!y8`!g7OTCO3%!{s2LxEn?arVcI@xb#cYX_S7{z=!r` zM>2{q<5A$KTXmGl_QN7HvIlVcS(5)wy1-g%sx@ACe}RjAr0?!axGqcsX4ixaNAVY4 z8&-Okf#!$mSQfTv#6VBTd=c7;POv6eFH(3x<3)-qXuC*p6HFH=98P0}2fQPOkp|yc ztiTFbGZNm4nljQf3tKWWvsxtSEYN!M?K~kJI-g%a*@1Sy9POO{vKbClake4#ZQeR#N&G!HjyF!vtW6GM z(-cp->ziprMENUfq(t$>Y?LtVV)jXho7^^uX_u)ilQ5k^R!In-+#-ode=2(E%kQ7yaOG1RxHAOs>p#WRSp!gfMDc70Sx5=)~w_MHW^?( z%Noxz`8vkCq`!%YuE26v08`6WOefD|m(Yalb!mOW2vf*h7vqLZbtzrgBA4MS&!Cp% zF;k3e#kNt7(HZJ2t(S4si)$@n>v|`I@}J>5U#CH@Dw=HJMQ`oYY z!A)*g%+M6HDi-wTfG@|WnD*-cXUwgrK{1mq`gnkEHGLTNP363ubNs8d5Bo%Lna*D9 zhf#~HD|^SX%CD=0Yt2&Y2##@jvc1-7495%C6A^94*P6U6T6R5>n+pkzn~+IG%_C$_ zQD75{DQdmBwiH=c1uZ7}b!^fVgNQJ0))wqAuElOrwnVUZ(Fl~bK! z5Doo~`Q@2Y6j;73MbZ_tqo{lpHKVBb*~ZLbTRV)V)4DqA8(JkIw_j)K+qLZ@)$IUe zjLfeza(Yrj=9*tIJLW7$Q5)tOcM22cQa|OMvBo9lvaRuQR4-OKF}seO)W*5yH7yh8 zN;|cMbJL#Fux~D9nAEtr<~f;dbJnFbM=kYG-vW;USnO?qsX%ckVECEB_POvf9mD6$ zZz`kbq_L)_g{KJy&kawLnmgCB&v)C{SVOlhEIdzQ4PEe)nnKq+3R^-qJWkUNy5u#r z5p|vKG6;HxEp>Gt~&`oI~UF&KJ3+Yl1#jKx` z_o9~1HT}s9pEG`Oqvxg^MJ<_Y`qMIGuC!CwF_*F)>(+05d;8`DteQf;Vu#hXxsBE( z4PR3lJJ&p?v~{j@Q<^$gx)Y1?2i=f#v&>m16{Vq2ZA!%&%-r@8moC{3GqBq;&6xhI ztUWn|Uzf}@#}PFpd8~ACY2)4l8wjbdRJ=Y8Gnx%Ho#|RYzB5wC!Kw1#o(OwD5=nukY{b8%S8Y zjOHA#)WNGW#DGG_LzzPZ&!e&aTtLFMD0lF1?l=KIBaCkd4vkGcRXBKFYmN-{cj%?9 zjDt!CkNlH7;7!U6gek*J2ao(G;Hw-w;v);^VqD8O%b`IU1!-nGG~&F}=mHCma~xb^ zurJp~ogAE3vwr3}xO5g?`10y+o`YxojgAiW^x-DDH>hSwr`n-|bJaoKX)yg72Ywz; z%l&vLZH|^#3?K9J=?wpg;8MxZEpX^qUt=R9xSBLLWh?1HW}?AhgSHc zQnQv}v4cYf#Ap+nG9KpO*~a?p6x9DGopjnqzP8yo0`_e4`4(J);*ZiLK> zHWXs4KPP>1d6*_?FGfr#J=h<%{fTwuJ6W2f8lC6%g-* zc%NA24fG8<;Yx(z6Vk`e_6EBKhl2b6Y7bA%Gv;oex+1(=dn59K;Zx zXmt|hH*^v|7~-$b3cbvrsYL&tw#@75&yAX4Vv#Jzn~;Acjo9wYzywXkT#KTOhIo*`IWIR0LM zw5V6KR?ic{J`PMD!u?U&QS_qQi1s!(!Qk8!(SC3n(vcg9bf?;0)f);MM)tS)XBO~8 z)znf4GxhcHWZ=gzu6-6~Jo)&BcI>Q;we&cSFgsxC-S9RAt@Ll42~C<_tZh3Ua8-z| z0?%UJjPw@`nhdhyHYJI3Szs>{0*uFCuq|5f0=nKa7YbQ?g=K4M7IEZz7Kq&zmk9+8O*BChQQ|={d++;28zR_ z-ge6u!fo`8Ve7*<4q}}_qX15X*30-Qj3LLM@Ix_X!<#z>t^BPRk3Y-p^ zw8Jik46KTAuxGY+#j_X|OYR0gn_(D9PsDH)qHQ^cFuVOz*j&QkejTX09Z~;Gu8NA%pu-=w1ESCOF84hO{8@Y66 zi(iH#2us33zVdSJu2Uz5k0l=0L~j1aN!k`@_})Yqee=<0h_-2rFgR$e({LTb$T=Qsm3po>;dXeK z@nv2^Km$J_>SI&O9k=uWM#|7gIP=M)Zz8uVC#DQrSiqlyx6+WbW+3t|*-8KX7CK77s>Lw#Yn; z0oa7;xh2+=My<#iLF$R~uZvr^7JJ-O{JhQtJZzf!!M#hECef0CL-SNDW#kL)1H*VU zCp>eAU_F32+=L@#KK$EWIH;!<~Po@U|yOXDa@YYk64bmE$@NXAK&Mw z=@W>bhckUC45trZfwK%L2r3LJbWyn*Y>Bru!S|No-Qc&tGb}rl-X1Cid4UfrQyBIm z_)OZCsjss#VzJ5mR>P1xrJbo7O}#+%_{#YD-M{ zfQEYrA8!tDm3g>2q+2geTW#7>CsKxtw6lS84Ticha5>}9c5vawQ(2pFRMX(pnZ^s_ zaXZuzOThDVGO4b?RIacO_<7NXK&G`l%^4ykCt=cdQKuYmU~_J!qZzXbd?=ujSl3>e z)GrVGrKM~=8#vch?CNYo?_e9oGG2ztn&HD3OOv_=*}8r*G=|i(2WQy(>hVLm-hjjw zH4{^3o^^Z&cRX>O573ZpK94?LeDct{7Sw-Cx%{;dCxKK9UV3f&*sSDk+8&a3JcX>1SovhabKAw}Aa4qdoeY}ll;D{k>F?;v?QM1NT zBD2KNfYce+VoO28z07<4wU|07tPkdi5>H{A+v3~&IXPnCd1v<%-5Hv(n(xezWh>~& zQ2XQzo4%O>F>O725I&R^;a!XLn~$6F8Rks!%x{$LHebi@yv{guL*m<#3H9hDD=y|8 z@eGdBb*8;BgN}>2Qf`l>KbI%-pf3XX2+k{uW<^pa-EZSQymkA9qriQ1Wr zC40XsxRzL3QzsW>CZ4_56�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%0AAsWA?k0u~ce;XczQJrC;)FZ~e&|Kz1K@`;zc zH-dJkr_|F9gGlI2-mVwa#M=u0?@wP=obKdh_`J#cnNHr%0jV|rqLcS+m{s!9q>`5= zmAneax6*C<600o#d?U zRFc!AlANZ1#e`P4FSW_NvVcp?^~!?p%*ujqV^$W-n=Q)4wXy(9HdkhK%*6axzcnA7 z`shbVeVWI09@IG`3+{KkvF@$5fU<(=uMt#Hp*2tTt5P$&ilDw7j~{oe%;QpYXxD#g ztO}Ggp)SPtGQ5MOvva)QPQ;ht8*H71ucERN{|4_`yyiJu8|V@rZ$I%=g%+O--SiV# zsc<%#kFnpF>HN)raTb5^#L|@_*a18n3_(xPXP8*5&cy4toFVR|WU*SnXdAeaxRVPT zx*dD=n=W8;n9o}otdkGPY*oKb6;8F$u8{y%=d)WGfJ~H+@v4fOCRK6M z6p$sYoYqO_5(#O;=`ncm;%ZUGz2vJ3}mftn@s^FZ;}3XGclD^$7#--P~O% zd>X4M2E#g=Sv@tjS?(z1DYB$nmAH%Wugc@)Fm1y-Smxy8m&e<|!*XiM3(F(*0C8jR zo}tZdx+#xyK`Zyrx4FvWF`$Kf=}vj z1K?Od=D`7gOw7;ms&Y(|D#tXba?CD*D#tVhtZL+};;Yl904EMK4pRwYQj3ih-#Qz2 zuFZFWjl0Fh-EQNgY+nWM;*{Wl&dR(`$YvL2y@=$!H793S9c50ByDB;aOP%&PGn8;B zde(cOXN~%H$M!)$4mvY~IQF)I`wDMNZ+rN_dz%xm3`MJhZ)ri-_mqhI7U?koGO zY1D$B!;q$4&A~9yZ%QI>-&2o0uh~U&sL&`b<+7Oni!=v(@1i-ll*GUJFj&XN=#P-+ z|4Prl(I=)k@wTR$=EPU{H+D#3+EKf(iFQ6-J{2hKOwVHhM*_|V%mKvt53&$$0U%qI z)qvC{HGua3)&V{WxCrnGz$U{RO}!fUg491HK2i6p%8v43M=wHodnq503|A zzI=~YwJm5;Z3~(L*5B~`L2&%1DZrUqv5{`Eov--Lw{g@R3U{rIyV1sRAdl2^ivxLz zZ;Oq?Ag0D)_)+t{W8<9mhX3fkd&R2nPJnnTR;M9AW9clF{|^q+>|l*UvA2&-YihxhYw{q zzPO>fxmoWo91S!dQ&wlIU+W{V+QXtDjU-^2FbFJc`FQ!90O4oVehT0LfTsc;0eBkV ze84q;b%1LDnU?DSMTsHJRn=_4q^f3`0$jPn2@>GgDOR`>ZQQ9gj)g_>v9Ktai;xM?7%sMq5Ml zUyy6Fz`!GQV<3$5m!jIxtOw^8<*ts_wVJ}jCDL3dM(K~@T{yeCJ}TowUU4l|!MFYb z7u7;BRu)Wu^Dw?%c|8mAM|s@@NO?UMkn(ySUfb#$^1Y7`k5g_F?8F{MYl_n*x zGzGX`RjBE5ZkfVW*|=l0DPVExRoRW&xSf&LoGy!GI3U{b)T5vDS@X`oHScDmKP4Mo zra(dW>x{0)p_qpu;IZPXb~k1L?>|Bs0fp)-g$Dw8#z2{z<}rhHM%8(HT!z<8H!8Ub zjxbyJ#M0FtRq_pZy{l*GC&jl3uXl{oIVk3*D`TG(j(%MvYBfIW68Wl0hSMu{S3-;^ zcGm(@?5+c(*xdkF19%hQGQgVw8NXWqDR$`)6(x2wDY2s|Ak%~j$9B8I4b-M|snQf~ ztc@FI^Zkd#ZUzGW|AyE(C-3~v6uUbhMijey04a9&0#fYm1EknJ2uQKx$*>f=hXE;e z84wjEb~Gumqe+RK!cpuLj$)^9Y)L5`#ZKWUb_(|&7Q1`|{QnKHbI!^7pDA{aL5wJN zPXbcxwgOV@o(81YJqJj!dmfNt_d7s}-4KY15<8ld*wLiKPT?qa3P-V1IEtOZQS20s zVyAFBBX*^}l`Lx1;T=z5j~?n;j*q@G5Gy87_V|CR2(k{QN1l!kTZ6tGAI3I*$7eXGo+hYYjn0WcK3}?P z^f?MA-*$ZI6H}`gFQ3;Tvy}0-0V(5u1f-1r8IbAy4q!9jdw{C|-v?wmegH^W-yP|# zWSu4@>of%{&JQYFjWz|OE2MC(Hg3Jmcb1L&uaxyEh{gXuWjzh)z7W&ImK%KF~`DeK8)g)CMD}M z1*`@5DqO8Lsg9Duv7@B;DC-JGSywob^=)w8oEhJiI(hRaD?#rF_FMC9|AFT`0NTK{ z*W?uHQNS7XUvLDnib8SH7hz~*1&bUV(iuNevRAW_Ek1v`*O#) z&@s+-jKyoV?G`;^R&>Iw=%`uI!E3f94P5uYKV5Eb-_K#*%P|gijD2k*#`<}X!p1@b zXXhT)k7Mv+R2g4Y7gD!OM7pL}hr@Is-V`}@{6;Zx)}8}Cs+anN;8;C8D<&q$rD8f4 z-)qEl1-`F~=~jF>nwui0DKNKEEY2=+6g5S7Hi?P3`iPjA+xLrU512TxlEO{bvPvUG zLdo1pu{hRG9gXuT@nu&(MV4@~6@uCwU%HfHor*8}W+~jABeI-gaR_UI;5b(_Mod@Y zyRVoy20T_wH{y$p-mrTMz6?c*+{SUBnC`}RyqGvHe1Mo9!k4m~Vr|BEe=%{act0^E zA>`lS&BkkZ0o?dwkT#7mrlYthR#xCA|`nd6TKW0Ct&c%KHUvg4)OdS?D;>) z^FP(|KgIJu+4Db1&VpmweS_wNEB3NolG<<(-h#G9xzQF!3)o`_%pdbGJ%{0EDqiL) zpH65~rZJYKwg&(b0e9gq;O>CQfYSie0CNEQ0u}%c04xI>2v`BQHy{Tw_5oZ7I0aDS*=f&j36O@GQV1051SM67Ukh96*+`TtJr3e84*ZgMjw}&IDvh zngzH8@F>9N0gC`%222Nh3$P#HJAjPGkANcpIh495Aj`|{fP(?|0OXAPP(aoM!vIGD z4hE!D4*{gaX97+I90YhUU>4vEz>$Etfb=H}SOUn}=RiO%w4MOi1UL?G72pAYCjjmX zxCU@Pz;%G50nY{u0aEUd24wzb!>ra%(xlc;(iE^R29;VZT@K8lDZu0Pq~xc|@e0%d z0UnuWu|%hf-k~WVdzo0a(=FB;GzCOkv6QFtbTldNYFR8}pDwF4X$r`!8B2aTkNpuH z5Rij;m|E#_UK&jSIhcnUC*2y3FHHf_J7Wb$w`dAj)9|GhN*A3+Q^1;qFZEG6H|~om zU~Pg)rNQ~ygq`0A0an{&P|^~tuXY5i#0*ZK2HH6XoG=JF094i7A7G_rwBetc0bH<` zn9)b`(v9QEtKHy*CT=%UeB4OYZlt-~=;LxDVB-@rXzmBs=?_b6qV}i1&7xoo^B6&H*#ko0oMUh}>RbhEqX{2hRRT+mcV}|v$N*i{E7_a@}x*IAh zD^?EC1e=nkyJ&ky#I=`K9Ly=L3`J&^msN&zNZcqV3_L5^owj|DiF}zqOutm5&QS6o ze}-w^Tz`La@+u0eaw-ZD{k*c$ir}0I_}mrg_`SP!ufX3uce)mqhAVPP^MamKHE74p z;hy-6z`r*>dy)t7*-P^VtmHwX5LYE{+MK{VQszAqzuHk?^%>M3>SrYEpr_c>xY+1< zYX|Y81Ruh^+PD$Ct})6yCVsTStJ~!vX9pp!NY}({!P70)zK69nHdZgMt34oEz4!>L zGUivsZBOk#!-+bkp?YzvMfb;uJFPgfCuK+?ngV;{-|Jq5k9&{BxL3t+H#H)BbaSw{ z5o&5`P;uK8|7n&!hCS^v|(03Jx(32KS5EAixR$lKp&1l1C~eB#))I` zZ=NhGPO;0=m3W=M(-V{@q=KW<%nrO zH;gPsVNOMLKT*3g$#w^N5WH@`d2t*4R(2AssoKs#+K$%`JFIYreoWK+hj{p@i}~^~ z?jwZObj{C8SCnq(Go%?jbax^eihKK)*O`@Q@>E6$X4pFJNS7N~+70B{j@%ge%dd`B zPn5hL37#a2|C8+h6#1Vl|2c3kP5!4~@;`Y9qL`QqoOv=V2|!FZ23UQDWPyR<9|ylp zdNsqcU;Kj%GxD~;74~Lre=_Wwx@-XGtUs7`gw&OV+U`->E{pd{!v-S&=KyKe|Q=5Kh*QTEB;L!W6N!VRj0$fNQc|-O~F6YLe-rK z))LLf3j^I{+Uwpj&DWs$;?#*nxOXp7h|0CRASW*vL8X{i1X=e(J95(K@w*BC?l3lM zzmM<1@BCm@WL8dTesNF*p)`k$lOi9q<9DlebG)yNM~cdFkBa2xgjuoMX4u|Q<#MYzhx&(G zGAO^iuqs#{$q5zGHHOu}7xv*Ch$t^0)ceS$o&`x|$(r(6Sx6LjrWmr5; z`e02MPtop8(z=DRj1|4nRl07+s&(~Wq}mCmn*Z6>4z^QJHd5Mw>rFf5Puh<*aU-|7 zwNAN7KZjc-)o5(B#2kvO+g+q*X}b4pWVUgr`?K|N%Asl;?WgUngg;~TF__MYg33>B z?;fXb*09}dRkRa9n_%Umombbw45l9}XHzT;jD(|X4N2SOG~lLLxm*j@Sc~*xIqwTS z{4?OqbC~5@sEi1DilE77rHi9*$I-`~iKGzYpqvhC*e0m%_u2}iYsF5n!tMTMrO~_ZnFJtb?w7R_(FxDV8jWU z{&nJewszx~m^w8m`N;h406ob$i5o7dw(dsY)40^u78;PWyqyDDKRKRF;TS%MX5uE` z&6ClK{=tek<%IGuT+6xfa|3W$Sd`dMR}-zPji{?)?6Bc-1zvlg!^d_*w(RNW=>RG| z=feJ2tE6cK$|B_nBUgz(cZGKv*ZnHh3bP3Z;9Uhvc z?Q(X~30tc5OKtxOZU1*VPiPOz-SiP9Dh-KCuogNhM$T7Lw2`1CS}QA>qSX!BlIRZF zNwOAVah;u6ttOvHOSTrqoZqVs^l|*dm~{-@Z8z0gxI8BsZK+?_h9!GSSJBNh=+ISi zR*|Zc+26Vf@iR|ftJ_K!c}_`)S7ocbKNIPc$XdbDm10$4eneMk3?pd?U1<{xEzwO= z^_E3DecX8E-h@a&VKG`yLQitj^U5kqE36&+S*aq=l>2KCPg74LNY?Bru0I4lo-Qd4 zS47Y#Dl9E1qs+U09a+Cl%ZMXC36^OC-k@owO-cC^IYpS*#{U)RC<8ZXzVVP#jv7<; zuf@x-)6VrYcG^Pntd2Jcit$L#><3L|&+7K4bI zw$~Q$TheZliqlm;$_b`2#z9$PU7Er=tbTdhaGz^r<*Ur%?!CiOY!o5u+`jBx5C=N{sh`!i7x?Xo?*IHcK01v$l20x<5(`- z=^}asj%49=@*v521#UAfUL|br+NPvEhrf^Yn&y99^Sj%Wv2G_?f6%;K)lRn?bvjcn zcuqI8Ca)UPH~KhjHS{B5@*vrj2MiC#<8j^>2J@61w&^hzZy!FO4~Ulj9^2<{gKi#- zk;jyROB&DN3bT#TQ$?lQ@|7=^gUma!yjJM#j0@)=<}RtmWClkw;- zKR?%YztDD>*J?c08JphWqS0^nxb@eXM*sin;xl8q98+=JRBZ-RKG+6lyW5ekMC)7p zyW`C8(@#Q&FUk5o9v{-j&G!!vAJdTS4R0F$6L=G@Z(xpX!z9X9TQfhvegWF4>atnL z2KzP%$mc{1!kfoCUgtMYIZDeQ^%1T-$8epapOPSZi?rMDJu%7Uc3LmSI0m6j&GrQP ziRjIl;RQAoBD2aWilhyXexjF#YC+N1fAH7?O=&x}^L3xm%Y&x9vd=z-$3AFmqA7ZE zS9)1hv7%v(o7XOAoYhzK)UNb!MTw%Z@8a=S^;S_H4?-J?}PCbgXNA<1EO|7`}K>X+<{svb>wR~|M82vPD3NAIvp!~IP%vrVT`n&ue zj+BZw_wbsQvji)YQyvatbq6}Bg;?WJcubHwkaCi!X$9qlLClEEHTXUn9}ebKmKRpc zjZ~J)SRd^qXIpm{U<%9*jV0 zWZWPp53{8+P5vcVhJFkNG%$)BR7+tDJ<+B!^_1?Sb)|ERU7>|b3kwPiEy=crhEjgn z>_~YqTv1*q0S@bYNp^UGxn+5gP+6!lRFYGgGczb6Mn6()p4{N9oT|dI^04@wYUA?@ z!#TN_+AArFgv!e*%JQ)ENXbN+&BI(NE|HiABlsyoh)TtszBZ4M{9McwsyxL;TAg+# z@M>95aE?rI7aM=lZN4g$wfvllV5Ag5ok;_W5#!O%=CR$vh+dH4C@#yvl1uRPw|Ou? zguyCTQb_q2VAD-RW8*T=rq8OtBBV;lc4-bWEtC@u&n_#^kLaW_d7EMLhjR*okz8a{ zMVS&42~Va?$ADHOoP%L0h8d*;leb#F2iZI`gB6Tz1Om>%%Ak}|h_MuQdpv6wo4+C_ zHy1ONx#eZE!;~78XM=5eI9yygN5V10#+kg<$;%~MVT^y~E1B4}3tw??W=`H*j`D?& z>|qub9qyqvF9s?wBaIZt3@0WhF*RLLsocX_9-aSlN{X4JI*hy7coUwAU~ws;Z?Z-6 z?QZiG1cN$^d)T;K$|3rFp-Qn>5~?ueVz|u%MO)6`bBLF1*wi5-v>wRRdO-S(@LPwp zxG-Fy^??tCdI9wzWesg63}ohnE4Tzuhc|(^JZRryCI5;1FA3*Ce!%6zX$0NrBRn}V zJg8S8E*1IWv`+72;tE2xkF<;PcEC56j@xxjs<;=Lt%707F~bp>?G8s@;meuB{N&g- z)^&(}+y&_ZWk@G6Qd)(yaQz|vhuUqiyuuI*L{X%m65caBh(B;Sd3g{O41|{!qPIpo z(gFC=;A~8Sqq3kFMW6%1$S^6FNCVKziu2>pksh?qqR0t_VrW5e7ij`~MR_F#mf>z; z0qSbK46!5xZCqLrDJg{1qHu^mNH6dQ=V1Lru($vkbtb|P)awZ@|ngZ2i)1DS*yxv11N9%&kjk5m>$Lcwwg1d2`p(i!9RlFmaYe+XWF zailP>sTNl^wPMz%Au?gYgozZuI3(nNTEk;?naf0u6)}C(0!;TGEJ+`EDEwrbZa>|o z3rSmj$?W>Zik3DE*s$M6T#~gUZ_(nC#VwO3$y`Sw!n_;onx{8ycGLf0|CX=Qk4d!l zU^vjm9InG-`beYT0q5tKQRoQe?bsqO5g?U?yL_91DHd=5Xx|1|$7&Cj`NwokdX zH{M)0IuoXIp$flR=i-A#ilW?bu44?`r~g@K@0fP0>H|4_>1^;|ZCl-Q4{PlsMs;>I%>L z)Skl=PsY)y_GU6=+z0LC{lV~?@k(m9Hlw`#mhmz^%Sm1|S zvznrMJ>EF{=jRl+n*Ry-FFp$Yyf#$xOa?Boz2Z&G+({pW?i?hzdE4NvjXP9uAAC`^ zqQS-;0bEl1XTMIuv1AS0Mxfoy75rZx!u(NmIdGJn0q`adc=IH+pY(K+v zGTRJhEmoX4R89q9Tqab83LH&P&k|7|igC99VPV_I%rj<5z+&fO-1A{G87I`~tu-z6 z&C#Y7)*Vc%An<9fIW7M8({oykH^^TUHoFT=%^A?Yxjr<`6OeXn7n-wHZGIP;GanY|LUZPjt9@u@eM3zbnllet=R-5| zhl{(=oHVQNLUYyvF6%;b(sQ{F&8!J*vT5xeAKa~trE{PeL_=&-ER{0_}oTe7+f%}M(ceP|}_Pwql<)`*(78&AbI25Kg>9+ z1-@4DB^G}=@Jo=k)w1SI<;8m78Z75jA=*C^xMr0HwqIuf7qy&22FZ6eaI3Jlx2<)F z&37JfCt>}4lkJVliwl5nC*JW&%ET{#U+ap0K@0X3yVh1-0{VK=yBrCt+`R(yvm~x9 zP0e*J(bZaBt^|IQbwZ>dQXg3rsf%#k5&O5<&<|IEWlQlZ3 zu(qKtyreB!+qAOL=%a$BmYTX+8w=TT>!NGmAKH0_EGt}OeAD zu4}Z5ojrzoyV#|D>eHV4v|JlX`DFMk&Z$#6^Qvo>XuW&A_~jtUdk1i9t-OV%Ty`Lh z&Vs(tidPl}k}nG`ZgTKy0w4L!wmJJqce=uQzOI3s)>O~?ADwxMQkg4PJq{yhf=3n}(g3h2>0R5VhSTH$4|K zIGh}pDPZP^N}psmk0HYi;n41+xOp%xVA$L|scxPazc?W(6HH+ft~58Vp5BI+E=Cpi zzHUC3zb-~eqkx;QlENX%D?hI+WUo0%ck_hd7`V!VM^|E{fTU$VH$ATyv)GtiuR_n7 z^Zi-|`@4C#41t2F~$pg3t%M>1N(pr;*9iA#NU-hldwB-F9`;)Z}9@ zKTi4$b@M7ec&tfrvAx(u#e0~WPZsew{_WA;2y>h!4w`Scn=h{z5`V$%dLM+fQX*I&lS6EqE zRElEhh=-*4o^BphvZ*XYR`+t#%5!Gh!O-P3%S}gq&6%5z;VY#YC|4uhbWTBsD$2Qq z$c$f&a?|t5%8Cj(3+$}J8XZe7!8&CuD=5QUGc|c$5IeZ-H5l2kyvnW0kSvh^m&A39 z9}n~^RElfL`JhBXp~Z{N6lI4>wXOY&sDxIEOB zGs|=GRo%9~n@^|NEL4BSuW>Q-$)U)sAgn5xJ-|&1t2HL*kV~3+(|x>~7g{CE>3fXx zdf6!t2fBG<-3>=j^vY&C`8mPOEBcLvr`%o#H8F3Ke6W z8&&~eLk|j|$j4+iU#Kz{3r}W2Pukjj=nH#HhmEM@@=96VVTt6l2W9%{1 zgJO7O(H@o-f2 z%i3#6AAo)L{uKV3{V8mxa(~K$z?sMFPx0(d%#6#ot-dDkUMm|Ko^d4BDcNzWAZs>im!h`N~%t#0259^xQffG7<99`&G+w7*t z^hIbNYnyF4mpr&fMM%f`W}6QG-J>58hrTX4{O>}?t*mbQv7;b5j_EEQyVqn!Q8Z6K z7ms_ygkkLOqA_3esELGcfQ#lGIiX$bE49PN^z#`#5qC0Nd};*6w1XV`aYjkVtrlHso72zH1;$^zU8C4P9Aue9=pT)>-CpmFo9y=o`Dvm>4cA3Xs z`Y;#W9tzRsH2261^Lo!%niCuy z*1cSGCq3PxG|G>xSiUZ!HS}v_EDt7{)rbvgqg*sIp3C)pqqQD>82U<$f3R5FW4Zj1 zejIhM*-J(9Q1F}a3o}O=yJxWX=Nn`}Q6^doad1X6_duB~zA}DAS|6XY2u1>*WUb_3 z1agm-Y~nR>F_%tGRp%6-2e9*V!Yg!L#B?}Co6WwNQ3w}O zQXj0P_D3ba?dVj`_dk@ks+RyzEFRROXKef0;9b3ZHA)ZN8Eew+0SQ~Ill88>?jvyB?;L?IASb9LN3u`LTv~e&WEiw=kjpPn>m+ zQTg;N+%{+O|OZhfgk5O1Ce{UCvfkv-bKkd zI@Za*1D|=OxMQU{OKQSSA7W+4&qHI~JV~b?_Jf2gF^f`=Q(0`*dSV|4aAwWBEZi`nvo4^Jptt8_jyZB>3@G+<^iRx-?CKZeU?Rp_)%#XP>3 zj^*yo;>7}tgt*oucgHJjR?Pc%$Ae|vb1kl&#!#im$}5N$#)M`Tm*wUZmxU@K!C4VZ z=wsYLHR^l_h^gAAY0kfhv(K|=7NUW@8960kwwjzj<_FVi4E&}(GVAoba`+nP!>v%; zLY!p4{s;BM>%^t0eZ}TKE3J{oPRe*Aff0ZmO(i^8)y1P*gNmTgZ_te)S2W_A74Ih32~2&`MG6}nuMS2q4XX28=|9f# zvE7r?Jy2$h9aGQIuW;K!MRwJLILF7fiv~fosRqY4xaetCy-g>cx{~SkN0;2|Gku&) zancd8&lL0{Dfy3g{vFpIn?<;)u8PH&a{Xt7gXQ|5IQ7drpv!qyoFjxoOc&0bWXYO3 zbw&|ty2N)~@yUkncl+ikxGc}zkezZpU5AZj+|;d0bvW5pin)eUr}_J^GZ=fl%~`sv zABSPy&eV1$Z$6NCsq^gQd}iBc1+-1OL7(EmfQ{WB-H#z}?*V=c@#J?G{wv^*^r*Ir zbo@^BsJ4xDkZWgO181H|{yK5Anmae!tA68nxDD0E!y7?rzM7*#2lcob!Xa zCWOUtj_IR(kGNIYq|%i&?ht)-#v)vLdH9K1-6 z47wC*O?{!9GUq#pGkd3ha+OnG&P9jQvB)?wBcVHO4ph;Lj>SNniTf`)?q;8>iaT^} z*SD=eAH3PFC=@@4ESPtF5o2M_j48!OT zkus3F1Pw*a>nE@vK+kcZEbDF=`AW7(D_b0*52D2m)5lwFH>_AX3szU z8faCtF3qcLrF4M8EGes4gqgrSJceA$1kPOykoc%ba&Ne6Ln8Cu^{Mi_SD7H|fN~{+ zQ;#%``NH}#6NzAbIbY`q_cMm-)5IZe=ok2nttd~Dz;{Mx9C?g&$>@<82sbI%_YYoe z)XkXW0qL+-)xHcI>Nlr@dVuvJ!84C36F8rQc$X&8IkT&13sG z32G1T5hi&!!gAT=6%-bM?}*2E&2f`gkX->hd6)ePrimMXI2)k7m7$0Ig$!qYAA$U3 ze$zZv=e=o5_LX$%oYFkTK4P@%OaZ@R^_c?B4KeH_SN=eEne+_<=Z2c>bm#IwI&Lf} z$6!v4&!ESExDseO@WVrY0r60TVbCfcq79>sWSHybGqPT zXwF_B=KeHe6M@G1a_4r}P<`v89PFmz^VX{Iil5yWLH1nb6u z{HE3fOqJ!&an@H4BEGPM87+0_VD&wZ2)aw*Hx_%LVnMzS_nSo+M;-&y=dK;FzE@jF|67h?;Qy>}tUp}|6@R^XuX!E5Lp8%aYh@eC(` zeirfBxe`{Mn7L;{r8}SB*ek*V@bFH@N~NVcp8f%)A}?WB2|}Mu9rw&9D;eLe{I@db zW&u~)m2B#;I)Fhza(!3jWn@QpH*oodROO)Sx`d@M>^p;0+zX!jf3*J7QK-L@bp0KU z`U^Jq&Z#Iu-PI;7&;H_)XYM_drXNN*XZoF-Q)Pc;gvcxQPgI+DAimu)j^9Scv5ljQ zJ4oC>nBbv|v%7%3^m`+|0WRKQu-3y=BjGUSTP*($k?5vtoRZ6emPxtj_*&~*Ob ze3L&-ej(Krmu8kK`2xKF{`M%&;yJVA7*+l(RtQzr*sJbOhpjo-UxI^c&{iSK6skO; zJE*rUfEL?Ypnk=hRiU=CnYcTe6^b%v7vpQ9<_WkDuv5I`kI$c@d5mc&g`nc$upFgx z0b9Lh*}8y~eI=BSkfF3z22H`ZL|8g8qMi$fwW?H~nReaccYYyu9pn{*|FLbQ3VR|7 z3o(M5Pr;m7Momk?i&)2(f?{ln^7E>co6^cmorkz_#n0ZG=h)$_fS(=inaIzU?GVOq z$rDLKm6WqzUMalnWl(sQJMvKBmENQ|O1F%vW9~fBdXMI=2rAh(SL<@-5RJUsBeN6@OhJZvPP{}<1C(2XFn!J z&v#oL-MZ%k=`APxRQ_3}&jbZ8UfnjJP;Ff@j=ks^0yj{_lG0!(I0mHjnMgbqunnnUr<)!g$@~~&4{oxj_n+;R@3|wY4Bzf zkFFO{25;|5QZgsn;IR#C78)d`t)GoktRkGE{f{wrsyURt!f5ai`{L}+jaKPXkyFW2 zW~9#PZ#(CgZq;cGGhUHQlryku{}{$Pfhc&4xN)EU5eRz};sDkY9d9s2;?wouG7jEr zR^_uQY@>2NUbjDE;fE!AfJ&(Jy58u%KN9#3%efbg^P2EHa-7hsAg~`DVjuJ2zu`U> zCr{KlC=(CnB~I7K{UPipux%s`eQAB4s2XmXc%-`G0sWh@xxzVf0j5{F=ViIWzIH~? zD*cz*Yg5=K4BbfH`6c=0MjiHy$rq89vSYWZsyMd_0tS5=4EfPzqJ5OMmtiEjY4+Aw z%{$Qn_U^st{j?oAE$FAHeTFeM4s9KFgqglvf8$T)9Byb6gh?!_K5rZkfySkv~YEqY>C2o|Vd$63h~ zv(H}aSY1VcC_A&iUhIqlHSNyqt5@zaarS+_w@~YXGW+O_9kkJ*XQKQxd*{WjSm_uu z`{WfpMKt1vkq-03?2i{aoo>UcChcaAywG5$G#FhrpBg?h`{NyZ_ERMLBn-1RUWM=I zd^CIE1)qS-fft(j(7#q(nvVk! zvIha|BYZRo2C$J+h)PyF-{7GzYw=n`v%0p*`A~9%eR^4&In~h-s^*fNIb^x)eFj6=sK>rh5T& z>inp)LymEI33zpO)E~ba_*C@r+-DStn-p+H@e|n%HDaWvX zi$h&BjwKwHae$AR8g999wxmu>J z0RB-&TOs3(ye-o4XJ0KDu^)wZ4Ekz+)P1j+u*Y5EoJ$v;%EC8v!?Z7LL@m}lk^>yZ zRn3hp4Ru&nlR7*LxPh2U#@xKE|2`kM1mK!mT5Q}L;BdaDZdr3HZnDrmXn%`gH$31x zD`gP-wI#4KPlm~%9@YZ?pwq*7e$1Eq>3|;z405EdX}NR99C0y>KUV?}AM!irHA-FK zvQNiJ{&4FU%-^HHpXB#an?EogLq&t?Tn-M}srDg)Gd5gh;S?>xBQHe?4(*6OBNip! z_LQyP8fpdNg|-8pI8(Oz103udMa4+iNX~X z=TzX(qK>!1$q1i{S9H8E#ufKAH*0?}&J}!iu^eKNG-7-!ILOdU(--WoaTRme+g7|7 zt8q*y*E7ssvnrKN<{SM{=`>$Rrz7(tEu%}u=zCd=JYd_M3}(O{T6?XFIOZYFxCX6@ z5s$dERyVa_&eUJ7aP1iDj8H5|*;0o+accd&25~eG*AngdQqzsp`x|5(P2&)CjIqr= zA*FXSl#DlR?*3-($12IsDJshsaZ`aI8Luz0*Omh8yz?|)`r|PJQP+=S`qj-OrB8U5JkG74)n7*}>Q1T$>O4?XbXs z_hRwx(UulW zV<_byN){B>FKw-EUFWtyePEm-bzN;xJnW)y&UXhO5hFF{$2fRS<-Ht=hns}Q?5%}* z;gW4z4EL7DG{YYI;ANgd=6BS%IiwB->S!GW|GBSfsP_MO@!zNROaM>bhQE=mf>+!P z{{ttB!pBtA}_2N8byDJaJKz|42gPA}wW)!^a5uhLJb2xG>+G5|gQs<%S12tB!)O|X&kD{@@ z$@Lv;LGNK}v-J7Y-iW5^CcWo|-w9S@b8Qt)aHQf}WTxrK3y^3NOY#UXE==Zd!# z{oD90kXM{EMq3jAeDzzVWH4$U%)6U)u_;Rjccm za$=(*CeY~jjIXU*+P*xcjL1m5Q4wzzk=xwQ_@z+SsvovhmW~rg@=cmZ zYrKyKNz_CCq9P8)KjZPD@3nua(A=S8M+|79K>$9JCmJg;#$;f!#8S5PX}iF%(Bp)vlss+tXSJLNxO`du-rcL{#sRD^sn{E&t41m8Fv$aW;jw|a?E4-wE3*M=Xr0GDT?1he6;X?zYhYUSRO42ao9;Y>CLGXgM`5RFZwA_-udp%9 zF+S@x#cg7#)b(5n(O;d~KpK>w%N2-Ru2xNZ_zB0= z-P#pt{9REA1?!u1MqWYCmyx5dQg`{qPMCPA05&?TR%1uJ#AUN!K6lojbyD zb*pwo8h=*@h$|D;2V*9G;<$Q4yCRLhD|n5tD24c(GvIb4-NbN^7Nex`cZEA_;EFuM zXYcC|KnNOFsoE83{9Q3_4o4N{H?MPCE!3_^qkQT#Lfpn&=7(|DLAG~M5tPz=CX8Q= zX4AyyZtaRR3b)Y zdW{`cazI!q;!gqsVyk!8-B;Zl9M+*ib2c)TvVc#D9o7lj=M+1vE@1k@Kl-dJFSbJu zOzCLQs4|5E>&mm9LzdIzZW#{~nxla>DMil~I6k*)pGR9v7oV5xumV%co=8;0k@#mt z8GrLRj|PWzxX>^PCWJAzX}9)yj2%{#=_m-sU4md2S6EMPz3R!}u*M3_H~2SUVV5<& z_;7H*=ZGMm8ULt=M*K568(%&i!Vl5)%dv4nvlVDlTaL7S9;JOgQhWxXHN!6z#FPSq zMh7c?rUa|}Xxu3s51OcmcKkE$g%=fk8XTXagywd{hqZ|h#@)(bt=2w|m-x7SP6dVI z^E}>o{QM z!G=EjhjlbCPFU4h+2|s}Q@{FkjL^8lI@%6vr4H+8JFHW6SoGOHtUri9|G_^q{=D1E zlY_&WDKtle!{cG%gSkm%u+G(C{lO0F4q)CBn!vC!fQ^b^-+-yPD5c?&;IJ}SgP5re1$_es0S6rQge+EAKB5zx;&$EOk8f7sECO)~g&m*tuW$pbbj0@YO{AQV+YajiU~YyB`s^Q8q44N3)y+2!-4TYkPJ*yoBMpUZ8ZOSI4BK|WXd`TW$0 ziJu1hOlcbx;f`~q?ekLYb7hdv?1e-{bl{(5`nQvlUI_MifzZ6?%8mK9&pz$*{2-s% zsyRMy-TK2B!9E`wBW>U{0 z+viKP&x^$8l)^de}$PVaCJ&A8j3R855CgcUWfI zUXTUTX7BUMm>7_9CM~=z+=kKO7Z`E)(?`nC+6IF%6+t^In?d;i+Yp;DGg#Q}Offv+ z#yR^uk%pNwtFkkyQnO}dUa#*r)_m=KLe4DLpTtJ)TX5D z;a83A-x}2%DD|&!nIdgX%9KfyQzw|nu?fLSP;-rl6=_347oZY5CWbxG*zJ(g2rDww zIAalJOhV4sM6{LaS!f;DsBx_ek`OpxTXjUG8LOLRWA6eP(p&Pa^H%ZtJCdX5b_{=J8fr2dfH?sW8FHO{W2}x&VKTIgL4Oz zAJsJU9(9KK>vNVyUD6Kcfl6!Xg(I9o+Ujg;Q|w{a7F)vE7`wT(F{W9Q&XV|Jw}^rw zr#SLZVh^`RO_(rwQnK?*NSl^EWy0iX)7(f{Pe@IjGG$6~^0f5SX;X!KiKj5)SnJ`V zjw?%A7GZfffWYJ4gTQYN4GQ<6$@O>=OkbJYhaf&07NbFP1iS8d`s2+=2=;F*@GYRZOw)z)FBuj$faVzv zjPP)@7s|gwf&X69kd9BN_;JQz1O^dFRYDThKjvR9Xx3;t=1VC5h9iDmpt)`d2=IhU zF9yEWXG<*Wm19Q zuQez-4uwPI-!24nJZO&N1T-Gb$A!zkcR@3Z16Vv5aEJ8ILb#JbGx>NS3!7ffa-Im9 z(={EOh4k-eSZo2!ORdVkaQsaFeg(|{PWa#n=N~Qh1!-}zc)bBZ?!`g%D-=5Jry)#*En>c{JRU*$AMT=_Ek{{+pP6BS*!^m6T~12jjjS9Am-7`&n4cO>|)7BpKr zNTp^IL;1(@{k+4nzQxN2(Fo}u*M7P?u=nRwQiYd)n_yQ5nlD{+q2l)n{7de%tlb;M zyRiIxFRZ7W2APGI59LNE|Ar&IN1cuv;m#B?Svv}q-WOo~XV7e5MDfJp4dq`d{QDo! z{MsdCVe2pRuLBcQU3mHQlz$h3=7r6Qj(iX*e(T}EPoP2o=Ad5x-Geu>br5 zMK>gje{7d`gXYJriY^?#aP54`g_iZ?MT%}f82^3(e#FI)S6H3l6OT7k{5s&@9iSO^ zxsb{1V5sz73G1Dp*>r`X3s*n(A{~!_=H9CmUAXom6Ldd-X8JXXE?oI;LHy1F&HmRb zI;JC3{0;#AF3`NF>EM0H^s@c^2WY;yLHQT1e912d--vz*UOqkfHwiR_Hz~Ss{xNjYGykOM z$XB8G#RvZ`0nMPh6 zgXY#pm4D&t@9D6Pehj>imrpqV&W3-Ff+p{AMHeo9^zR(dByCf4J^7alnpdAtbUpbu z{7J0R;^otmf3JXM(bI}9oPQs|`dZMO{*0oF0SLu^$taH}LG!_Lz56%jdF-!$p?ClC zK(pe-p8fj*)_(%cWiL5&q2f0m@p~UM(_U6|lp~?|nf~1bnys(&?B62z_ZDcTywSWlR~sBLvqV|9JgqUFua%W;P@?&@6B-nMj{ueEx0 zecK{mYkSkGMer85Rg2nMYiM57ymTd|8LHN-ZK+zDK4npT8vbwz@zPaQOIJ13R%!C_ zAj5WyqZ6$qto{^G1J=H5!y+E(X=`5QOCD2tcye(Ij%wAP0G+tWJb7K;P}geR-tU-1 zt7c8D_4}e})ihWOr!T?`YEDkUqN!6-Q^!x3l9oPs{DehIkzmH0Z%xB^?|iRS(^zYb z%dP!=K`mNcGc9#|OYPF+aku=c022#Q3}xj|CTO$E1Q7N6ynG9)sy9dON3l!hHBEAF!BHF62Cx zo;H#HK%}ls#r(H&2%VG8x2DSX5;Y|?&G=n~iyxt=4u|BhA}~ih#KjGT%IB)Aiu}SH zt(dK<>KIiU;WW3TSfV#aR1z|7(Ceby6scGh%*!bd-4#$^Rtf^#otTqv)L`mprB0Nj zl$1fqhi!$(*CdZySTlVMRufvQeBcpZ=nry@E9MLD@RB_}!)m1<5Z=44q&?kQ`k zM>O%Wty8BZk6TkaNwSb|BE0jhgBptZ26&#^6E}mu7OkmnZGxN}kLVVa_kr8WAwuR` zU};s4d@YAsV5%KK#z1EyRm++ClC6=N zZjeofi+aJ*NO`=Uh{lsON(6Gof;4*k9`8OdC zwuxpzH#rnw;WBMpW&k=Io6LhgUr`+ewSmdn*L`gV&<=#T*SA*(CRb+PJ_O~f>yG|?KAh~9#JBsPlAgjlPm123_Z^-bf4Yf7UAEih~ssfni1jwYmmw}`U_F=V4AO^5=n z5jWXl)SwBCQ90?{R!hdFS4JC}kjY7ZqlVIf(SZV5k3Q}=rRx8aapE&yi*q@Jj-`u0o>4tGhoslj0{3ODSGTa%!WMF~7gE%!~~ z6y0Qm@VA9C-HfN87OPuPpajTGq9&Eh5(d%0TNluEC+h8x0OuMIbZz1|y+ ziwz~~`g#es$?EWzYa1W?dcC%he|@-O+ti8PZrL_Ustg&t_`|O~IUmgA$;$&Y1(?AwH)e?{FsjIv{sR3B)IiJ}r8{WN2;r_Q56b3q3akTkj6&)v-Vc^kLJ~qr zG~H28FlH|8>o@E>KA0F<+U|G(h+Oh91UBmW*!MpfhNr8rN?W*ZD77u2*hXAIzfrlZUd?z3?MY&3 zTd?({mr#!+7OEdy1?{@%6PIOYmUyu{L6P8Ab>$Yy#B!keq^wF4unD6d12lnjsg){q z=u9=X9&O9cw^))4t+sL-r)}B&uvk#^5PCo)M7i>y)J6|7X!P-mGHoyRG3b1#IyPR! zYou1tZt@{Pqp6cz)bEnf8DygI#G74Fn$MCgE`pAC+rPouUMHQw@Wxck%S)bU&FBUV zh51Aqt$7Tc)R77eEiR={HI3M^8q*?5S%@Y*R`{=h^S_{$EI`U=MVT!MYpHCXBLyac zmi=_FbIO?lXk*4DI8;(YFKHj+wwI(48>_w4>iQ@~h#sKOHpiG4;9?}E&ES=GJ@N`2 z#RXX69;jI|Tx82ZwT|J{HFFTL3>0A$1t!9J8bZL`3DBjEOIHdd0YqWgkzG|(mW|;g zYLaBCjn+683~^CHnrTSMg+${r01P3^b2x`1vW>`oMCM`>ZCSbC4RMSRFJM@Tm{&<+ z0V%(P^CBTw-D#rT*OKKzn)YM)~g+ksr`51w+M$!(cf!!Q0ZdtWw zC%p5aRJzPgFmz}l!6ox_;*3iq4lYISbf8NUFcM17IrzpvDi>-1%dx9T1&s8D8*o%`JZv1SCdQfVg6g z4C$d88Cz&e%VqRRTcn9G!>AM9WI=|>sB#T#khP+wT&ecU$$?78EGT>=N6{L2=~$~f zE;I!LCIxcTp}-wwOuic0(iXYqXKNT+$p>;hsgQ9F6_imUk%dz4Xo;M2EVXu4>RmTc zL^e70%9xwU`4*93wbE$0w0g2KO@+7EETv~b)YOM4K4cXDkAeSv>2N%3p<`G^NUNJ35Nc*otdI2DsZMJ%v1;zM(Oy-r4nZ9(w=al3}HwE zY&z3aW?{m_o)7WZ*7o!l@A9rhHKSfHRNui?Y$CO1iC!<1T@EIv_5<#6l$G2s>!)=K z#Tc7-6|JbsOEigPXQ3|_o4Cm!McLOdV5m#WUmY(!?SB6Weew8aet z>S9BWJSpYPF$e>yoDzNDOsMIUo1B;_Q$SbZD55kM_b~nR)lor5%q76!A`p1VmMI{Z z;*t^-OdKdLBqj7`N$y^N5BJsKl4ZQ3RW3zyuD2f!hg2`orr{&&@lfE_iYm4v**ml;KU=q`<&CZlX-qkcZkY)K%u zS;fn%%1rK4AzF#1BHvWop4w?5`Y`4V`>OWFSt;fYiJ(yg2tg2=_z5UUXzmL~gH)DX znqR^jst$%dZ)X>uLhJ%Y?=v=W7W@=~z&k5gx^c#}a|8k%U6sE<3Lfcziq=#oJ0FVn zlx9h0-hRd-?)|m5n@gg;L3g_tO;(}0)?py1M}bExa1+!lN#fxksKU&%$swc_H{W4i zwsL|*hG7P&vt(HhaR=&bO~*V}Y~sEMf+0vKj3Lz;LbY;$mQATLYnUiVaTX#|zpn)7 ze`Bu*n0;LVI@|oMQE>Ar5+NBQ+w|pRhFlz8=ksC7p-rm)YWN#M_o&FCLB?yA1iI&l zFtbIxRQ!Z#UFsJ^%f{sR=vQz(BFnTfIb@(h@SX zq=u@5-5gDdJ@kn;YKzVeI7**Kx?=5B% z2Fz7z8o+Ubo?dJst7w=SN~yq+0sM0-@Ro4cc>><3GiUC+C|vETTjD=MuL>PJBlnXe zhs}2=c36r~3QMxFR3^=cT{`yhKdE4c7?~pyfl~c#lj~aZJ0(+#a6i4GfZ4@NA+!1) zRzcq?Hqj0y`~edwM!$;TK8GaC!uCPxsu6zTrryqu!1OXVc%gxrv+yr^W-zBxk>}2J zBO>BPNxE{lo+r66%!DglAC@7EpF3d#W^h(c+-*t($|58b?_!2d|MU-To011PW&6;wGFQ}Ie}T8w28(|mu|R*Vbh z6A^tqYbb%tU?3seK32;EOeUe~xsIe+hro_2ojqNpCv3q<(7-8BjCEBX&}mdn7mz%` zTYXfF9BGPfGFG#h-)Xef>67dtt3n;SOaQTn2AC-GJgQ_jCxamvMH@d^)us@!rP^ev zVyPfR_L!S{rFRo8u_2p*Z`kV}OGI{sT=2?z$+=dpsGCcXIR>KWbypH;?vvTRS76v% zDuQ?n+_`fmn_E;W&^J>9n8WC;lR=Ud?2%CLuo3gSE?b%aw$$G6wvI0|#CRdS2< zL3}~Hh%IF@i4@jit~0h2s3sMD@|2c;H=Gs7m+U3>r%P8?ucW%Q4mYXO9VJ!Bu@Gw! z#jXi4q|~Jk2bz#k4c+G#rK>p1W$79a&>cIrA?r4Kf0SI(A~?x$jd)ld$t)gWSbD}a z0-<-Pl&oUj{|rl2Y5nq(-3iy+f$Hm!jVWBdr=`0oQ7j^?KxS5LC<}{A4w4SD;2>g? zSk)rhXcF5aK67}|?rdxS+0Eh=MyTo-v}9!#;tIMdZyxU)s=$O8t-pbFN$6e@gZP>u z!+A+r1t&}}^~@H9-D!0>dC2}Wll(qN>Uox&BNoG@xXF<%)J}$p3QWhsHwObDsYa9P zSL%{^C_OC(F_j0o;p$o)kIb7V=|hiHzL|kB%69J(}3Hy)R*3!-+!MYl}fLKi1)9p zPI>U(H~ddd+^NN<{^J`sY7+YK{XCy_ZJ#l|?w9`0zw!5r-oc>_!QV0YKu^}2Z(R7- z!W)&X$L2F?mcPQ zjMw(IfBUzSj>ZyMB;&L5jzgb0xAu(Vj=B1d2S0u_?lv3-75q;pB+R|Les29`qnBQg zzvSzWk+Xtdmp|sx%~wx2@q&VrTE;wbGYb3^!9RTHeZ#9Se&OiD`ZWx?{-+=RiUU=G zulVw_cOdJth#gRdl#IPazg6gm}$QV{+}C8*mdH< z>)!0QFzwB!65lGdtiz%h&xJ`Zq+a#;gh}UKZyopM?o~LfwNmg`7kE;yN`LFn8y-tJ zV`%KPIOTS};Gdds!+FUkdT+5#UwHGludclchad%CR{zO;t7lfdc<{vi7LKp)ILpEX z-Sj`}e-8DQ4Sx2;5R0E~eg8#)k^yrqmH>~~ZoBLgU!G_CE!LoKghMThP&wGwK_{rSi%TCzw z@3W7nx2%bRwAX`8JMVu!$@~?EKLvl^gE3cr zI=SD7kzamgZTaze_&|Z(N{z!K4Do41pn-buXeobdGp58 zZhCd<^zk;X?)Vl5Pz9fxctgK|qo3J%_{{5D&j0Y! zk(Tw2;BOf9?z3+_cKZeEFYfpEO;2vU0t=lunU)Z-Yt<8r7gZm6$Hk+D9n|>K?Kq%y zq~OPGS#oQ{J*63k%}ejUJ3jd)49f&x^zxu3SKKmv{NJX(fwB2M;Lpnh|KrVHzh5_c zLuTd&*NkX-e&{6RgW&&O`RU@w1Ae)5j_0kMBmY&31DE|FBN8HJ#H=Y#J}qL$fcHk0 ztsj2O(>RbT_`5GXyrl7?r{DYAj18Z>x8s2CA>sso$LFsPj~R09C!3~U`rd^for$u& zT<{CBJ4&Z*UAq4nKgOMR;XSAS!Lpte{Qhsui8~_Y^}{?&c?M*m&eIQ2a1}@#);Y?t!?$<9_%k`I-+_%sziLx+;QSJoe+*|M}#_$6r}| z%WFq}cRk9hUhsK${P4yJez&(aX+Xmfkb4b+Us`>~^Ml^MFRJ>7*5^9EylM-S;tD<^<(`>` z|MQw>-<|ivs_Mwk4@W%}eB)|QK`?bvd)3C+2#9wgw z+AH5UtPC4?aH20EqHx)U3ohC4bmAqCKKAKl=YKLAN;m|6VdN#JJh$VM$rl}TU&qNy z%W*1ik>DSkowWC?*z&X9_(%K3(O+jFo*M;!!dGQmXTBA?^`r+TRo}5@)UA+Xf{%aa zjQT4ZcbskAAGhO^<13e1)@y?Q`|b^0k1admsMl|M=)h^$SAGU%9fIHQu9Hvu%j4Na zMLF|#)oy+O_2SThjOWg)|McS%x8GGZ;)>ma9zF2M{m{=9eB$nlp8m9Z?>)y|^rLTe z%oAwI+5~^|&6ivnaZ>z!FK?Q1RC>oO93a0!@Hww0pS|Y5YbOtT=Gz};OldzAd?oml ze(%3~*uE1Fd8mBQzYke313a};@ZH;^mLLD8#rO7mEB(x|SHJWz_A=w7VM4^I+n-MA93QkSD(LW*FBJv zZwvnH;mcpSsPy3BQwI0DZ0?fhkUvrTFg|aOx%~dq?>wXQ$|cu6dce}j9cYgPKj+f} zPP;y8Resj~f2+7|(|FY1d4j)l{smWj`0EKj=lp5wXA3?*XRKwNEcld9-YfafrRz>P z|Gk&XmLGfCOHkM$_>%`+JU#!`t(PqLaL^y0PJCe-`UQgj`{@&g)c>+Q_Kf@2optKL z8RtM@2>ufTtDD<>y_2o-HS%nf4*0j8R;_JaU4_7U4+f_%>uVc&r)zDgX=>|(f5^$! zI$bc~a#iQn^4dQ5*V4A41*-4TdygSPTUy;#*C)a{UZvazN^|0@Cw63Ns7w|5$9`vF zsUyTKxUvxA=bmGwc^@;9z0-lVZ=BoKQdiUFYvn?B&%QFLEm()?6UVewH&iiSdiN6d z*R6)PtNTFd#MI^YZ>=0EzcG}9O2wMy2Aux()i*cw96B?e8M?G@yxr7?8jcK7VgA1O zH`F&lb0iL(xAhX1M4hsv=M)MbyYm+uQPYdpfo|G+7lCX)YUOrLVY{B=MB=vE)m43V zzz9JQw1cI3_E{6wH`n<3ApP1~8yb7#5c*iNoZ1MaRq9dr{Vyat^$;iq)~kqp2(G@V zsm`}%m7@GD+-8oN8%+p(2&<{7=6@58^aa{*e7UZdd?Z&Zq1Ah&bR#mM&ykYl6UP@>Unzbh1 zvhnpz4ZSs@@U^;aonfDz>Q7_M+TIID7y88BDG?OvQtxyiYQ=H#-U;DhO>g3YxzhmE zAHF^mIdqXUt?8wKV!1Ro)b$~`$miOcx;}7ZOLGhRUcILm;a0c%ntLZ~Y+Kvd2XWh6 z-M1bFl(jU}FYimnEM3{Rz9I6a_f&w$Zo7M8Q`$AJ=|lOp)viKI*DDW_W$M<}wDi&_ zldQfEg~7I}Pa_tjqiuB`@&$K}SJmJ~YBOl*DR00seJW$ctg1|YOUosiOr$Xpy+T#1 z>+9B3Vc^x$m$6rCU3HtOzyFIsd*&n&kG@(dsg&~63K)VCz_ds6b)vHBG9B4gw0i(gz?*6%U}?~K=!P^0;JuyR%M(!uX}Cr-{bP^bU>k4j736JBNmg7U(!pJs zmQ0jz=@Z-3rX^zLP@eH{9f=r2n={@#g_M7WeHSJTX@@m8c{(hsgYh{9kSXm1Oaj~p zI2`bFK*kko0v(vUMV4VvLT+uODNgRxp~+)it8L?~8@0(}VP#BQ#97;HoMd@rS9|Pf z-}#1h{@U#u+}%EKrB%5D6jtZc1G}Ex8JV_i@o`VaV%LaLS)F8=?9U;QelWc%53_?0 zv!6*LE#XMKeBAcR))Jj_Shm0gk^aR)Kk4=`yeHbl5Mi$Q2`U_hr5+YeqAncnMQE&R zY;IkLeLiuC%r~t4$cB?JMZ<6di{>n3Ipfj=$l~4%m<)*N;Eoi)Er5*Yd4LRp(d}=o z)uuSPmW?=%^`?#cmo{n6@AAf;w#_$qb4kQmu^Ag*X#ZjClfGyd|1)`kTz@EVd`!{< zxxNW@QvZ@eeHGo)Q zu&x6<2=GQg#_uL=kJSOq=`<-$r^#d8g@1*+Pn&dhYOX%GD+al`U+3O#Us4Hz!Sb-x z-4d;&OXp|{yd90r9ZDL-Sd8olypE8`!Iya^XoEYu$rb!IoJtb6z4@XLB0mIjIsK&D zad?ZJ;xKnr1(kyF+p<^+Mg&cQOU325;6X&tA@Gk+8f++nD1b7E&=13S1n!ox~Lr1k1>^M*0K(sVwXUNz%u#2^MS3loEb79UH- zDn^3YxW!ml$I^^d3sZ{V+VIa}O0v$xzoI)ICdGia+qnB}+}~~7+cu62LAkIIuX#Sz z2HNqVT<8zTZ!+6Ec=;InXJ8+pzeq>l`MB+k@IDOqOT;$No~)t7`HO&)EbjMn9>$4& ze~356wuw-e^_W|Hg4kX8DZWHHLVY2aTCGb7uTxa;DFT|!?>zM>ywC5Y`nycqZwauc z=-|V;Li&HIPrL3&;FfKk!hAkiRp>+EKg)YM$j@K=83sKIDPZ8i~z&U^vwk3d! zV<{kO0R^!Vx-==FOOwZXO54U+&uNp#qNr7L@7Xxj!QM4|vvlWm{dLUkS z(6p+uuC)zIS5mBunR!eM@r~9r-cssy@TL0y!(5$6byOu!R>RTdS6#_d5R&nmxE0ljzBn_e-x+vnEdGvOpeB)f#_gtjsrXZ5F(=^4R8tIRKR+`X@E-snZ}iXOfO5K zzjd)T#aWkYlgD}mrc}If)^=_3SVyA5(nXw=s!h7PbPbRe+v62mVOSY!H>O>4Mr_JV z$A8+kX_@K1{+;X6yL}NEQhCX?s@Y->im?pcZ-Qu)$5bNn14Spl3CD`9;Q+-i<||w^ zrk`{>1@GO+arKz;&cbwTT~qDvtHy>wro&si8mF5e02wxk82=;j@@YhQuv(+bEhBPwTVz6!_ct8lEo3iqCk)73Yptn0YguIv$&Y2R&X-`ka!-c>T9 z^Rtf4-bd#>>;2Vw*4u4uDvEX2??=DBt&-LIQM-DV?trh>jA!FFo&z@MS|7Wz-)8T2 zRPb$I-{5w+{p;H{d-uW_Z0Q)mu82*6cxV|RK6LFq%e(zdZybcWr*r*Y%NM%lx@9uui`zGYFwaNQ0UnW8s08ezZ5$DHK5YRmTkS+vu$ND(SH}Wj+p6T8=-+t4* zzxtBS^!~c@k1N=+>IsPNb~eR7;QdmM9bEOI0QF)FJnvjP#%kw4EpKzt-nsD)6n#0j zyJgJgqU|e(&-Dwl{m`ysM|3_l20h0pG>q<^W2If)My7Q=TebMu7tnb`gP>*Xxwh#o z+mwSSDhYf%Osokp*2yrb`gj&hsy;qw)4gHaz7Nv~aX}6a>^$y2G@3VN1;@9 zdTbt6JN$Qp7Q;AMcP1Kt9-3Gi{ivjExcI0x`Oz%7832p0kF1;hZMgB$AMwqr2h6@dEz zUIoZ~?eME(HsEc5rGR$=)&brJxB`&wR{~xGxCZcAz;%ER18xO;1n>&LM**(^d=l_4 zfKLNH3HU7Fr+_a4l4o85Bs(09S9PXoQk`j7JGIGUJ!0b? zw{b7pxR-6*M>cMUjS~re4ZOEDpScKCd0J6ytEXQIGH#kTb~U;3l&*Rr*d3N@vx6E_ zLjs8UMSf=`=Y*Smv`KfD$e$xMxjiS^m(KAkC^yFGHNe9G(Ua+*)O#Ip65tzvEZ1zj zYATc_H9BKi1h; zjL52Nq)BBXO{$NtaHttF-K4W|1wL_$i{D?`wvrM^7XA&~K`YMdv$#g#jS=QNTujU! z_C8~9Mo&q=80Z4Q_yBL{5-|hua3z9v!kQdVDd>i!b_8B3Xi|?V5tp8(o{J^y2#w;1 zwSZ+3D2|*_nY%<7pFqamsY_%RAmjOkE|ChDRf*7~N`xj=A_~V6Q8Z(R~#-7#z(gx4iy?UT&g3+BnQO#0e z2BiOrbN0n?iI2N-M_{Dr4hKexf=dKQ%$D=M2C+3|K$tT?F;s_i^TGc;|MH-4Ax*DGQSE z`UR@H@S$dI*kz&2<72wqOXN#^o2Kzu4Dsa(&nSe2XC4lIm zcL>h{F2i>mAlU=WVn+jDBH$T-=tXyQ0iqY(@khY@0WSp{33xT&D8Oq04+Oj!@E}0u z`yqf#`x3lr{(&Yn|3H(+dI0~5n;y|7kM%rE)p+CBa~6}w8iR&~g=F$R^X zKPusw{dYz^+h4C+v;I`EX=5>{YO_B~sw&NZsTOaN^zf7|vpYv{>%5qLBoQJL@s?*5o5tr-SJk3%DO37)T~F z#{rh&dpzJGz@q@G0aF2M04D%01H@{DRE9}_%#+E0Wa@gnYVwmNHTg-C$KpDO!VS|V z537R4aUDd_k!=-ShK+NEX?Ia4)oo-@H-g}JJM-R;Snyt`mZ=x!ge z$-BF|eK_Wpk~Vq2QM2#h=@p!+GBZ_`Y75L08I-?54h9cu8G7RQ{ah`96M|@vNPtxWJWa-{#z;eeNy67iyoJ?G%iF7$ z*Fn_>=Z%=yWaMO4`!Y=3K!rqHBJ+;CuTX_`P0M{NkfCvj$+Q5iLY2Fwd-~Gugsfwx zyxetcCh7#c)0h~PhQ$R{X#(2 zu_nB#j?tv*7)>5oR%jO7oA{^6V_k=mR&+OM6LucixNSBrV7SeU3q7)668SJHd;*8t zPXX7{aGMHC)uUJ|jNa0oM;Se_lo@CwBNQkKLcfNZQ2j^QuOJc--flfY4)=xb2b(Gt z1#eSS0<0w{5*Bd{AjRoYT|_>ZRX>;})eol0!`_CaaOh`<={NU-%R`B`!1co}??6bl zE^k6fcPgY`cY6|73n0!CT&o3@U3*1}bv;*w4sJp(Qj9F2q}Y0xa_~9~Qj0J1ke68< zO*se3t~DX-jqLKmZe~b(M|NSz7sOx;b055vv_k@9R~RibJqxkEFc>q0*XA*KJOGGtjl}ei|~+o&t#J+z#g3T0mCn6YwheLX(m&GKjpz2@qe?o0mD4D8C*yU5 z^lu#gT>-~@-b9w!%`!{KJSOkad$PASSq=qY!uA8575JA=E=Zbl&2;I%^6 zNg3bSbunOk*VGkUCqwk9bE9RZ#i@`vY;Qu<#t~iK-CackOIRn*j0mWeTyTw*ecWtz zV`Pa;^{;2*o5hpFeL2WR+Fpo%RXwkQDF<(obwB<)@W#mgEQO24_qTXA;x*3;Fu1D^ zt0yZLX%E3`dUmS9VZqB)Jt<9B;&r=sSI=hHnQnu>d#8GS4;pVkPn>Zg{WEw&jW+)e zt0%Id&(%|M22nO6(?Xc}nD6`4r+;;2)iIAL3wm_6MqY;M!@R(vVh1_kTEJrf(XZ{` z^!E*b9Fg7#$W{uy+>Q-^w*X?%(z+Fpa^fC9R?m9@xde4P;2nT>06q-(C%|ohcLFls z?*n8hQS_^7OOvX$G^uLKiJ&-()s`kzZ517>t)gSKRXA2#g*(~CK@4f!#WwD88yC|437-lA^O)-8?v-OjSS0+DfH5F^LKh`jO7+TVQoVATRIgm&*eh2! z$@;l-uK|J8S@$#N#F8*!7TfvkaMhi`W}g{9m>$jE)$z_$^=DJz%e)2zv75T7dD zJGpjan@&HR@@PK-*dapxoo^_QeI#mPXKTFjZs)b^^PpP~2|j$&hS*KH15bM!PSz(` zKFnbxZO$EDrgm2Iu!uLdE5kiQ-aqYyxpU|49Q&PjV0`s{WTkL5@N`Wr!}ui>;!g>|hSK-7Ac2*pMSDZu`mfR1e7az*G(Q zfwMb|6XU>58^eU2Zd7GQ|BjWdq`9HKW}Wo%=(~9a8pChz<#EtM=gD}bI_Dq`dVoZf z1SsPsZopx3+wsbl96evdNgy__95$(~I-H~V8C!CEz_zv5)IfO+`m)m!)9}s5v^I;> zr!^g-g!XKV`5606>eJq1o`Q_wW9*CcH#?VfU#Gv*@a-Cv?NzSipLxv4l1FxF{9hq_ z`osJRU79S+0ByvY7?IQmm361V9VVwShqGb?h4JxfcuQfN z-q{@}iw|8Hyp@+wJn?x{=LZR$@5RTx(iQ#3u8QHCA~(fpG3=7MRXaV-FoAvV zB-uu*q+T(iLQYMR4LcLW^cen?oZJmlj^KW^aj2_7GSP#4XT5OCw0L}zb^zXA@Vf2q zf{ap|mpP*hz6@b+WMUoc$X|i(-7+x=;Rnh@#)*Do>CfUtQtGj1yaQw+eK(K4Ozdg0 z=y!-fWJ&KL@FR#o_r~^cV(}3jWh2&pc70QfeT8rGwRxB)lwo{d(#S;Ab(YaEz)`dV z91FNVU=iQ}fYpEp0#Ym=1h^LPV89arM*?!ld^q41z_EZ_|Ck7P58x!g`v9i_J_MKp z$Ue9i@HxPv0sjZ^4}c#6&IJ4zFawZsb~fNQfCYd*0y3T~(?UR&6vqKdM$x2X6iptB zgJy-puw6_Zi@k4!yV}OxXX75UajJuezF6hFwC>Fz$5 z=+mHkkZVzOXSO)=?=jB!UiBEqnjRw%L)c?XP{i2atj|)K8LpiL-R%jO4o2^AQ*Jam zh^l|cjnYpKoHuV?cl*zkE0SG3JV-s|S)gA?s&vm1^oc@N&?AvBB__xSwRn@{*s~H2 zHMVUtOsb=HDoo0jtf1UdGO~Kbh*ZsiDTzBvbw_PGOiJv$1Cw&`DNM@67ceOos5e1k z=O^HZN24tdyJ8HTI1gUB4zxE1??|^ZguM|vjMLKr_Ph_pEq1U7WK9bgcQH=%n?rwI zDWe{zE9SaUj)N~o&phO2{h-bIO)G8ec+ojK8vz|JW=^P%R}%349WPS)@VYx*`{A39 zkuVF@r~TcizfDK1Bfy?@jSo9k>}auO^RYWx6j4_bqaWrU#S^n`tHzbF%EMd^$h=(u zI2v#v;8?&#fCYfZ0WJls0%Vex0CGs)49MmrFwVh)u}k}Uh= zi0OR%v;3WNPaE-N9+m_-$1M#8;hR;A4cvKn-S(W!GXpcyogKp7NP`mC9UanMRa$b( zzwri21ICGdUy3(y=?Ys*-1kfcE?Fs$;Z8EP=^$Mz%rY*P*sBzc&C51w0v$()<*_8Gxq(76NVrtO7g@khS(Kz*7Lv2HXU= z8ITM$zv@8zbo8IZSq(hHg2PhGXsINZRy^GdGTAfrFBnR zKX7yOX_LUQ=ytDn&#TA5*){OKPfh$_R}-JM?KAdkIxu~M>GiIxNtIo9oehL4D4nc(X~3^wC~z?@7x#IedF(sA+oFjXSMdh1XRuqAUN%&i77!;=SnSa$-3hW-%Tmo3oSkEY8j$ zM7Rk%YhzQVjJfQw6i|0056>SXvHnyJa|`E81U?N#7Z6&d+wJjqf~cukrgLJ>0V)U3kz zKcb8DPMFmi0Znl-mZ8aGkzo{Wmo^0*kohw#LT4`}9G`I6do%2&2S^gSVH61ivp4t( z&~SROEC`XFdIrBef7!shvzPG;%-$z-_C5v3Zuyfsd+&o;WiL%CdudYHt8mO-h4bTP z>;EA)vmOL)@$HG5Lkey95$gGWp5F*0Fv~-6^b0!6{|ZQseo<#R1)$1unpBq4u-5QN?);9ltZD+ui!1G@MB0ak}}cc!c3Y!Fn=^9{ki@Wal^iC!A(XgYVjuVoUK&I80#M}sqV_VFy)Btm-z3%8zYn73KxyusE#5nwlmp5#x$DWmN zZS*_Ww=O62DFUa7j4{p(Nw&^S%Vm1Mo3@lrz<*{Y`-u?Z=0J_X2(d_yFK1fR6y~ z0Q@K5XMpbj?gr#!=N>@LcI^bD9M}c87w`)}mep5)%>T#ns?G>asxv~9N2boV3GPSy z)8w&EMQJO#)3wQCop0l?XGv_KxX{MkXyYEWaocR19xq|fQIh|jBeMQAcrC7->wSQ( zRdd;MWG|HmjEx?IGYS*vC0jG1D|b@Yma~C@FnJZiBrAd^y$N`A{c*vWPliv{Y$Hz-GnNx*iESR zFC~?9J~gn+>|ZjL8F~;zeqr<2+XkkqY`XVhQc`6nOys8|i`>@%Qw+~0X&hxipi~(O zTeno8RG~~D?IC#ogE!FL42KrOj$G-s=Msz=4pqT)cSw6x_xHf=2!tOfRTwA6VK5+X za8-}J#Pa_$se+v9vs5v%+eno{oi_8$I?u;^TgU-E;iZfzKev?m0kxa?ht6vU2hov$ z$M6$y0boDCt$;CroVSbxya#XqAeT-&fNZ1(0)7lQ2=Ft&A%NtEp@3fl#shL*G666K zF--*IkZ3R<%WfFIVgC$XC1q$*QidiaWu6rrr3_6<$|yQY8AV4aqi~cm3P&lUaFj9% zcaM#`-^RUUHK;uy`Lh@37o9_cphs!q=D$u!4CO6*PLY6UQCR{V(zl5XvZdf zEL825?`_L43ugk}Bq|~bsI;}fm}eaftaMVyfPr0s(_z#72OfU5w<03Hu`I3V-j2tda1MZ9X~J56fm zJ53%d1?;A9W3Y}{{T#@Rv47-Hr;fITykUFXr9DRXR_ibe}zrrO3x0@!Ad zLCA1PaxhY{WE;M71cy?Qc7zn>IT;4BB<=VFvLqQg(B4pcVK+IXy~C21!hT8sOEOHd zJa5I zkkBEkx?ZlMO2>lLL!Y=Lmyas)@l{ub{>yyoeKflO_tVgs4} zixBpP>GNQBPk_C<^OO&}yF%KN71UfZ=ez?uPmB{Q#ZPz-36RrzBG#N<45}E)XE^M$ zgyxOc*a_I)QbJvQJ~>t?V=ZKt>sTc-i9*xwbQ6zNGUq}ctK{laGHm~Y5Q=eGNJDi? z3zTd1xkj?&I`Epul+_?0d>Wa9ip2^!8!!#905Auz2#`bKxqxc{%K$G2tN`TF)B?ae z02czXjE)2R5^xFNcYxJ^%>Si;%+r71RUIIjR0oJAk98GFP~ooACXdD4BAU*|ITg3} z-pa(lDodRg*s_s?IbIyxN9|BMYhBd?iXh#S7>7zM*$^BBQ!U;ks|5f5!W$!phnP#w ztR*STW6UTvc~~dnV2Z{|SRq*dX$(^**#5G^%E#^A^mO(B&wTzvKtsSV>Gu-6hX(LG zmO~x(L95W-;1j+Fsr~f5K`?8g0bF?~n3WMGD>t<0Dd%Nb>wI->rm|5p95<%2c98#; z&a1BXp{7nthm>GaQ0pVp7?(ODiX(O3eemsP4i-WcMN|?(nP)~O;j*yqJmKq6^xpwV74aKYzd!n<9r8(K)S%~ia76L6 zf2xOh-a9LqW9vIg$PL2Ye!{3pCac#1@y~|a2Mr?lntw8|C z1y$fwU1lb0;udEXK%@A}n!iyR`R8x*fenn5bB!_xdoo~}z=81*2+kh|#_l1FF#)N6 zln+y2&*{E`TEbfP4Lmug`zD@scs`0}Bc6}rc?O<8!1H1}e}w0yc>WmATk(7f&pYsZ z7SE^g{1u*@_xu{q=kWXuo~(th<4@H>zNuQsH+2|S!QO{5Rj|AD+hpfsF6{rOT6pyT z*R{}Q`2Tt>TtCz^(*3`z8U|NZa@E3@QA=10U&E8N@DF&h7XArO*1|XN zWG(zFo~(s`$CI`2Z9G{E|Ai-O;e;|(3oGzsEu4hsb9h$b$y)el{Ha>VH&qMyR!Nr} zf}Je(Its>GsOVS=70j-MMI2uF9GK@gyfW7rnRxMebJ5)yn>a=E>JQ%6I=^i_`atYI zpFI6*LzVAe@m3Xh*j*paq@dfoO8U$ztUmL~*1cDb{$X1Zqq$d)E+)XXO(2Dlj#&Ur zz3=sx5toyB-(xh;E7U1+5HcBm6P-=?&*D;@;!ox6ITu!jx3}SS3%edXUMv7VsWj~r^PVh7RC@b)F0#W}= z*^ht9-ei0&c|~Do+sdWCY~qac@~}r;mLA36wk}>JQ~lB<9RHe z_u{!2Po7*^jwdVfDm;IO=ka*5d``lXa{mYZ)KV$m)KV$mD&>65KLy5$%eP906B%HNGAEB{tJ zS^2l&$;#i0Co6vlWvMDZ-&E!2Tcz_Ruq6Wfi+-!5cOMBcnf`p_tX?nTPF3d=&F!TGZH%kI%ySv{`V5Tz2;QS7(@W^Ei$gaD%m4 zoN66;@q5aKXKdr%qU8c*vUa$#X8x7sk54QkQlGzvV-w|Jk*oaN6`3ekY^e_VRD7$q z^?2*T-z;Z~3mbFaK7==xT<(?a`+;GU9FXwGIqgI|30r}`5&drC&78IYxJ*vG>a;nh zo(6dbJ7vbnIH(uL20CS$t_=+gb`Omxk0MNm`6;gQg-&_A)9G}lNNwUZaE4u$pGAX6 z_3Y_(_hm{E;rI?ij@HRBdo`y7zPke7T)*MZbiJznU7>*TpYmW6#DU7W0>K^)>H}r8 z6Hk`IE<79X+>K`n&-dclkLP)KvW&*?@g(ny@Z_Q6i}Ab}&r9*V1J5h){3xDR z;(0HgSK&!Xm7|>0D4K6-6wNoa2c%%!15z;V0Vx>wfD~+t3!{mgg6(i&dtBIcF6<^3 z#!`l7tg1mgL(Us}ah#!wDp@&3sf1>txPes*5YwEBDlSBDWCkjPE2%2gwB&IPX*G`t z0Ui@`@F>?jDl8tQ7LQ67UQ)&PDd5g{W=aZFTBo`+Di0+({^=UN&Y3V9WyEY)zf3xj ziG-V)YQvGnOthsfmW;P#+Lk)4c@S&XIB%->xIjbM9Fv!CA|7v2jQEC-BGdhJxcB4@ z7io%yTUryDwaIvELZ`$Ad1;ufd71KI&EX%*hw>{&`Rq>`l+RpETbn!Ha3mdT3#Vhq zek9(Kj&4XJ=4_xB_dLz7J~uyGuCbO>I@}V82Bd1h9?$uK{2YYuV15oJ4f1n{rmb`) z%v^xHDt*)MA(oMPKe*(Lz4cD%%&9mxc__l*AkaYn*80)@PI`WI_7c88;0a!AIXr?( z$ymmOAEw|#Jv-n^6Z*6Yd4*g{77Coa*bbjO+TV}!c3q1{+PA*PY4v@oydA9LXF73~ zuD5;butWZb3!hIm!0U?z-My$bjiS5MgIIVMq{y zffUVDh`4It<~sE~{q4Oydlc4il(0tvKOf7OtdA9twF_vDS5cLGgKf?+ z;K{lPI8VSjl)G0aLe3)Mp+k#3I$yhYoQBUtc-AAzfIN&Yvb8UFN}Z*e&oY+}+Ck9T zar07l#;wAHoRvBZ?~5m0Fb+4Z;KMjpYx)xc^lXdy$DiSk6gnqq`ja*NG^cd-AZW;U zDQ4+M9FHogt(2o1`#+{{-aDY%C_E0`ye7<{xOQ) zJ2O-|vxK$SX>5wsW*WjRbxqMsdSfD*X^5vA9pXaSxYksy!jF#7~be2b+?gafU;=fbByn*KCZyGT_0OCT|7YNuWupe zG)ihE6P5AC5#b=zJoL(5YNtPuJ6dxLfgUr?E}Py}m%)bb@iN-nQKI%sx8t`qNfdHUm}K{(o35D^zu8Rd2G@;$vy%8;BbMs8ati?e3^HR zAUG-bFyIxm;c}G*D6Ma!z)cZ1qzcCLK{ZQu0B(L&MU2CD7{lK&Ov+Tqy22czv46&rXCt%4r_hfx1Y2!b)DrE-SsOp}#EKfZ~`U z3V@Y-?Rg&O-_k!p5S-`j0dMN?d-)vWcqcTIYgVk|Odp>MtS8S4cy*xMfw889KVOH> z-4~(a4r9Qd8F5KQLzrBAz zwF9KDa{30kGCSn1XQqjAya@4_-z>*XNLHG1>v3;S$LMfJW~lp|(e7bn#Q%-l?49RJ zf2Z$?F!IElqU2I54Z$`#*Bmf+ztV#}q@gXCT$$uhvN?cC#uxe0)!pAUH~?BtR%Onh z7yx93xt^xg5=m{deQ=Hy9((Ti&=exV}xnRZgum66>zP%M3*sw+d?ojrp+ zT#{g4smjtQu2;TO992II4a!gMI%k?#R@Yf+DyFPX^yyi48p@n4-R&czLw+6e;-p+} zu;QFjgd7UTsrZ{bRyfelk=jwc_=8_jCT zEmk^;>6d2u($U+!qq`R?_NtxvfW@nrcE;$Z(x*YQkT3eqcI)vI7eHovrhiq>?W~Hs7h`N6n)?`e* z#%QIduX|wB=+b52Rp$8nVA5VLaFov$)n0P!QD(*hI{jA)%->JGUtl=D5mkA(R=&fd zBLg1ndd;i93j-D1hukPIf4g_Hz`S;d>AF>5UERZ-Lp_5dUijNIykm5$$nFmP&AC;^ zt){9hK4{~Hy0>CgdT4hBbx-H(LxRWf1<)>;ohcc7Sm2_UN@+CxM-`mjX)_uj_3<8o zL$-7b2U^w{?5UJ|9B}iS>-fhF5iOj0|C530pH&7KB$|ZoNy~fU30`u6KV5 z`7^&s&bW&)m8E_83GO*X}s*#w_`ofkv59_d> z(_!uM_0yI(U(mE))U;Qj-1Pb?6JM8Xi`8ZH(hFs#*H?qM8iT|7s)tkSE3zhw)kF`j z_|;_UV@+7)6Fk;cJ-k}k+YKuAGcEC!DB2OThVH|)wnQ+gT^p@~UnJByuA}?#;kr75;~KdSmy9;Y z+kn;j!?kQ59#y0z8cAnV45AOygEYxbcK3IB`-7n8SzlaS_~_Fhdc{SVldd{5+zfcPz}^i{f?b2Ouc$j|g; zrA`MH()>3-8l36_u^uOD2dXT{5B;CZPqa|$5pfeOTxzsKp|$=KkN(dMiz7WF1DzO7 zSojL3$Hf!QGT?sG(~yJt>Ao&G%sw8n$7hUBh`aqKveW44~Y(LUu%LzaP?tVcw^KlzBTvAz^Gnp`W<*y zIsH80F7o2{EN5`2dxx`^`xjVSE_o3!^P8(jS6(gkHVJGP_0QHh=^wzP8h^IVy$s%z z#VdS{Wsg}I&Z94NUe)xkY5HZk>kEbv$)<23fx$#;#`{33&@M5)KkD#>*3bV0Ixqfm z=XD+bULD@7)h<9fbvuJ2F-n$%={*p@8hW;F^WYUuTrH*O_LHd~~P(>4^6-1|SV z*1&YKUH!9_w+grZ*(u7OPFoLIo(mv9zh0F&e`R?>FaE~o7(9`oy~I4u-B)=5aLS$K zWOUiTw^HH!L-Y8j=E1d2wskmz!sTyo=!~*eZKnrEPI!VLnaW6R!$VaE9lxqH9 z1ivE;#qDwD81nj_8Fi zai&;!hOdUaZ2Yt!-WPv~*g@OvAj9*I{bV(0S#Ew^FL!2wr(LfMjX!T?&MeT)LtR20 zcE=tNs*Eq)Pb%&(X=>jk>)84!N0IM(8gwac(py+!k8 zeOzMkE@sV{Z7|y&%2VtOu&cxGX2exy(jKW57-=xx*9L#yx_*rnXEE#g<{YwWTkCp; z2M2~ZM_{~*!K=)P?l9}#$KjiCn(^3Dd{<#?jLshCgVa9LGAsW1Xo>Qj6Z@$?^B8gx z;bba`6Yp54iQ(LPY*Uo&HrvG#jjK<_qBs({(ZEYJJQa*A5t=BPSPNZbUC3&JOAI1Yq2;5eGZU9Mr#mPouVnu(<{tt~jQ7RIn%@EGSvy6d6_ zudzDqlQcdNPB);Nj5kXnRlX`U4#`$15pDj97D&ddEuOi#FdIBF;rCXPc^Ve zL$o=pVABjNmUhEV*RZ;Hb2!$b=&CfVDIQTXGab(i6W+*G2V%NrYMd>D{WQ##4ES(P zw4WXetbi_LZ~|RY&x8B%7IsE{2zsNZN=-jl9}TBllhF*cM%K>4k%m~yS|f*$WAK}> zsD~3jQDq)r@Fgyu(ow<;AfG)6o6>h(F)ye z!B`UG_*80rJXx2~qB3P$<iGR%@%3N@C>?yl+X=hCOcwYAZ@Ol>m0K1HojWj4#jr&3L=8zddGU6?6r zEnb?jq;R^qPU*y)EV`!X+HhneSGp4rdy17sr+a^w7KO?uMNrWR!16pN;t=hD?jqdJWTy0BX6Ar>POtrD;~kv8>WzDt9K zHp%4k0QVa>k6%6;wuv$)Sf$$mnR6p?)W%@#r$w8O|vMS-jD-W z1g&qA(*F{EH>V=dA5d8^4Nz?WX~I4l^s7*pbe*u)@}59geZq}V)os#kBy+c~DVI1C z>s2yLJ!Tw<^>#WY30-&t%ad~@*k_7dRzogm49OC^1#OUp^@aSO=-LHDVhL7=#!P)H zqGx)Lf55_#2vh|VhL#vs4+w`G0B?z|$AM*Z7F44Q+JF=aOzLH+;NwkodGL@2!?P-K zldlP_pzwuE08b}du@3>hv3m5?+BB;_~Gvo-~tu0cs)A3BWHlCyo5r^@H>d>6f%vOmjYoL1`tp`jz3+rLMLKSqxUPsKOvqSyEIr-w$dSjO=gVP(#? z$d;|mTZfh}ll{UHTQGZ$;2%SmIJHa%(i7ox%$r9o0B@efHuEEn z&-q@?5u*-Mufv!<2(D!?9O*pzQl~-F$22|9C3AdBd&zv~o*UxnT<27CfR#+ShR_85 zjK3P=B{S|-<9Kh~vJo_}7wX>94u7y5+L|FY%0k9eW6pJ~C;M84t$Fg=X63bHtm3)?xs`P(o~5TwL813KJsa|*XQP##ifIK> z19?!#X}81ljFsCW$c)eeE?*{d;gC})zYd*GxUSphJaz{1XxgYQD~}aZ z3+FFi`N4oMSJrZXRrygbx9EJ0P1*N+ZOxOfZC1Xnm{K@j$LO;Y?CTt-p}Tz$JH(wl z1)$n^!pj6+w;Lx(dpb2dEb+tUSg!@w;k(LFHp(#`-qU@=TEJ&Hk>(8CR%FyMgN!+c zu@1Po2A6*#%eQFo>xnzI2n zzp}A&zgyw~- z^fLj|!Wi>Hq=VxcvoBjMnasbhIY{|nd=NZK*$;SywKvJ{DSB^`GUUF{Ie?iT z_XlJ#zku!1Y_#W0AJaO+dY`M`|LDz;isp5*|W z_RO5AQ~Mc=V-M28a`M)x)m{m4=Vsx&z2Wo6!Hs3%)Y?CJUX%mJ^?u?m$-=2U5aKS& z!l`wA;;zWTsXYneuF8SqehG0`XW>emX&QG;4qTPSU6+OPWOhRquEeR-;cm*pdGfp^ z2hN-w{XiDZJ1cs77S1~xb!Qe%?G-WacV*$cyx*MzXY&4$ESz_yI(oU5$2Q0saPYX7uA&cV?ft8+e|F*rILx-ivRZtHCuKGUq!F-&hkJ z>ehBp7vLNHKF?aoVIUgInZEx*;AUYT2pdhqSZL6ubc)Z#z|G~YIJQZt9$Q=r+UNm!D*<09dq6lVZ>|&3{N4xLQH)E@dMCsN#H8{4z%3%b9Jp(Nt6@0I zd%ctAD*e|3w}Rnv;BEwNHS#^|UaqCaQa1yBvd9vLDro|!$4IvVz6SBomemuJ3UeE9 zbs~#loYCrmou6m6ZNlFHng)~sty?LJ58}JYIgR!QE<5Cc=iS^h^&bLFLeZ#E8H;?V zPtMjGz8?lnTJrB6oAV!9)am~y=r)Kf#;3anbemP2JlG{^{WrkQlCl9r7Y+093BbFg zT>S7)0=^Bh)qcH2Cm#T;*YO+{GW@3j8&qZB#`PdzBaU|;1L-~s*e>||F`n@W`y62B z@?3)(jVg;T06s>z7nQ{SCBQGS@^9b9M}Gef{1wD!-La$ieg*ieC9lRDOu@ej_;t>n zOns&&vn$h`;aNt`(H5f5{~B=auf&|3AKy2_5_fzQ!(qzQw$YKUft~QN#PJ38lLm%5 zySrQ{%9i_AC3<}E4aA4>g+a?fJz1l*As7-YgKq>#3BmZY#&r?w;zXTv5P~2w*ZUUu zFF=SfM~y|(*7)uW{cg@9d>gbifN^fZzsK;+v4%QRI>C7y-)slJ!zUQ>opgLRXCKIe zFpizR=L=uvd|!wEfevr>qQ8r8N6J~+1FHp6<@H10F^3rJ?su!5yAJsy3Cr+oPYch> zc!ra@qvi})e4`de+B>)DcK1<<%L9`33BWFKA|0mwo&y956Gt8bD0Vl~n=dL}Royk)CUbg#q_SU8Q1#@beIzqVAt zWnq~*TBg1u*r^L+DP3)%LQjdCpm11w=O%bES|3ef2P>+_)+$cHx#MYpVdsat23V@c zP!}7Wt%|AQS)t>D83uRGC7wwNW`_R4ALpi+PXiNgMJxlRYjOaGQ(|lFefTK~-xA06 z6}P!q=cej9_Y}$jbq*VIEm*1ds+-inPf zlOC*MdofJ*VAB{hcnF2&Gts8O zeAJNHH03spFD`Bh$|g(7q^rWF)myxX(jru4G0CR0;8K{!c(^|1xF0!0r<0DPj$;Ae98)kIe^VT{z)u!P#Jx@w|M3RL?R8rh3R6k2X`Y@FJFi`M0l-~KkOii6utO-=5B50&q^Hk}+~@!~tc z#!(nRF*?kx;hap_x6QL@WH+oOja|w_JQZWTM%#w|PpAJtn-;~1y})ENfqg!c2TeEM zri(N|gK#oP?UtouIHX`?b&yRLYi((4LACVMLu7uiO`~cy8v@bQLu_0!yxvWQuCLWL z9_6)RV;z=FRMSAcI@HE<8#a+n(v-}sn=G*Lk$Ai@#+^{_EYe|qd^66zVrxB){Z_W* zktjwr?m2{oepfwZ4t_*a4N@k@k%Md4W)C*^ir?`*TAs|pZhxNs13tLCzI@e++L#k7wZH?bE26{N-dgZkD=eCawz(D>%>R9>Db#WJvZSa4 zkJ)J!9{wzCyl=k4@bG8p;(0W{UU?xNcEBzk@!Kmbl7~qaKCl8K_(}_p@cxw+oyW-* zP1b6RrkP^V*sC&3<5UaBa?vX@68|&{7hIiTSlBST`J?=Dtk4LbDvM67(wMQ97e3Ew zjf9_Rg%`T)6&s=3&!VHe@~p-P?JSFyavP6!wnZ!Pv+BBIF)t4+V{f%a<#B&2EXz2E zpKIaW@3+Ju&DBOGt=dJoE+(8!3Uj1QNAMD3@$>v{!;u9MyihtQ8@~b*P^P8?wsVKXD5zoH<{}b99I4w*HrBn^X(PYRwZ}Zu!Vu zu@Zi_tI@6*f86p8f86)^+QuHUW{~M0?d#x~cD9FXH_M#%-jQLom}rp1{TlJYju`%4 zGNZ%ryCcSrkPUIa5gfwhz_BTv#BkcrnhL1G5jWY6Pa$!hQrQ?iM*{tuYVpt>xW@I> z#{SOO67v0I@G^a$*$4I8cNXvCq#9|0{kJjVHfHrA3*un^o#l^2^*=l5kVJgM+5XWO z#@Kk%xRv|9w6Xe~mH%?(s|2&Hcfaqu+3NSZ^t;)!UVylvQF_ywXIa&r^($7~Wv*Rc z@%~r$)A1YwevZ3dD3LKfIX9v#RC$8L^Q-xqE+_hzVts&(o_oZ^Gt^USmmysz{)jM& zqntKzjq!W|Q9Eweb>MWQ4c9of8$Yc)7iavmaulN$%#@D)0lbZm*6`3!yYT@;_(J$# zKWDTDo>slF58+3dJrN83C%_k3zUS#Hp@z2B+VY*}Yd8ja9dzcm!p@bNj4CGy+NrUd zzW|Qol4V+cusKP!;*>yrxV6cgCxxvEVCG!C91f4Sz~qEu$`UQpH;@joUP!h2tr^TW zB4NEcQdUzk|m77FMX311ez>6aXV-h=*x2esa!sZIw9m@lKa07wtT@Xs{UVF?%Bss6j+HB( z6*=kLv}sb+|4%MJi-p2?1dBUd3w{su()fLU8)Yc&rUD{o51&IaqLcajc-!YsRU7Mv z7=3&PaZ(>wbvoIvV}1w6v%T$ugPvd2Qlw)RZ1Tl*7L*21J;Fnc8vth~|ZHQU@AdCCD+c?q8VUZ?Y*_I=u1UzYraJ)iFz{>x$}&GZ{I z1$#O;&5vtB)I8nP{|YOOQ$ntQv366Oe<{}g_gL~Sq!*J#ew}Jcfwqx)L0Gl34g0n{ z^Qh+0Q>=6uy~rUu>O%l*^dMA~K)TFbLes#{=tMe4dbeoVvYmDU?dWubU08{U6}xKP z=Q7>gR6L4s>bM1;0r;Xy&;JI$YbsSc%zDRtw3&dJ-wMBE0?)I`sTe!qeE#8?MhX)C^jdITmH3Ab z!c5xd>$ID*mMZPIm#1fV8^((Ro!ix%>mbm%3m?QTRFzhS0<7_>Du%l)6Jj(B8QMI+l*?R$0PI^Mdy~) zXv56eqy6!{&>9mTfbXNk#yV1K+C9o`k&}QEQJijx#ib7-ti}l^BIX>Bh{UtiUI6u8 z;iQ!xQ*~q+Lo(G)F-@y+9;J_q5xZ5o*!G_6tZ(lb(P1?0fk@99C%tWmts3&o_Tmu0 znjCMue<;2;I~%sZVcSS|pYrELerI_w-~RhFl-B};F~2TddjbuhsS*LOl6^t_l>I5W zLQLwFl&OY+gOuGC-G1Jn+sr>no0;9GE<{?F30=6jZeRe7APaH|b&j^MoX z?62?us5H;zcUv3-NA-OGzp;^+;y!u(yn59c?!7(4zW2x~P!mF_i!aaWLo z5}lVYVc3$Z)!()JMnutYv+$0n?>LU;xO?h#9t}3&v~j(bL)6fF7|BCD;fyChzn1Vw zy~NcZ@7&8*`Ht}$XBcRl40bwIDlhL$CqIBx;w28JO6ViJD~fV*s_|{f-&w;j8@U6l z+NLpQ3=k9~_Z^iiOUB-L2e4QZ&Fpnum$)>9<2aB?c!Bd=iuTXC0QGl;uD?rBf1&2l zmeyv}UHzupvtL;4nSGYej0xE0nK2O8qS$w?l=g~!rRsNA;oENG_-)!a_Hk_Ej+ZcA z8|My33XH)@blW29O{jot;bRI;x>AsetaYh&9Wx{ww|p7)Sb53^C!@4{VDI6li8axk zax$D$?F($S{dg2-yk)JJmBiMvLa4IF8EQWrj*Q^k0}OfKNkEo#Re6++aqT`pi{ln> zjS;PFRmZGM+C8iH=J2{WzLsg7K==So>5?BFYtcH!JS5Rj(O9NV*~8-q(puL~i^8|T zF$5J#Tg+<;rX}R)%utUoOW2T6<2T~o5#F&T?1neQq5n8ek-=VlQWa0T+{l7ag>`6 zIJsDtNjIQZ$%v3BPp3@e%L8XpQl_m|aPCV})v10C{JfUW#;wZI7oUK7ls+4Vo58JHSYK4bEz-lcilHxa z;qcQzZw?4S8NO6%=BWDExbPeMZR9F!po23Rvq;iGiELCAwae8n}B}MzuL*29D!NYtbPw zZxdXYQWen@&3~f7sqRq53P(VPI2Px4?o^dOl{l3>^{)GbZ|J<`nV*Qz#AB>F$Amdf z5Cld@%QV=~)*`M2h!d&?e_N{mhyaFl9ka#UV|@LOA>J{kP2G(JnQ;B71Zl1ldWLZv zoO8}~0U^?m3#`&%;$_}pr6Kp`v0rCjMi|Dv`W|C7#WV5NTk-Pzh^*hb_bNh3l`s1o zU={D}?ixJKo5IgbbVDL$Zj$6kmgQLDC>)1DnRtB$4Fbj>m@Z<7Lwu>m%d`)}D))$` zF6*)YUYz)9+ysroAOqtHbzW_v3q#+8lSO9iRc`o%TX--^oGTf9tG8(IB8orKX z{fOzCq;YUIrVig~U9R-t`lK&f5B8B7KiR{pa2a+M%A+j#VtqtpCUFXdYCEQS;bh~> zq<@+P$4FOXH{IsZfP--Hh&Bg1{Q^4ZgMeP}>AbB|17#9k8D^p(#q3xXn@S)$hM z%=vBZd+2j|?wXuAw=FnzJW{Lr zq#}KonXtUfIcve`d>dUgc{gXRg$5^Xq3Cjm(dd~uXYJuRt`PA_9OjI*ir@2}XU+#PM%vov`FNg6YGm9@u9_B2y&}@J&t9UYogY~l43iXk8 zbsb)yMqVMRw$=NF4skrqwHWrj#>R!~X-y1^wupb;nn#(_Oj?9#87BN?bDUCCJZtOI8^yrZ_ueK~+9&UriaZiN0fW3YW@6o^{I27fi2D4Lc&w6E}*QJ9r z?%0ESY9(5(o4{YMEc;oqmgb5Ia?UARtWPm-r-L7T{%mHtA=@)_`q^JqBlQdLcNF@o zTXcUF2Of8C(ig9+TPE=hUjw5ZeXzEKuCX6U1BS8WK;K|*Hev)k`X1tpQJl45iAdKc++hV6>V>wQD3xz_$;h{#(22C6E+BxnWTZb(I&bX# zyc<7!ztPG_<{ZY{$fUu>iFuJ8KiY7pkQnNyFr|)-Gp0VKef8neW==Q37X}yV>ikah z!Q*KhJ{G$lGmh$3c_dT#CQ#-?VryqZklR`}uW-gj7vM`*NqZJ@^f&xqvEG!(H%8F9 z3`z}t)e7-f4fU0FW~+)9fj!yk50Nc(x%4euDLe=HJ9qf2zU?E#X~l)_gI} z7I-8shr1<@7+(tv?OE9LZRHx)+QQL;(!~l5V@A22YR(AsseDpy$M*G z;h6C?#hOi-`f+v1aJ^YC#h!;RF8G7QBnmx}9s|L@t`84uI(ME1AGABP21WKZeDI~VwIs#T%Au;=@46lLM3l9Nr)lN?a!3uVq;*W81}{Rmah zaW4=~SA+)#aS}aC|_zyr1y0cz?sdNTOHY*?ApcRe*`1N$t=;dsk<>xl8AI;AWNieJSvqCdXVi0O$Vn z`N;9kX_|8L=TdTdX+XPc2J7JstPvKjzGpEmsVv-1}R2<_qgi za>J-ucM@2EyX~A3xgyNH$L@Bft<*0Y?y*BnO75`I?UcPceGBS}mq+xT;A`Wlduuu| zNm#?_2!W+8R6AQ>c{@2G;|35ljHYCe)3C2ZS#RFKvM<+XpH>0R;qr)@y8aN@u^$R z%nWdq* z$c2&EB$smxIQ}LHXTG)apZ=9NnQ$+h@OeLfzTh(&oL|C!#&P256QW9*cD|+v%`Xu< zIy?DIc4Ob>LaI?_{O!>Y$4$@GE`&L=^A7I}h#j_-Qi4Bw;sdW{$39JH=39B6>c;+I z&3P)~Qn7zlLsaZ`Tv$m&T$BV@Ilnslg&VTtVk1x*I@gM8x*ON`fa7nv8y8gDIbI;N zDdF!G`OkmVft*rurJ)n?pQYT^HRqY^*x5XkhGto@&v0X>R`EB(jlB|d=I58{egKz- zUI(6KI{%u=!?NR=B{Z)gF)RcA_H*MpSaaUbjq5l-Ucw(atDK&UuWkuNh%ILfArL#u zlqK?w2VX)U5c_J%9HAlD=<{qh_85uro9$4B{IzLFwp8~AwlqW?Cdpk_J^oa7Tyuqn z={2=-fA_6VbKc)EalKzdvg10Sh`8nn4HIMHI>3ES-MD_HIUnf8_4~YW!J9s0XyQ8Pfx}U3B(__CgN5e5@ZaR?AouN`n)5*t zm#qox1xiDo!GE@KA8mQ)`fSeCLPK3OdU%M-d6FuA=MdoxLT3RWAHkEHl^!ku0Vz}qju4s^$b~7v z!`-)!>bMSfh%MI#T#B9pp1_ThG5`=ZpPnY3NDBWoq}4Zd@;E&PPgIHs_-y z6x(lxdiId}shdufLa2&%Eg;tlO;Co%0$LjSF8;F@ zuejjpFJ;HRNN8%n%INB`ZtQ6t*Rie)cLH)3LXfk+ycP=|<^Uqf(`vCkmWJ%|TI|Mk ziH>Wr8`rHGl3iZM37_*25qqGCqt`u|ov#|9`6u$lwwu4>+_*laIUnc7^=&{{W5{`; z!%IlX301|1uYN5PnyV4}B)svr)Q$Zq9sANO&dWhp z8u|zRvtPe{U3GIdXO6i_Lu25~ev7~5F6UP?=jFngxDbY(mkCXhfa_?TQg|LsmtGCy{2^&X*_53tF_Del`{n)4}Hxj0oq zl^_($Vrt@xQ1T$>HA2&cvM?>csV?U)YR;z$XAn9+2IN9=72qQ{>Mje zJu*A4TA>-S%02AH^=lnh*p2HifV_eb#Isg2MS%+qGt{0jSi*wZFyg+k~W^rCCq29rNwj1C0?R}rf=G-7O zt05ng=Cv;8Rhsi!;S542t|8eP6%#&P_)n78zP8~D*>SBCny(`lEHD0IZd@77Ip)T7 zt{WHo9b00J2w56pD?^e8p85G<*>N=q&DDs@vqk#QR1>WqxrKq|9sK3!?QWJ zWN~hGIp422H)nB<`#3wN9}fT$=c{pvEY5M4^H(+Jcoyf=B-9J|&r-gr<+VGqIVXjt z+A8JKT+UBw&Zh}y5IVorknB=U2_F;J`OlZ$n;lm=E3T9q*FQDqR8}rpCDb4ApXGJ) z%!dES=G-PU8;}dOlKi#0oToGM0x{#3g@9}nNU$!i2edR~;#%tbZgX~A8-!-F71w$< zuBAGz^{&L$>bS_+-)=AkrJ?)rpZR+G-l{{h<(b%U z%V=+Jd??yCII^3;NI(xj9t&DV31sOqC$l}HFYM$k3XLR!a{%nMbt=S=7Yr_DhP%}o zJ%L_8-i<&AEnpQMygFTe+r=?aMxT>IIu}af7p_`SvmE9%v4PH!-b`wDf9INI$b+V? zrMHUyE-!W_8ml)0ooiI8=~O49T=#&;W4Yo4_hV(v3h-y@Tmb}wkG32<}Sk9#bN2VVqSXu@j9?L?uqqlKPyP5xP$gfZG4)> zjNtWpv*#{)4UQeCbTIe19SJdOs$NJEpdQ=1yP~@~x3%|gWjVMBUZw@p$O}XAGxO-7 zM=Ekj95>HQdXy$)fpJ*c_CvI0S&bF@2}?a$y9Y^klg7=V<;IFJxhYw`+K2%u4-iQu zgp2g}P|#PGu+SQ^Vx`H8-{Y4lB&OWwBitZVPV*oeGud&XJrRw9By6u=zWl6YEjN0X zpX&JK9+fUH%j*%#U3gf2w_JUOGTT1Gq*+m|OnBHdGbRC^8x`&U`z8#590^?K|c+BA4y<5bn^ z*^Km-MBjZrRsq-g2}y?}9jE=x;Ar)U3r0tKx|a0zbS%gRE(4Ff_+#h1%?ZsQ%RMJ< z9^TR4*WS~=dF#NyR@4f3NZvd;+_89MsC`Gz@aB=B(f;k5!4|OXn}>%w`M!CeuiD&$I=dOJ-#fNvI=1(BWfXbM5|BA3I&cYf76%fX!cN-tg!^pn=^Ppu z9@sKceN^)3>i8fI3iRxO^>H=N*!A?ndg=ZNr_69VcXsV#GM&y|XVZzBalc_*UE}8C zSJl)kS-NWZ>Xl2DZtg&anR5Ph_AbGll1^t|m$SIOYab=Dqw|ECC4*fZ)r;!~_K`&{ zp@LncdU0$YIkH^#IrKgU+`Mlg-+ic_{?6XfuI^!k%u~#u*xc2%{oS)3N72WRt$ncP zze&(JG*Z2|F0*0vs>~@%@y0@w7u+Z-t{VWup)Z_+!bvve&;#e(g#z{mtqJqSGZd%P zfEWiFmoGa7%^BIYq?c|0U-eD!p$_6^jzIs%E+2 zoq@Yum|@|l2)t>x2tzmmYEqmtwXLzHI&=4Q<`h*M5wt!Lm*lmG!5!09*QCQVt5h|v zufqrvCl_I!lLP@g*4D+0k*7{p%`(YKA{9<}C?vkKdhw>t6L(@@G?W=xjE`RY4X&?y8+yE zJd)GcTvv~?B4QD!Z^eaCBFjRgr_eP1GfAdZs-SC5s9wCYYlVoA&t+gYvKt-Ej=dehm;gs=G?;NV>#<}(zR4y2!!<#HD;!K>jOCB;fde(8`*I5a%ZVvACO|@z?}`RWnZ(8>NQkxN7TOfH zlKL`-qcx?m5DLa^k(y*0!yzFJUev(q!kCQ(kq`xLYA|9k7D7T}tS3E(;M8KWGKNAz zCWlImMWshe#U!mU9unFd7cx+JNN0?Rgbt$iU&>%|YD|edZq}s=Y>>!moO>4xpK-5V zn6LTdzI$P@#uj<|f+_gI7ciJ;b6>$=LRCohHx8p|K3;W-WF4*+s50_E^j zz;J&-KCzwR`hapBO)(iny5Z=BN<2-?2Il<|%y)Mixvi4`IIs*ieYhYd-V%fF2s+K! zUnAkqSCI9|7&;g@@-?AKHNtlF>mqSRS3fKpY^K7{v!p(gja7VBAdC9CleuGvF9(=?#nN8mK*X7&%mFuzQ;j+j-_; zhG7zov?h5anGR_9&D40Eb%L)&Fh^YnX3SL$7#>t8Dr3gT*h!sraT+TF5%$e#tTrD4 z%*B3|B&fG;Bzzg#^PpOa!xL+}8vrWfTB`xc)hksZZ3y6NA7FF|K|F@kYj_h!Y@o zoJcG|w`tfDqo*^9oJ`6k!o+%&;(36Q8kqn!&Esi_5^agWlL>1iamWpDEm62Db|>`F z4e(l!ax)AAW8@;SUT4mPMCK4u92*2fnuw86GKV`E+V9rGE;EgVWEC;;3!FGsVQ@HB zj)-4lSsIZ+KTPoD?me70Q$ZjK1i`8%904`e!@zqjuNl(5EsP6NHU!KVL;>Q~7J49~ z@qM@!S7=E~PAu}olttmOC>gCq8wOWoxAsV#mKFoLWyR2+reS?g?kTBQoDb;U z*2Glq;!ua^m@3oU2vH+22}=cK-dW3X*}E}| zFCy>URmhn|sXihcao*O({;pZfN8#6r$VMVrBwW(6Jede`I+6Z@Ml%j4*bGT;!lpdz zEqM$#D`xQO3d^9DEk(6OpD=#0cH?l9(kB?C=256QprCt3r8#MM2}eH)p;It)ah$_R zKh61Oj6jCaQ1Q~q1hCOd2oo{zH%=L;1x&7B#Qc|~$vcfDcW9^KIRx%rNk{M1aQy}$ z@IGJC{n^l&ZF*4^dcRJ<3u0R))c~iIxMq#c-ozC{AUE+uLgj`cr4wg~6cyYjQf8I6 zoakakKM%cA7rS9tS}}uGpsXs=BGSCuzS2YL*zMFa_YxLq(&r-JPfW&bp9d0Pf60Pq zhHNL?L&)n5vw{7gfCXgWK z-3q>*$35C1{p~2a&IH}VN(q&LMN`5`6mu66zW!Q(+!3`O^N?F}{f#r*uYZ78Ra)!P z_ys`x%OI#-IqrvJ;kZ|Oj#Px8F5nZ8%^2^G5~O!FQF>!m z#w>>vY^Gol;7BE4=--;qmRk%eJ8$zcX|nnWX5d(&;AbZTkEv1VXIQ(fdPFI(Kg`!1 za_H+yL1cC`B$-L06W5I#ga=3B=poydN?w>sRoGTC*@n29!@=0V&hDYa0349)#$F5R zEAmM>^G_=9ufYYLq5@7uM7w?ol;jDjE!xEd`MNaS2>gPCEM7$Dov;)w<|Uwl5-rX; zSSdZ_&q0&JwTg6Wyx`O=NU4;ckyLm!%&U|vqMwqN*B;s9o&O*!s(oz~11-+P^{@ij zV=d+VuZ?vZTQZSmW`qZRdpf%_a2dcMA7>a%332^ReHme^$wrfrva7NhK@%y*>AvxI z?n9q4&iE12%}jayhc$5JNaTaax7SSu8zd%?>O&8=nY85RTW)a$iCM3I$lNkQb=4-D zt{(sdRWPoQup*;c6e06!nKW~}SO~PnJ(NWFdx_9%UA>Z_c+X-Eb9o7sVMzv9rOa9F zHdDJvMQ40&ksq(F$vuu?Kfub9r|vLYT=7EkZBJoRX}Kr>xbd6D2JJ0ZjJ*DePDja~ zv1f8e&&1s$fjF}Y%AN(4MBt`G1ao@Paaf9|#!o6G8-hVmHsYBAHrS%LrX>(*KPypi zAQy~+30Thb<&-u#a&HUS^jsrKI(`j~5|50*C?+l)23>QK`|*UEmcTb~m%4%cU@1ur zTG;Z-06JIG&wl;kpnS9P!?x!kP$f)^ECu!~?2MSvocUxrza+eK+$tq);SvPJa0!hz zS^zeV|8U8{oUJ-{G$1GKs+Wq$b{X&Hg;2O_UYG?NR;2Rg5rd(Dm-m@s498$wMG zKW}Uw-o`glXRe+Qk$nL$HROcI80fDAL|WyB0tVtfjeV;J7j;;r?6Q;wwpzxaSnf+o zr|>6+^HMG8H07MPg_6T)QN|ZUPiqzF0lEXjF#boX*;{wxmOWPMn zrcpUItdjg7J62ux6RMk_G`vxI`|&;xa}K!p!`)X- z`s8&z$p>TQ(_r&|gup-ip0}zO)z(a&Hv2uV{qdw7*E>$Xz?V#@eC2&lpR}a=?eg#Z z?8mpl-uD)PKd|zk%GzgscJud|KE8Fo&Vz1poSzH)tu+^Z?D3;cb>6z9F&KCs!{CSuBVAiCz zw_f?m^cnYEo4nF-ek1T*%MYo(_^;<~Iq4^V9ewME=fY0AyoBj_^?}2`eQnp}XPk2P z17G~zQh|~Fz4W~|Hl90p)W6@0 z>T;pLzkK+^bK5`g-II@;&^z^G|M)w+=-emp)<3>-&SNV_FM0U&KYadxmZL9soTml; z#utyjeEX-5f9}R}7w)O~A%*s~z<+-Jp4Z;H>7&m~*tGnaZ_Ri%={QH0GM$@deYfUA zzhAoI+K)MBJoEbYM;zyDf#2O&S@WUQ&mMlyR~BAAr{W{K9bAD#`fn}0=lbgRMnB

+VjyJ?EJp{^mapcbt<1{-?L5Z+!mjHL)uWdZ0IQ)&=l% z(=G6_e}8TFZznnDJ^IBJl{=0<=ch2i7x-7Emz?(ghX?+7&6|7Mo<8i#PRIFAfxjJ{ zbMoMW=kNO7GY8yx|{oE~kUjFsf$MnG5U*OKt-yW3s z*NZPMj8{Ltd`<>7mg@!n{)eyn+igeQdF)po+|afA1K;{498L&)^}WqoKH7Nb#+QHi zo430Y_k7uLzAf-)k6w4iVYhsL*7X-2dHs)G4FAh<{wDB;zc}%(msU=gf9N0IaIX9N zcffxUY)Gm?%YWH_)P0Y9|MIif^_G3GWX3mOx+?I;-uu+p6P3?={L+7W>i82^{|(lp zR|)*QJHsb^Zt#QUUwB~o%T53J@>`DcS%KHjxM#wYBfkCW(WicF@P_|<=}?%?3;do1 zzj^H0uiSs*c^{bY<14>;(+9Dm2Yb}2&}-Yjapvas!yov-g8dKf`^WuHAUy(KeBD|1 zg&s<-Idc8#^4F(V{~HDY0&jj|>RBKB#EDCOc;e4$Gquy8pLYoS@Atm>eD@LOhr_@9 z@cjPo%vk|B2>i!wFP&L(;M=#iR6bj`=$FX{P%qF%RE18OxHDaSY3Sui&mEdNZ|*6N zI?iH&KY07miM|&eeeQ=Ro&VxAng)30DcM5!C zWGs2YO&#+t|NG?YZ+_@9_$+u#;PZagGWnQ=KmFId_~XADIrZ7g9p`m{&p7F&cY4pb zeN*E*1K+skl0~P$_9&x@H3D7UB!=H{QlRT zJo6JjIr+~YLwWTGyy1brJ^9sdJy-SWc~|t7#-4;h&MgAZF2`>P{De2Z{o+TzbJ$6v zk4&!l!%62q1QU6I-}r~`)D3>GfA#f89=v4t1CRX`uF@-+o+m!@!zt}Eum9ux`#XPp z^PGcY808Cm#fR>AvSLB<_YX$9W=-ln2JK$2z&qL>_|DYlA1-bG+tA|||M5fD!I_7^ z*DQSK)T4j?;m3Zn{%_mcOMZVe>Z!o{c2t%;bJfGwFE0J{BQqOc{t4=fz;_=oc-p7- zKl2mQZ@g^RT|YY#_TE!qYh4v;+H(Glx1Im!jN2ah%1d|L@ZvhhSt0P7OK!XH@t0p* zdF#Osk6qA_hMn_ffq!w`tiN7Wk-q9@|1o;W5pUKaotFrF&l{87td+yaGakA{Kv1K|GuwmIp(;Ze)3BPo$#@?R~+Y` z0zcq07hL+)uSJ@h>o&aB_5LrQUK~D!>3sF>PyPKH_kSie|AVhjedM5T9)R(Qz-PRE z>!UBd^Vf&Yxb^QNJ0|klk70q|d+%+xht8e;@Do?AI&SsY+7CF+2L)dDRQ1(65BkW; z{lERz-%eUJdJ*(W;0q@_|C=NCTXxu&(o=tZ*v6BfQ?CmAou^B;p7W_QKRe;s)mI#Q z_YZ!Dqpz^#t_ofB^mn%Z>f>`}CU+hF_sbT)Fb~%@3Vgz6KAX59vh66h)+cXG9x`{;%n5g#cGlyNPw6zK=NCua`T5H} zeR=Y(vp(|3fgLNy&>soB<)s5J{aEStSna$Ywtn==C8)pa1^(#`H-7Lx|F!3zb)UNF zm5sl@=2*wMK;R2sd@k{)+jn1h!*frhww`|J4;<$Q0>5DD2TqLLchhYf|8wdskIwk+ z*D)>-_>V7JI=koXrz(23~^WYfK6e14=G*)cFWQkZP}NFVKHbj0u0lCf)OM+T7< zjs})_Jzc$p>4pY7`-h9*2T2Zf>w?KARV}TpT}AL49Nsnv{{gEDrx3Aq;NI<`2)lWq zLJ^e48fiRrWNwB>2XU|F@IDrnGA|v3Gi6*$JbtRQ?!yYTFdb-%)7;^~?#|(nA=q6N zq2_}yI4(+KhTD5Hl*{-D73slMIN0teg3?Q=#rxe>4khnlag5P9&`W!H9HJOMb_$*X z?I=#S`-`aI5Ri&<-_qZU%X7PFkUU%8<-EJMh{{8Sd{-5R-RH<~0lAYa^8_z3 z1#&MXv=iN0|HzglJ^j6fI#FD zuD&9g+ky7tMi_A9(c81N7{PR$UEJ6ZvMHPk5V?IfiaPI%h`52BMU?Mw*LE-|sDo6Q z?p>XO1v+Jt^%PMU?5m2Ju^=DAJBpA?PhWSYvk%MKMPwN&Q&br%WmRSJZh9{9av`0G zcxcP)=;_{>!NhB@n7P+bcl)rZzyFO$$JZoj9!I*Qq_BL3qe`KwK|Di_y3z)luukO| zEs8@ku~ZDKa!`w{HM#bPMg}FM!T(ZCOCH=MGCU>(cudT}qg?Z-uy|mJ*yT~_!b__7 zJ_Q)Y!@VY6iNpA(x-=>e20mTG*Ws!NC+iB9d0ZpEOACTusX>Gjhm5ECGz+ zi`tuORptRcpcnT%&5zf`=HSPCnB6RQ1KuxH1NL~%59H?{d;WLbDG$-=vsfkD6 zJIF7cgWorGeiXkp_sU>iMKeoy&_SQd+Z=qu$_U+K|LEY_p@Gps1wR1rDL#0ly}z@& zH`3nQ+kr0E$bj;%a+0`lyRNqvGGH7BBJ3LrD*ybDqo@}=OpNZu|oP@LMM95i0 zJalNWN9Swzj?-}aY9aD4x;TROa+pvp)qIw@e9#U;UUu9yz_C86Fd=894zo&!3C7{3 z6?_=SYE6GafSzqJ|M)ZfkwWJrO@Fec=e0b8pdsI-j(;}T54r&>$62hz2_BiS*FMup3@Rp z<8m4zYh0EcvWDY|J+b)3`2ZMnxL51tGfkGX<+V%JJad~Rt9<1)N>(_ZNwVe@ut=8p z1LnvA^VuTnumMwKq06#E*0lM|kXaT16J+7DpO%|zv<*JI(t1C%C#+{Nl)apHp(OQj z1a+mgbwB}X{#2>CD$p3%;ba+{)u8K&;M~Mowt?!(K!Xoh9BO<%gF}YRXKYB^_=bim z?m}jUlAF03?teh*ekmO=kjOh+-kt4LRr-zuGsLT;$AJpbbj-C zm9Btwyu>j{Eaq|lF2eB|M{JWz``8S**hjqN+Gca$3;93My{eYh>7IE%)04}HpYU-E z_$4jlnCTmN&=THfqffr?!aiU46lI+6$uWm*zAMjwWxj$#rha&)HO3pn#Yq58!`4I2 zI5r`2j#K~gowb7k=0TwZ*q`N^S7A!!9iD8pzYs{~m!~04jz4pUw@(AMS|11vnQ+{c z(&3NMW4tuJ;n8+|Pk(x76!%ne+(%fMvn{e^YxCA2xESWVs04X#6aA z#?jqd+TlZ*w~v|$7Rre7?*zWWQEuRQ#jcr`b_pNya-5^Wh2@_wUrjIx4ju>A7q$k# zUcR;WZUfs-Pp@lNc0rtwUU*`=I%6-n)K%RUJTKTG& zRv=d**IezNviZqTb~y}jynGGme2tawd%lMA?vS+{U{5d4*ZCTovhVr2AWy!=tbAQDrEtEE z!I+PI3)in;HGun3;Mczs2a3?Y7&xwk2E1-JmOFboHM~vY$J*eqT36hN?|zd+=QsZW=b=XWHf#=E)QNGaU-PNWn~P8U*;w;tPj>C)churS~dm*0Do z3X3_A7q(f=ap25S)|5Ghyb`kH9LFWXZS}ryR71+j>?163WfjArOk)eA*5u%EYGA0d zyUT?l{akMd279&wGQYKT{yRck)uI<(d_MftPVw1wSStMV+unYH9$Tu;_I z&hZ>sQ> zGFGmyO$key$8miv_;LMS>o{_|y;f-~(&@FtRoLUT;+fmuwZawhc1_t9=jmGUJJ6ON zoR-5gQZkx=FFMx)uA(dG4_nKsfIDoFLq1p6OnY88*P8!$UalEFzlUp;kGyWHHUFZ# zR%_Yb0(6P0qE9lo+(;b~ReK`M+ zYLGtbn7lM>RM#fMb*gVW)}~9u;q!B2rUBg_$9gQAMgNDpHvx~cs{Y4sCTk}xO-ox! zDKL}*Wh>n%Ws^>lNi%ekj5C=oSQxUk4WvoP(ghKMAfTYK$qu3-;sVMdqM`yK;DRio zAZ{T0B3j&V<^TDdd++<+cQP{xg~#vj`Oott@4e@oyPb2_bMHMjfM1-5^I)6vTXH1)muZCW$1I|~%U*KXX(A2Mx0}nowr{|QV4t|tzMiWPw zLzD9ep48KF2T#*oJy-~trxVTm&d+nuHjw61r4ybi#(}<`)`7O(!S#3@jIyqB@JQb^ zW+e4xf`do=qwrw|PeYjj1DK|a)ea5f$V)TPp>b_5GLMrSoMUZD^0$+N%QbPyu#+7; z`IpD^nZ#4$&}n-;ntxLqcmV@T5`Jnf-Kf_ob)DGRp(DQv7%Y-Fr#ZCbTQS<{4y|uV zQXCi-V_(bMZ4Byl3gq$aYr;=bJUt@y>E^zAaXb+s(oG*77uNwuAF6 zwrSk%4$gVqQ0np?L7bl*lh-{Ryw6YPkw`N(MuK#sY@@MW?G>c44}fbldZU^9$+StgRgC*^C-*Tq*#SpsBOg**B_21I694(gs6 z|5aw+=`#3n!x{GhwC;!c_1UTkj}>_Ton@{ga87wlq3>v-Hbs1-n(is>SH-`E7jzCK@UPa*e6*Bz24*3Y$bA!AAnGp{?P%gf{1*>nXuWg97!u-#;Xr-P*Z&WnCX!Bad zy?Uq{rLJ6$vOqtR&xDN(%6SkdU7>x_fR$6!Wp2sg>`$~QO}?|faUYKL&FIXkZSQV~WZr1gP{zz3Xk3Pyi49ju@VD>k+D(_|>8&|a#7RA<8hxf(!irHu-H|XV z<3$YUZ&}7Kn>da$?VbIFQnB7n({^tHz6^V!WHvi}sW1Kta5%Gu zAxguTKg#50!0oSQ9D5j>3-m!ZBA(gUm!)Asnf{#>?Fv8hbS>m-4p{S-`#1UI!hK!4!Kp

m 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%0A@bJJecT4a=CqPBi7D@Tira$rBr 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 1200 +#pragma warning(push) +#endif +#pragma warning (disable:4201) +#pragma warning(disable:4214) // named type definition in parentheses + +//! User defined handle context space, see \ref LibK_GetContext. +typedef INT_PTR KLIB_USER_CONTEXT; + +//! KUSB control setup packet. +/*! +* This union structure is identical in size to a \ref WINUSB_SETUP_PACKET, +* but provides additional field accessors. (see \ref libusbk.h for structure details) +*/ +typedef union _KUSB_SETUP_PACKET +{ + UCHAR Bytes[8]; + USHORT Words[4]; + struct + { + //! Request value + struct + { + UCHAR Recipient: 2; + UCHAR Reserved: 3; + UCHAR Type: 2; + UCHAR Dir: 1; + } BmRequest; + + //! Request type value + UCHAR Request; + + //! wValue + USHORT Value; + + //! wIndex + USHORT Index; + + //! wLength ushort value + USHORT Length; + }; + struct + { + struct + { + UCHAR b0: 1; + UCHAR b1: 1; + UCHAR b2: 1; + UCHAR b3: 1; + UCHAR b4: 1; + UCHAR b5: 1; + UCHAR b6: 1; + UCHAR b7: 1; + } BmRequestBits; + + struct + { + UCHAR b0: 1; + UCHAR b1: 1; + UCHAR b2: 1; + UCHAR b3: 1; + UCHAR b4: 1; + UCHAR b5: 1; + UCHAR b6: 1; + UCHAR b7: 1; + } RequestBits; + + UCHAR ValueLo; + UCHAR ValueHi; + UCHAR IndexLo; + UCHAR IndexHi; + UCHAR LengthLo; + UCHAR LengthHi; + }; +} KUSB_SETUP_PACKET; +// setup packet is eight bytes -- defined by spec +C_ASSERT(sizeof(KUSB_SETUP_PACKET) == 8); + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +//! Base handle type for all library handles, See \ref KLIB_HANDLE_TYPE. +typedef void* KLIB_HANDLE; + +//! Opaque UsbK handle, see \ref UsbK_Init. +typedef KLIB_HANDLE KUSB_HANDLE; + +//! Opaque LstK handle, see \ref LstK_Init. +typedef KLIB_HANDLE KLST_HANDLE; + +//! Opaque HotK handle, see \ref HotK_Init. +typedef KLIB_HANDLE KHOT_HANDLE; + +//! Opaque OvlK handle, see \ref OvlK_Acquire. +typedef KLIB_HANDLE KOVL_HANDLE; + + +//! Opaque OvlPoolK handle, see \ref OvlK_Init. +typedef KLIB_HANDLE KOVL_POOL_HANDLE; + +//! Opaque StmK handle, see \ref StmK_Init. +typedef KLIB_HANDLE KSTM_HANDLE; + +//! Handle type enumeration. +typedef enum _KLIB_HANDLE_TYPE +{ + //! Hot plug handle. \ref KHOT_HANDLE + KLIB_HANDLE_TYPE_HOTK, + + //! USB handle. \ref KUSB_HANDLE + KLIB_HANDLE_TYPE_USBK, + + //! Shared USB handle. \ref KUSB_HANDLE + KLIB_HANDLE_TYPE_USBSHAREDK, + + //! Device list handle. \ref KLST_HANDLE + KLIB_HANDLE_TYPE_LSTK, + + //! Device info handle. \ref KLST_DEVINFO_HANDLE + KLIB_HANDLE_TYPE_LSTINFOK, + + //! Overlapped handle. \ref KOVL_HANDLE + KLIB_HANDLE_TYPE_OVLK, + + //! Overlapped pool handle. \ref KOVL_POOL_HANDLE + KLIB_HANDLE_TYPE_OVLPOOLK, + + //! Pipe stream handle. \ref KSTM_HANDLE + KLIB_HANDLE_TYPE_STMK, + + //! Max handle type count. + KLIB_HANDLE_TYPE_COUNT +} KLIB_HANDLE_TYPE; + +//! Function typedef for \ref LibK_SetCleanupCallback. +typedef INT KUSB_API KLIB_HANDLE_CLEANUP_CB (_in KLIB_HANDLE Handle, _in KLIB_HANDLE_TYPE HandleType, _in KLIB_USER_CONTEXT UserContext); + +//! libusbK verson information structure. +typedef struct _KLIB_VERSION +{ + //! Major version number. + INT Major; + + //! Minor version number. + INT Minor; + + //! Micro version number. + INT Micro; + + //! Nano version number. + INT Nano; +} KLIB_VERSION; +//! Pointer to a \copybrief KLIB_VERSION +typedef KLIB_VERSION* PKLIB_VERSION; + +/*! @} */ +#endif + +#ifndef _LIBUSBK_ISOK_TYPES +/*! \addtogroup isok +* @{ +*/ + + +//! Callback function typedef for \ref IsoK_EnumPackets +typedef BOOL KUSB_API KISO_ENUM_PACKETS_CB (_in UINT PacketIndex, _in PKISO_PACKET IsoPacket, _in PVOID UserState); + +/*! @} */ +#endif + +#ifndef _LIBUSBK_LSTK_TYPES + +/*! \addtogroup lstk +* @{ +*/ + +//! Allocated length for all strings in a \ref KLST_DEVINFO structure. +#define KLST_STRING_MAX_LEN 256 + +//! Device list sync flags. +/*! +* These sync flags are also use by the hot plug module to indicate device +* arrival/removal notifications: +* - \b DeviceArrival = KLST_SYNC_FLAG_ADDED +* - \b DeviceRemoval = KLST_SYNC_FLAG_REMOVED +*/ +typedef enum _KLST_SYNC_FLAG +{ + //! Cleared/invalid state. + KLST_SYNC_FLAG_NONE = 0L, + + //! Unchanged state, + KLST_SYNC_FLAG_UNCHANGED = 0x0001, + + //! Added (Arrival) state, + KLST_SYNC_FLAG_ADDED = 0x0002, + + //! Removed (Unplugged) state, + KLST_SYNC_FLAG_REMOVED = 0x0004, + + //! Connect changed state. + KLST_SYNC_FLAG_CONNECT_CHANGE = 0x0008, + + //! All states. + KLST_SYNC_FLAG_MASK = 0x000F, +} KLST_SYNC_FLAG; + +//! Common usb device information structure +typedef struct _KLST_DEV_COMMON_INFO +{ + //! VendorID parsed from \ref KLST_DEVINFO::DeviceID + INT Vid; + + //! ProductID parsed from \ref KLST_DEVINFO::DeviceID + INT Pid; + + //! Composite interface number parsed from \ref KLST_DEVINFO::DeviceID. Set to \b -1 for devices that do not have the composite parent driver. + INT MI; + + // An ID that uniquely identifies a USB device. + CHAR InstanceID[KLST_STRING_MAX_LEN]; + +} KLST_DEV_COMMON_INFO; +//! Pointer to a \c KLST_DEV_COMMON_INFO structure. +typedef KLST_DEV_COMMON_INFO* PKLST_DEV_COMMON_INFO; + +//! Semi-opaque device information structure of a device list. +/*! +* +* \attention This structure is semi-opaque. +* +*/ +typedef struct _KLST_DEVINFO +{ + //! Common usb device information + KLST_DEV_COMMON_INFO Common; + + //! Driver id this device element is using + INT DriverID; + + //! Device interface GUID + CHAR DeviceInterfaceGUID[KLST_STRING_MAX_LEN]; + + //! Device instance ID. + /*! + * A Device instance ID has the following format: + * [enumerator]\[enumerator-specific-device-ID]\[instance-specific-ID] + * - [enumerator] + * - For USB device, the enumerator is always \c USB + * - [enumerator-specific-device-ID] + * - Contains the vendor and product id (VID_xxxx&PID_xxxx) + * - If present, contains the usbccgp (windows composite device layer) interface number (MI_xx) + * - [instance-specific-ID] + * - If the device is composite, contains a unique interface ID generated by Windows. + * - If the device is not composite and has a serial number, contains the devices serial number. + * - If the device does not have a serial number, contains a unique ID generated by Windows. + */ + CHAR DeviceID[KLST_STRING_MAX_LEN]; + + //! Class GUID. + CHAR ClassGUID[KLST_STRING_MAX_LEN]; + + //! Manufacturer name as specified in the INF file. + CHAR Mfg[KLST_STRING_MAX_LEN]; + + //! Device description as specified in the INF file. + CHAR DeviceDesc[KLST_STRING_MAX_LEN]; + + //! Driver service name. + CHAR Service[KLST_STRING_MAX_LEN]; + + //! Unique identifier. + CHAR SymbolicLink[KLST_STRING_MAX_LEN]; + + //! physical device filename used with the Windows \c CreateFile() + CHAR DevicePath[KLST_STRING_MAX_LEN]; + + //! libusb-win32 filter index id. + INT LUsb0FilterIndex; + + //! Indicates the devices connection state. + BOOL Connected; + + //! Synchronization flags. (internal use only) + KLST_SYNC_FLAG SyncFlags; + + INT BusNumber; + + INT DeviceAddress; + + //! If the the device is serialized, represents the string value of \ref USB_DEVICE_DESCRIPTOR::iSerialNumber. For Devices without a \b iSerialNumber, represents the unique \b InstanceID assigned by \b Windows. + CHAR SerialNumber[KLST_STRING_MAX_LEN]; + +} KLST_DEVINFO; +//! Pointer to a \ref KLST_DEVINFO structure. (semi-opaque) +typedef KLST_DEVINFO* KLST_DEVINFO_HANDLE; + +//! Device list initialization flags. +typedef enum _KLST_FLAG +{ + //! No flags (or 0) + KLST_FLAG_NONE = 0L, + + //! Enable listings for the raw device interface GUID \b only. {A5DCBF10-6530-11D2-901F-00C04FB951ED} + KLST_FLAG_INCLUDE_RAWGUID = 0x0001, + + //! List all libusbK devices including those not currently connected. + KLST_FLAG_INCLUDE_DISCONNECT = 0x0002, + +} KLST_FLAG; + +//! Device list/hot-plug pattern match structure. +/*! +* \fixedstruct{1024} +* +* These ansi char strings are used to specify which devices should be included in a device list. +* All strings file pattern match strings allowing asterisk or question mark chars as wildcards. +* +*/ +typedef struct _KLST_PATTERN_MATCH +{ + //! Pattern match a device instance id. + CHAR DeviceID[KLST_STRING_MAX_LEN]; + + //! Pattern match a device interface guid. + CHAR DeviceInterfaceGUID[KLST_STRING_MAX_LEN]; + + //! Pattern match a symbolic link. + CHAR ClassGUID[KLST_STRING_MAX_LEN]; + + //! fixed structure padding. + UCHAR z_F_i_x_e_d[1024 - KLST_STRING_MAX_LEN * 3]; + +} KLST_PATTERN_MATCH; +C_ASSERT(sizeof(KLST_PATTERN_MATCH) == 1024); + +//! Pointer to a \ref KLST_PATTERN_MATCH structure. +typedef KLST_PATTERN_MATCH* PKLST_PATTERN_MATCH; + +//! Device list enumeration function callback typedef. +/*! +* +* \param DeviceList +* The device list \c DeviceInfo belongs to +* +* \param DeviceInfo +* Device information +* +* \param Context +* User context that was passed into \ref LstK_Enumerate +* +* Use this typedef as a prototype for an enumeration function with \ref LstK_Enumerate. +* +*/ +typedef BOOL KUSB_API KLST_ENUM_DEVINFO_CB ( + _in KLST_HANDLE DeviceList, + _in KLST_DEVINFO_HANDLE DeviceInfo, + _in PVOID Context); + +/*! @} */ + +#endif + +#ifndef __USB_H__ + +#include + +/*! \addtogroup libk +* @{ +*/ + +//! Maximum value that can be added to the current start frame. +#define USBD_ISO_START_FRAME_RANGE 1024 + + +//! bmRequest.Dir +typedef enum _BMREQUEST_DIR +{ + BMREQUEST_DIR_HOST_TO_DEVICE = 0, + BMREQUEST_DIR_DEVICE_TO_HOST = 1, +} BMREQUEST_DIR; + +//! bmRequest.Type +typedef enum _BMREQUEST_TYPE +{ + //! Standard request. See \ref USB_REQUEST_ENUM + BMREQUEST_TYPE_STANDARD = 0, + + //! Class-specific request. + BMREQUEST_TYPE_CLASS = 1, + + //! Vendor-specific request + BMREQUEST_TYPE_VENDOR = 2, +} BMREQUEST_TYPE; + +//! bmRequest.Recipient +typedef enum _BMREQUEST_RECIPIENT +{ + //! Request is for a device. + BMREQUEST_RECIPIENT_DEVICE = 0, + + //! Request is for an interface of a device. + BMREQUEST_RECIPIENT_INTERFACE = 1, + + //! Request is for an endpoint of a device. + BMREQUEST_RECIPIENT_ENDPOINT = 2, + + //! Request is for a vendor-specific purpose. + BMREQUEST_RECIPIENT_OTHER = 3, +} BMREQUEST_RECIPIENT; + +//! Maximum length (in bytes) of a usb string. USB strings are always stored in wide-char format. +#define MAXIMUM_USB_STRING_LENGTH 255 + +//! Values for the bits returned by the \ref USB_REQUEST_GET_STATUS request. +typedef enum _USB_GETSTATUS +{ + //! Device is self powered + USB_GETSTATUS_SELF_POWERED = 0x01, + + //! Device can wake the system from a low power/sleeping state. + USB_GETSTATUS_REMOTE_WAKEUP_ENABLED = 0x02 +} USB_GETSTATUS; + +//! Standard USB descriptor types. For more information, see section 9-5 of the USB 3.0 specifications. +typedef enum _USB_DESCRIPTOR_TYPE +{ + //! Device descriptor type. + USB_DESCRIPTOR_TYPE_DEVICE = 0x01, + + //! Configuration descriptor type. + USB_DESCRIPTOR_TYPE_CONFIGURATION = 0x02, + + //! String descriptor type. + USB_DESCRIPTOR_TYPE_STRING = 0x03, + + //! Interface descriptor type. + USB_DESCRIPTOR_TYPE_INTERFACE = 0x04, + + //! Endpoint descriptor type. + USB_DESCRIPTOR_TYPE_ENDPOINT = 0x05, + + //! Device qualifier descriptor type. + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER = 0x06, + + //! Config power descriptor type. + USB_DESCRIPTOR_TYPE_CONFIG_POWER = 0x07, + + //! Interface power descriptor type. + USB_DESCRIPTOR_TYPE_INTERFACE_POWER = 0x08, + + //! Interface association descriptor type. + USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION = 0x0B, +} USB_DESCRIPTOR_TYPE; + +//! Makes \c wValue for a \ref USB_REQUEST_GET_DESCRIPTOR or \ref USB_REQUEST_SET_DESCRIPTOR request. +#define USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(d, i) \ + ((USHORT)((USHORT)d<<8 | i)) + +//! Endpoint type mask for the \c bmAttributes field of a \ref USB_ENDPOINT_DESCRIPTOR +#define USB_ENDPOINT_TYPE_MASK 0x03 + +//! Indicates a control endpoint +#define USB_ENDPOINT_TYPE_CONTROL 0x00 + +//! Indicates an isochronous endpoint +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 + +//! Indicates a bulk endpoint +#define USB_ENDPOINT_TYPE_BULK 0x02 + +//! Indicates an interrupt endpoint +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +//! Config power mask for the \c bmAttributes field of a \ref USB_CONFIGURATION_DESCRIPTOR +#define USB_CONFIG_POWERED_MASK 0xc0 + +//! Values used in the \c bmAttributes field of a \ref USB_CONFIGURATION_DESCRIPTOR +enum USB_CONFIG_BM_ATTRIBUTE_ENUM +{ + //! The device is powered by it's host. + USB_CONFIG_BUS_POWERED = 0x80, + + //! The device has an external power source. + USB_CONFIG_SELF_POWERED = 0x40, + + //! The device is capable of waking the the host from a low power/sleeping state. + USB_CONFIG_REMOTE_WAKEUP = 0x20, +}; + +//! Endpoint direction mask for the \c bEndpointAddress field of a \ref USB_ENDPOINT_DESCRIPTOR +#define USB_ENDPOINT_DIRECTION_MASK 0x80 + +//! Endpoint address mask for the \c bEndpointAddress field of a \ref USB_ENDPOINT_DESCRIPTOR +#define USB_ENDPOINT_ADDRESS_MASK 0x0F + +//! Tests the \c bEndpointAddress direction bit. TRUE if the endpoint address is an OUT endpoint. (HostToDevice, PC Write) +/*! +* \param addr \c bEndpointAddress field of a \ref USB_ENDPOINT_DESCRIPTOR +*/ +#define USB_ENDPOINT_DIRECTION_OUT(addr) (!((addr) & USB_ENDPOINT_DIRECTION_MASK)) + +//! Tests the \c bEndpointAddress direction bit. TRUE if the endpoint address is an IN endpoint. (DeviceToHost, PC Read) +/*! +* \param addr \c bEndpointAddress field of a \ref USB_ENDPOINT_DESCRIPTOR +*/ +#define USB_ENDPOINT_DIRECTION_IN(addr) ((addr) & USB_ENDPOINT_DIRECTION_MASK) + +//! USB defined request codes +/* +* see Chapter 9 of the USB 2.0 specification for +* more information. +* +* These are the correct values based on the USB 2.0 specification. +*/ +enum USB_REQUEST_ENUM +{ + //! Request status of the specific recipient + USB_REQUEST_GET_STATUS = 0x00, + + //! Clear or disable a specific feature + USB_REQUEST_CLEAR_FEATURE = 0x01, + + //! Set or enable a specific feature + USB_REQUEST_SET_FEATURE = 0x03, + + //! Set device address for all future accesses + USB_REQUEST_SET_ADDRESS = 0x05, + + //! Get the specified descriptor + USB_REQUEST_GET_DESCRIPTOR = 0x06, + + //! Update existing descriptors or add new descriptors + USB_REQUEST_SET_DESCRIPTOR = 0x07, + + //! Get the current device configuration value + USB_REQUEST_GET_CONFIGURATION = 0x08, + + //! Set device configuration + USB_REQUEST_SET_CONFIGURATION = 0x09, + + //! Return the selected alternate setting for the specified interface + USB_REQUEST_GET_INTERFACE = 0x0A, + + //! Select an alternate interface for the specified interface + USB_REQUEST_SET_INTERFACE = 0x0B, + + //! Set then report an endpoint's synchronization frame + USB_REQUEST_SYNC_FRAME = 0x0C, +}; + +//! USB defined class codes +/*! +* see http://www.usb.org/developers/defined_class for more information. +* +*/ +enum USB_DEVICE_CLASS_ENUM +{ + //! Reserved class + USB_DEVICE_CLASS_RESERVED = 0x00, + + //! Audio class + USB_DEVICE_CLASS_AUDIO = 0x01, + + //! Communications class + USB_DEVICE_CLASS_COMMUNICATIONS = 0x02, + + //! Human Interface Device class + USB_DEVICE_CLASS_HUMAN_INTERFACE = 0x03, + + //! Imaging class + USB_DEVICE_CLASS_IMAGING = 0x06, + + //! Printer class + USB_DEVICE_CLASS_PRINTER = 0x07, + + //! Mass storage class + USB_DEVICE_CLASS_STORAGE = 0x08, + + //! Hub class + USB_DEVICE_CLASS_HUB = 0x09, + + //! vendor-specific class + USB_DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF, +}; + +//! A structure representing the standard USB device descriptor. +/*! +* This descriptor is documented in section 9.6.1 of the USB 2.0 specification. +* All multiple-byte fields are represented in host-endian format. +*/ +typedef struct _USB_DEVICE_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! USB specification release number in binary-coded decimal. + /*! + * A value of 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. + */ + USHORT bcdUSB; + + //! USB-IF class code for the device + UCHAR bDeviceClass; + + //! USB-IF subclass code for the device + UCHAR bDeviceSubClass; + + //! USB-IF protocol code for the device + UCHAR bDeviceProtocol; + + //! Maximum packet size for control endpoint 0 + UCHAR bMaxPacketSize0; + + //! USB-IF vendor ID + USHORT idVendor; + + //! USB-IF product ID + USHORT idProduct; + + //! Device release number in binary-coded decimal + USHORT bcdDevice; + + //! Index of string descriptor describing manufacturer + UCHAR iManufacturer; + + //! Index of string descriptor describing product + UCHAR iProduct; + + //! Index of string descriptor containing device serial number + UCHAR iSerialNumber; + + //! Number of possible configurations + UCHAR bNumConfigurations; + +} USB_DEVICE_DESCRIPTOR; +//! pointer to a \c USB_DEVICE_DESCRIPTOR +typedef USB_DEVICE_DESCRIPTOR* PUSB_DEVICE_DESCRIPTOR; + +//! A structure representing the standard USB endpoint descriptor. +/*! +* This descriptor is documented in section 9.6.3 of the USB 2.0 specification. +* All multiple-byte fields are represented in host-endian format. +*/ +typedef struct _USB_ENDPOINT_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! The address of the endpoint described by this descriptor. + /*! + * - Bits 0:3 are the endpoint number + * - Bits 4:6 are reserved + * - Bit 7 indicates direction + */ + UCHAR bEndpointAddress; + + //! Attributes which apply to the endpoint when it is configured using the bConfigurationValue. + /*! + * - Bits 0:1 determine the transfer type. + * - Bits 2:3 are only used for isochronous endpoints and refer to sync type. + * - Bits 4:5 are also only used for isochronous endpoints and refer to usage type. + * - Bits 6:7 are reserved. + */ + UCHAR bmAttributes; + + //! Maximum packet size this endpoint is capable of sending/receiving. + USHORT wMaxPacketSize; + + //! Interval for polling endpoint for data transfers. + UCHAR bInterval; + +} USB_ENDPOINT_DESCRIPTOR; +//! pointer to a \c USB_ENDPOINT_DESCRIPTOR +typedef USB_ENDPOINT_DESCRIPTOR* PUSB_ENDPOINT_DESCRIPTOR; + +//! A structure representing the standard USB configuration descriptor. +/* +* +* This descriptor is documented in section 9.6.3 of the USB 2.0 specification. +* All multiple-byte fields are represented in host-endian format. +* +*/ +typedef struct _USB_CONFIGURATION_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! Total length of data returned for this configuration + USHORT wTotalLength; + + //! Number of interfaces supported by this configuration + UCHAR bNumInterfaces; + + //! Identifier value for this configuration + UCHAR bConfigurationValue; + + //! Index of string descriptor describing this configuration + UCHAR iConfiguration; + + //! Configuration characteristics + UCHAR bmAttributes; + + //! Maximum power consumption of the USB device from this bus in this configuration when the device is fully operation. + /*! + * Expressed in units of 2 mA. + */ + UCHAR MaxPower; +} USB_CONFIGURATION_DESCRIPTOR; +//! pointer to a \c USB_CONFIGURATION_DESCRIPTOR +typedef USB_CONFIGURATION_DESCRIPTOR* PUSB_CONFIGURATION_DESCRIPTOR; + +//! A structure representing the standard USB interface descriptor. +/*! +* This descriptor is documented in section 9.6.5 of the USB 2.0 specification. +* All multiple-byte fields are represented in host-endian format. +*/ +typedef struct _USB_INTERFACE_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! Number of this interface + UCHAR bInterfaceNumber; + + //! Value used to select this alternate setting for this interface + UCHAR bAlternateSetting; + + //! Number of endpoints used by this interface (excluding the control endpoint) + UCHAR bNumEndpoints; + + //! USB-IF class code for this interface + UCHAR bInterfaceClass; + + //! USB-IF subclass code for this interface + UCHAR bInterfaceSubClass; + + //! USB-IF protocol code for this interface + UCHAR bInterfaceProtocol; + + //! Index of string descriptor describing this interface + UCHAR iInterface; + +} USB_INTERFACE_DESCRIPTOR; +//! pointer to a \c USB_INTERFACE_DESCRIPTOR +typedef USB_INTERFACE_DESCRIPTOR* PUSB_INTERFACE_DESCRIPTOR; + +//! A structure representing the standard USB string descriptor. +/*! +* This descriptor is documented in section 9.6.5 of the USB 2.0 specification. +* All multiple-byte fields are represented in host-endian format. +*/ +typedef struct _USB_STRING_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! Content of the string + WCHAR bString[1]; + +} USB_STRING_DESCRIPTOR; +//! pointer to a \c USB_STRING_DESCRIPTOR +typedef USB_STRING_DESCRIPTOR* PUSB_STRING_DESCRIPTOR; + +//! A structure representing the common USB descriptor. +typedef struct _USB_COMMON_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + +} USB_COMMON_DESCRIPTOR; +//! pointer to a \c USB_COMMON_DESCRIPTOR +typedef USB_COMMON_DESCRIPTOR* PUSB_COMMON_DESCRIPTOR; + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning (disable:4201) +#pragma warning(disable:4214) // named type definition in parentheses + +//! Allows hardware manufacturers to define groupings of interfaces. +/*! +* +* The ECN specifies a USB descriptor, called the Interface Association +* Descriptor (IAD). +* +* The Universal Serial Bus Specification, revision 2.0, does not support +* grouping more than one interface of a composite device within a single +* function. However, the USB Device Working Group (DWG) created USB device +* classes that allow for functions with multiple interfaces, and the USB +* Implementor's Forum issued an Engineering Change Notification (ECN) that +* defines a mechanism for grouping interfaces. +* +*/ +typedef struct _USB_INTERFACE_ASSOCIATION_DESCRIPTOR +{ + //! Size of this descriptor (in bytes) + UCHAR bLength; + + //! Descriptor type + UCHAR bDescriptorType; + + //! First interface number of the set of interfaces that follow this descriptor + UCHAR bFirstInterface; + + //! The Number of interfaces follow this descriptor that are considered "associated" + UCHAR bInterfaceCount; + + //! \c bInterfaceClass used for this associated interfaces + UCHAR bFunctionClass; + + //! \c bInterfaceSubClass used for the associated interfaces + UCHAR bFunctionSubClass; + + //! \c bInterfaceProtocol used for the associated interfaces + UCHAR bFunctionProtocol; + + //! Index of string descriptor describing the associated interfaces + UCHAR iFunction; + +} USB_INTERFACE_ASSOCIATION_DESCRIPTOR; +//! pointer to a \c USB_INTERFACE_ASSOCIATION_DESCRIPTOR +typedef USB_INTERFACE_ASSOCIATION_DESCRIPTOR* PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR; + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +/*! @} */ + +#include +#endif // __USB_H__ + +#ifndef _LIBUSBK_LIBK_TYPES + +/*! \addtogroup libk +* @{ +*/ + +//! Usb handle specific properties that can be retrieved with \ref UsbK_GetProperty. +typedef enum _KUSB_PROPERTY +{ + //! Get the internal device file handle used for operations such as GetOverlappedResult or DeviceIoControl. + KUSB_PROPERTY_DEVICE_FILE_HANDLE, + + KUSB_PROPERTY_COUNT + +} KUSB_PROPERTY; + +//! Supported driver id enumeration. +typedef enum _KUSB_DRVID +{ + //! libusbK.sys driver ID + KUSB_DRVID_LIBUSBK, + + //! libusb0.sys driver ID + KUSB_DRVID_LIBUSB0, + + //! WinUSB.sys driver ID + KUSB_DRVID_WINUSB, + + //! libusb0.sys filter driver ID + KUSB_DRVID_LIBUSB0_FILTER, + + //! Supported driver count + KUSB_DRVID_COUNT + +} KUSB_DRVID; + +//! Supported function id enumeration. +typedef enum _KUSB_FNID +{ + //! \ref UsbK_Init dynamic driver function id. + KUSB_FNID_Init, + + //! \ref UsbK_Free dynamic driver function id. + KUSB_FNID_Free, + + //! \ref UsbK_ClaimInterface dynamic driver function id. + KUSB_FNID_ClaimInterface, + + //! \ref UsbK_ReleaseInterface dynamic driver function id. + KUSB_FNID_ReleaseInterface, + + //! \ref UsbK_SetAltInterface dynamic driver function id. + KUSB_FNID_SetAltInterface, + + //! \ref UsbK_GetAltInterface dynamic driver function id. + KUSB_FNID_GetAltInterface, + + //! \ref UsbK_GetDescriptor dynamic driver function id. + KUSB_FNID_GetDescriptor, + + //! \ref UsbK_ControlTransfer dynamic driver function id. + KUSB_FNID_ControlTransfer, + + //! \ref UsbK_SetPowerPolicy dynamic driver function id. + KUSB_FNID_SetPowerPolicy, + + //! \ref UsbK_GetPowerPolicy dynamic driver function id. + KUSB_FNID_GetPowerPolicy, + + //! \ref UsbK_SetConfiguration dynamic driver function id. + KUSB_FNID_SetConfiguration, + + //! \ref UsbK_GetConfiguration dynamic driver function id. + KUSB_FNID_GetConfiguration, + + //! \ref UsbK_ResetDevice dynamic driver function id. + KUSB_FNID_ResetDevice, + + //! \ref UsbK_Initialize dynamic driver function id. + KUSB_FNID_Initialize, + + //! \ref UsbK_SelectInterface dynamic driver function id. + KUSB_FNID_SelectInterface, + + //! \ref UsbK_GetAssociatedInterface dynamic driver function id. + KUSB_FNID_GetAssociatedInterface, + + //! \ref UsbK_Clone dynamic driver function id. + KUSB_FNID_Clone, + + //! \ref UsbK_QueryInterfaceSettings dynamic driver function id. + KUSB_FNID_QueryInterfaceSettings, + + //! \ref UsbK_QueryDeviceInformation dynamic driver function id. + KUSB_FNID_QueryDeviceInformation, + + //! \ref UsbK_SetCurrentAlternateSetting dynamic driver function id. + KUSB_FNID_SetCurrentAlternateSetting, + + //! \ref UsbK_GetCurrentAlternateSetting dynamic driver function id. + KUSB_FNID_GetCurrentAlternateSetting, + + //! \ref UsbK_QueryPipe dynamic driver function id. + KUSB_FNID_QueryPipe, + + //! \ref UsbK_SetPipePolicy dynamic driver function id. + KUSB_FNID_SetPipePolicy, + + //! \ref UsbK_GetPipePolicy dynamic driver function id. + KUSB_FNID_GetPipePolicy, + + //! \ref UsbK_ReadPipe dynamic driver function id. + KUSB_FNID_ReadPipe, + + //! \ref UsbK_WritePipe dynamic driver function id. + KUSB_FNID_WritePipe, + + //! \ref UsbK_ResetPipe dynamic driver function id. + KUSB_FNID_ResetPipe, + + //! \ref UsbK_AbortPipe dynamic driver function id. + KUSB_FNID_AbortPipe, + + //! \ref UsbK_FlushPipe dynamic driver function id. + KUSB_FNID_FlushPipe, + + //! \ref UsbK_IsoReadPipe dynamic driver function id. + KUSB_FNID_IsoReadPipe, + + //! \ref UsbK_IsoWritePipe dynamic driver function id. + KUSB_FNID_IsoWritePipe, + + //! \ref UsbK_GetCurrentFrameNumber dynamic driver function id. + KUSB_FNID_GetCurrentFrameNumber, + + //! \ref UsbK_GetOverlappedResult dynamic driver function id. + KUSB_FNID_GetOverlappedResult, + + //! \ref UsbK_GetProperty dynamic driver function id. + KUSB_FNID_GetProperty, + + + //! Supported function count + KUSB_FNID_COUNT, + +} KUSB_FNID; + +typedef BOOL KUSB_API KUSB_Init ( + _out KUSB_HANDLE* InterfaceHandle, + _in KLST_DEVINFO_HANDLE DevInfo); + +typedef BOOL KUSB_API KUSB_Free ( + _in KUSB_HANDLE InterfaceHandle); + +typedef BOOL KUSB_API KUSB_ClaimInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API KUSB_ReleaseInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API KUSB_SetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _in UCHAR AltSettingNumber); + +typedef BOOL KUSB_API KUSB_GetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _out PUCHAR AltSettingNumber); + +typedef BOOL KUSB_API KUSB_GetDescriptor ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR DescriptorType, + _in UCHAR Index, + _in USHORT LanguageID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred); + +typedef BOOL KUSB_API KUSB_ControlTransfer ( + _in KUSB_HANDLE InterfaceHandle, + _in WINUSB_SETUP_PACKET SetupPacket, + _refopt PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API KUSB_SetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +typedef BOOL KUSB_API KUSB_GetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +typedef BOOL KUSB_API KUSB_SetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR ConfigurationNumber); + +typedef BOOL KUSB_API KUSB_GetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR ConfigurationNumber); + +typedef BOOL KUSB_API KUSB_ResetDevice ( + _in KUSB_HANDLE InterfaceHandle); + +typedef BOOL KUSB_API KUSB_Initialize ( + _in HANDLE DeviceHandle, + _out KUSB_HANDLE* InterfaceHandle); + +typedef BOOL KUSB_API KUSB_SelectInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API KUSB_GetAssociatedInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AssociatedInterfaceIndex, + _out KUSB_HANDLE* AssociatedInterfaceHandle); + +typedef BOOL KUSB_API KUSB_Clone ( + _in KUSB_HANDLE InterfaceHandle, + _out KUSB_HANDLE* DstInterfaceHandle); + +typedef BOOL KUSB_API KUSB_QueryInterfaceSettings ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingIndex, + _out PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor); + +typedef BOOL KUSB_API KUSB_QueryDeviceInformation ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT InformationType, + _ref PUINT BufferLength, + _ref PVOID Buffer); + +typedef BOOL KUSB_API KUSB_SetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber); + +typedef BOOL KUSB_API KUSB_GetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR AltSettingNumber); + +typedef BOOL KUSB_API KUSB_QueryPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber, + _in UCHAR PipeIndex, + _out PWINUSB_PIPE_INFORMATION PipeInformation); + +typedef BOOL KUSB_API KUSB_SetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +typedef BOOL KUSB_API KUSB_GetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +typedef BOOL KUSB_API KUSB_ReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API KUSB_WritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API KUSB_ResetPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API KUSB_AbortPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API KUSB_FlushPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API KUSB_IsoReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +typedef BOOL KUSB_API KUSB_IsoWritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +typedef BOOL KUSB_API KUSB_GetCurrentFrameNumber ( + _in KUSB_HANDLE InterfaceHandle, + _out PUINT FrameNumber); + +typedef BOOL KUSB_API KUSB_GetOverlappedResult ( + _in KUSB_HANDLE InterfaceHandle, + _in LPOVERLAPPED Overlapped, + _out PUINT lpNumberOfBytesTransferred, + _in BOOL bWait); + +typedef BOOL KUSB_API KUSB_GetProperty ( + _in KUSB_HANDLE InterfaceHandle, + _in KUSB_PROPERTY PropertyType, + _ref PUINT PropertySize, + _out PVOID Value); + + + +//! USB core driver API information structure. +/*! +* This structure is part of \ref KUSB_DRIVER_API and contains +* driver and user specific information. +* +*/ +typedef struct _KUSB_DRIVER_API_INFO +{ + //! \readonly Driver id of the driver api. + INT DriverID; + + //! \readonly Number of valid functions contained in the driver API. + INT FunctionCount; + +} KUSB_DRIVER_API_INFO; + +//! Driver API function set structure. +/* +* Contains the driver specific USB core function pointer set. +* +* \note +* This structure has a fixed 512 byte structure size. +*/ +typedef struct _KUSB_DRIVER_API +{ + //! Driver API information. + KUSB_DRIVER_API_INFO Info; + + /*! \fn BOOL KUSB_API Init (_out KUSB_HANDLE* InterfaceHandle, _in KLST_DEVINFO_HANDLE DevInfo) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_Init + */ + KUSB_Init* Init; + + /*! \fn BOOL KUSB_API Free (_in KUSB_HANDLE InterfaceHandle) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_Free + */ + KUSB_Free* Free; + + /*! \fn BOOL KUSB_API ClaimInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR NumberOrIndex, _in BOOL IsIndex) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ClaimInterface + */ + KUSB_ClaimInterface* ClaimInterface; + + /*! \fn BOOL KUSB_API ReleaseInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR NumberOrIndex, _in BOOL IsIndex) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ReleaseInterface + */ + KUSB_ReleaseInterface* ReleaseInterface; + + /*! \fn BOOL KUSB_API SetAltInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR NumberOrIndex, _in BOOL IsIndex, _in UCHAR AltSettingNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SetAltInterface + */ + KUSB_SetAltInterface* SetAltInterface; + + /*! \fn BOOL KUSB_API GetAltInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR NumberOrIndex, _in BOOL IsIndex, _out PUCHAR AltSettingNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetAltInterface + */ + KUSB_GetAltInterface* GetAltInterface; + + /*! \fn BOOL KUSB_API GetDescriptor (_in KUSB_HANDLE InterfaceHandle, _in UCHAR DescriptorType, _in UCHAR Index, _in USHORT LanguageID, _out PUCHAR Buffer, _in UINT BufferLength, _outopt PUINT LengthTransferred) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetDescriptor + */ + KUSB_GetDescriptor* GetDescriptor; + + /*! \fn BOOL KUSB_API ControlTransfer (_in KUSB_HANDLE InterfaceHandle, _in WINUSB_SETUP_PACKET SetupPacket, _refopt PUCHAR Buffer, _in UINT BufferLength, _outopt PUINT LengthTransferred, _inopt LPOVERLAPPED Overlapped) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ControlTransfer + */ + KUSB_ControlTransfer* ControlTransfer; + + /*! \fn BOOL KUSB_API SetPowerPolicy (_in KUSB_HANDLE InterfaceHandle, _in UINT PolicyType, _in UINT ValueLength, _in PVOID Value) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SetPowerPolicy + */ + KUSB_SetPowerPolicy* SetPowerPolicy; + + /*! \fn BOOL KUSB_API GetPowerPolicy (_in KUSB_HANDLE InterfaceHandle, _in UINT PolicyType, _ref PUINT ValueLength, _out PVOID Value) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetPowerPolicy + */ + KUSB_GetPowerPolicy* GetPowerPolicy; + + /*! \fn BOOL KUSB_API SetConfiguration (_in KUSB_HANDLE InterfaceHandle, _in UCHAR ConfigurationNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SetConfiguration + */ + KUSB_SetConfiguration* SetConfiguration; + + /*! \fn BOOL KUSB_API GetConfiguration (_in KUSB_HANDLE InterfaceHandle, _out PUCHAR ConfigurationNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetConfiguration + */ + KUSB_GetConfiguration* GetConfiguration; + + /*! \fn BOOL KUSB_API ResetDevice (_in KUSB_HANDLE InterfaceHandle) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ResetDevice + */ + KUSB_ResetDevice* ResetDevice; + + /*! \fn BOOL KUSB_API Initialize (_in HANDLE DeviceHandle, _out KUSB_HANDLE* InterfaceHandle) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_Initialize + */ + KUSB_Initialize* Initialize; + + /*! \fn BOOL KUSB_API SelectInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR NumberOrIndex, _in BOOL IsIndex) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SelectInterface + */ + KUSB_SelectInterface* SelectInterface; + + /*! \fn BOOL KUSB_API GetAssociatedInterface (_in KUSB_HANDLE InterfaceHandle, _in UCHAR AssociatedInterfaceIndex, _out KUSB_HANDLE* AssociatedInterfaceHandle) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetAssociatedInterface + */ + KUSB_GetAssociatedInterface* GetAssociatedInterface; + + /*! \fn BOOL KUSB_API Clone (_in KUSB_HANDLE InterfaceHandle, _out KUSB_HANDLE* DstInterfaceHandle) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_Clone + */ + KUSB_Clone* Clone; + + /*! \fn BOOL KUSB_API QueryInterfaceSettings (_in KUSB_HANDLE InterfaceHandle, _in UCHAR AltSettingIndex, _out PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_QueryInterfaceSettings + */ + KUSB_QueryInterfaceSettings* QueryInterfaceSettings; + + /*! \fn BOOL KUSB_API QueryDeviceInformation (_in KUSB_HANDLE InterfaceHandle, _in UINT InformationType, _ref PUINT BufferLength, _ref PVOID Buffer) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_QueryDeviceInformation + */ + KUSB_QueryDeviceInformation* QueryDeviceInformation; + + /*! \fn BOOL KUSB_API SetCurrentAlternateSetting (_in KUSB_HANDLE InterfaceHandle, _in UCHAR AltSettingNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SetCurrentAlternateSetting + */ + KUSB_SetCurrentAlternateSetting* SetCurrentAlternateSetting; + + /*! \fn BOOL KUSB_API GetCurrentAlternateSetting (_in KUSB_HANDLE InterfaceHandle, _out PUCHAR AltSettingNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetCurrentAlternateSetting + */ + KUSB_GetCurrentAlternateSetting* GetCurrentAlternateSetting; + + /*! \fn BOOL KUSB_API QueryPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR AltSettingNumber, _in UCHAR PipeIndex, _out PWINUSB_PIPE_INFORMATION PipeInformation) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_QueryPipe + */ + KUSB_QueryPipe* QueryPipe; + + /*! \fn BOOL KUSB_API SetPipePolicy (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _in UINT PolicyType, _in UINT ValueLength, _in PVOID Value) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_SetPipePolicy + */ + KUSB_SetPipePolicy* SetPipePolicy; + + /*! \fn BOOL KUSB_API GetPipePolicy (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _in UINT PolicyType, _ref PUINT ValueLength, _out PVOID Value) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetPipePolicy + */ + KUSB_GetPipePolicy* GetPipePolicy; + + /*! \fn BOOL KUSB_API ReadPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _out PUCHAR Buffer, _in UINT BufferLength, _outopt PUINT LengthTransferred, _inopt LPOVERLAPPED Overlapped) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ReadPipe + */ + KUSB_ReadPipe* ReadPipe; + + /*! \fn BOOL KUSB_API WritePipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _in PUCHAR Buffer, _in UINT BufferLength, _outopt PUINT LengthTransferred, _inopt LPOVERLAPPED Overlapped) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_WritePipe + */ + KUSB_WritePipe* WritePipe; + + /*! \fn BOOL KUSB_API ResetPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_ResetPipe + */ + KUSB_ResetPipe* ResetPipe; + + /*! \fn BOOL KUSB_API AbortPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_AbortPipe + */ + KUSB_AbortPipe* AbortPipe; + + /*! \fn BOOL KUSB_API FlushPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_FlushPipe + */ + KUSB_FlushPipe* FlushPipe; + + /*! \fn BOOL KUSB_API IsoReadPipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _out PUCHAR Buffer, _in UINT BufferLength, _in LPOVERLAPPED Overlapped, _refopt PKISO_CONTEXT IsoContext) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_IsoReadPipe + */ + KUSB_IsoReadPipe* IsoReadPipe; + + /*! \fn BOOL KUSB_API IsoWritePipe (_in KUSB_HANDLE InterfaceHandle, _in UCHAR PipeID, _in PUCHAR Buffer, _in UINT BufferLength, _in LPOVERLAPPED Overlapped, _refopt PKISO_CONTEXT IsoContext) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_IsoWritePipe + */ + KUSB_IsoWritePipe* IsoWritePipe; + + /*! \fn BOOL KUSB_API GetCurrentFrameNumber (_in KUSB_HANDLE InterfaceHandle, _out PUINT FrameNumber) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetCurrentFrameNumber + */ + KUSB_GetCurrentFrameNumber* GetCurrentFrameNumber; + + /*! \fn BOOL KUSB_API GetOverlappedResult (_in KUSB_HANDLE InterfaceHandle, _in LPOVERLAPPED Overlapped, _out PUINT lpNumberOfBytesTransferred, _in BOOL bWait) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetOverlappedResult + */ + KUSB_GetOverlappedResult* GetOverlappedResult; + + /*! \fn BOOL KUSB_API GetProperty (_in KUSB_HANDLE InterfaceHandle, _in KUSB_PROPERTY PropertyType, _ref PUINT PropertySize, _out PVOID Value) + * \memberof KUSB_DRIVER_API + * \copydoc UsbK_GetProperty + */ + KUSB_GetProperty* GetProperty; + + //! fixed structure padding. + UCHAR z_F_i_x_e_d[512 - sizeof(KUSB_DRIVER_API_INFO) - sizeof(UINT_PTR) * KUSB_FNID_COUNT]; + +} KUSB_DRIVER_API; +typedef KUSB_DRIVER_API* PKUSB_DRIVER_API; +C_ASSERT(sizeof(KUSB_DRIVER_API) == 512); +/**@}*/ +#endif + +#ifndef _LIBUSBK_HOTK_TYPES + +/*! \addtogroup hotk +* @{ +*/ + +//! Hot plug config flags. +typedef enum _KHOT_FLAG +{ + //! No flags (or 0) + KHOT_FLAG_NONE, + + //! Notify all devices which match upon a succuessful call to \ref HotK_Init. + KHOT_FLAG_PLUG_ALL_ON_INIT = 0x0001, + + //! Allow other \ref KHOT_HANDLE instances to consume this match. + KHOT_FLAG_PASS_DUPE_INSTANCE = 0x0002, + + //! If a \c UserHwnd is specified, use \c PostMessage instead of \c SendMessage. + KHOT_FLAG_POST_USER_MESSAGE = 0x0004, +} KHOT_FLAG; + +//! Hot plug event function definition. +typedef VOID KUSB_API KHOT_PLUG_CB( + _in KHOT_HANDLE HotHandle, + _in KLST_DEVINFO_HANDLE DeviceInfo, + _in KLST_SYNC_FLAG PlugType); + +//! Power broadcast event function definition. +typedef VOID KUSB_API KHOT_POWER_BROADCAST_CB( + _in KHOT_HANDLE HotHandle, + _in KLST_DEVINFO_HANDLE DeviceInfo, + _in UINT PbtEvent); + +//! Hot plug parameter structure. +/*! +* \fixedstruct{2048} +* +* This structure is intially passed as a parameter to \ref HotK_Init. +* +*/ +typedef struct _KHOT_PARAMS +{ + //! Hot plug event window handle to send/post messages when notifications occur. + HWND UserHwnd; + + //! WM_USER message start offset used when sending/posting messages, See details. + /*! + * \attention The \ref hotk will send UserMessage+1 for arrival notifications and UserMessage+0 for removal notifications. + * + * - WPARAM = \ref KHOT_HANDLE + * - LPARAM = \ref KLST_DEVINFO_HANDLE + */ + UINT UserMessage; + + //! Additional init/config parameters + KHOT_FLAG Flags; + + //! File pattern matches for restricting notifcations to a single/group or all supported usb devices. + KLST_PATTERN_MATCH PatternMatch; + + //! Hot plug event callback function invoked when notifications occur. + /*! \fn VOID KUSB_API OnHotPlug (_in KHOT_HANDLE HotHandle, _in KLST_DEVINFO_HANDLE DeviceInfo, _in KLST_SYNC_FLAG PlugType) + * \memberof KHOT_PARAMS + */ + KHOT_PLUG_CB* OnHotPlug; + + //! \b WM_POWERBROADCAST event callback function invoked when a power-management event has occurred. + /*! \fn VOID KUSB_API OnPowerBroadcast (_in KHOT_HANDLE HotHandle, _in KLST_DEVINFO_HANDLE DeviceInfo, _in UINT PbtEvent) + * \memberof KHOT_PARAMS + */ + KHOT_POWER_BROADCAST_CB* OnPowerBroadcast; + + //! fixed structure padding. + UCHAR z_F_i_x_e_d[2048 - sizeof(KLST_PATTERN_MATCH) - sizeof(UINT_PTR) * 3 - sizeof(UINT) * 2]; + +} KHOT_PARAMS; +C_ASSERT(sizeof(KHOT_PARAMS) == 2048); + +//! Pointer to a \ref KHOT_PARAMS structure. +typedef KHOT_PARAMS* PKHOT_PARAMS; + +/**@}*/ + +#endif + +#ifndef _LIBUSBK_OVLK_TYPES + +/*! \addtogroup ovlk +* @{ +*/ + +//! \c WaitFlags used by \ref OvlK_Wait. +/*! +* +*/ +typedef enum _KOVL_WAIT_FLAG +{ + //! Do not perform any additional actions upon exiting \ref OvlK_Wait. + KOVL_WAIT_FLAG_NONE = 0L, + + //! If the i/o operation completes successfully, release the OverlappedK back to it's pool. + KOVL_WAIT_FLAG_RELEASE_ON_SUCCESS = 0x0001, + + //! If the i/o operation fails, release the OverlappedK back to it's pool. + KOVL_WAIT_FLAG_RELEASE_ON_FAIL = 0x0002, + + //! If the i/o operation fails or completes successfully, release the OverlappedK back to its pool. Perform no actions if it times-out. + KOVL_WAIT_FLAG_RELEASE_ON_SUCCESS_FAIL = 0x0003, + + //! If the i/o operation times-out cancel it, but do not release the OverlappedK back to its pool. + KOVL_WAIT_FLAG_CANCEL_ON_TIMEOUT = 0x0004, + + //! If the i/o operation times-out, cancel it and release the OverlappedK back to its pool. + KOVL_WAIT_FLAG_RELEASE_ON_TIMEOUT = 0x000C, + + //! Always release the OverlappedK back to its pool. If the operation timed-out, cancel it before releasing back to its pool. + KOVL_WAIT_FLAG_RELEASE_ALWAYS = 0x000F, + + //! Uses alterable wait functions. See http://msdn.microsoft.com/en-us/library/windows/desktop/ms687036%28v=vs.85%29.aspx + KOVL_WAIT_FLAG_ALERTABLE = 0x0010, + +} KOVL_WAIT_FLAG; + +//! \c Overlapped pool config flags. +/*! +* \attention Currently not used. +*/ +typedef enum _KOVL_POOL_FLAG +{ + KOVL_POOL_FLAG_NONE = 0L, +} KOVL_POOL_FLAG; + +/**@}*/ + +#endif + +#ifndef _LIBUSBK_STMK_TYPES + +/*! \addtogroup stmk +* @{ +*/ +//! Stream config flags. +/*! +* \attention Currently not used. +*/ +typedef enum _KSTM_FLAG +{ + //! None + KSTM_FLAG_NONE = 0L, + KSTM_FLAG_NO_PARTIAL_XFERS = 0x00100000, + KSTM_FLAG_USE_TIMEOUT = 0x80000000, + KSTM_FLAG_TIMEOUT_MASK = 0x0001FFFF +} KSTM_FLAG; + +//! Stream config flags. +/*! +* \attention Currently not used. +*/ +typedef enum _KSTM_COMPLETE_RESULT +{ + //! Valid + KSTM_COMPLETE_RESULT_VALID = 0L, + //! Invalid + KSTM_COMPLETE_RESULT_INVALID, +} KSTM_COMPLETE_RESULT; + +//! Stream transfer context structure. +/*! +* This structure is passed into the stream callback functions. +* The stream transfer context list is allocated upon a successful call to \ref StmK_Init. There is one +* transfer context for each transfer. (0 to \c MaxPendingTransfers). +* +*/ +typedef struct _KSTM_XFER_CONTEXT +{ + + //! Internal stream buffer. + PUCHAR Buffer; + + //! Size of internal stream buffer. + INT BufferSize; + + //! Number of bytes to write or number of bytes read. + INT TransferLength; + + //! User defined state. + PVOID UserState; + +} KSTM_XFER_CONTEXT; +//! Pointer to a \ref KSTM_XFER_CONTEXT structure. +typedef KSTM_XFER_CONTEXT* PKSTM_XFER_CONTEXT; + +//! Stream information structure. +/*! +* This structure is passed into the stream callback functions. +* The stream context is allocated upon a successful call to \ref StmK_Init. There is only one +* stream context per stream. +* +*/ +typedef struct _KSTM_INFO +{ + //! \ref KUSB_HANDLE this stream uses. + KUSB_HANDLE UsbHandle; + + //! This parameter corresponds to the bEndpointAddress field in the endpoint descriptor. + UCHAR PipeID; + + //! Maximum transfer read/write request allowed pending. + INT MaxPendingTransfers; + + //! Maximum transfer sage size. + INT MaxTransferSize; + + //! Maximum number of I/O request allowed pending. + INT MaxPendingIO; + + //! Populated with the endpoint descriptor for the specified \c PipeID. + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + //! Populated with the driver api for the specified \c UsbHandle. + KUSB_DRIVER_API DriverAPI; + + //! Populated with the device file handle for the specified \c UsbHandle. + HANDLE DeviceHandle; + + //! Stream handle. + KSTM_HANDLE StreamHandle; + + //! Stream info user defined state. + PVOID UserState; + +} KSTM_INFO; +//! Pointer to a \ref KSTM_INFO structure. +typedef KSTM_INFO* PKSTM_INFO; + +//! Function definition for an optional user-defined callback; executed when a transfer error occurs. +/*! \fn INT KUSB_API KSTM_ERROR_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in INT ErrorCode) +* \memberof KSTM_CALLBACK +*/ +typedef INT KUSB_API KSTM_ERROR_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in INT ErrorCode); + +//! Function definition for an optional user-defined callback; executed to submit a transfer. +/*! \fn INT KUSB_API KSTM_SUBMIT_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in LPOVERLAPPED Overlapped) +* \memberof KSTM_CALLBACK +*/ +typedef INT KUSB_API KSTM_SUBMIT_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in LPOVERLAPPED Overlapped); + +//! Function definition for an optional user-defined callback; executed for each transfer context when the stream is started with \ref StmK_Start. +/*! \fn INT KUSB_API KSTM_STARTED_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex) +* \memberof KSTM_CALLBACK +*/ +typedef INT KUSB_API KSTM_STARTED_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex); + +//! Function definition for an optional user-defined callback; executed for each transfer context when the stream is stopped with \ref StmK_Stop. +/*! \fn INT KUSB_API KSTM_STOPPED_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex) +* \memberof KSTM_CALLBACK +*/ +typedef INT KUSB_API KSTM_STOPPED_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex); + +//! Function definition for an optional user-defined callback; executed when a valid transfer completes. +/*! \fn INT KUSB_API KSTM_COMPLETE_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in INT ErrorCode) +* \memberof KSTM_CALLBACK +*/ +typedef INT KUSB_API KSTM_COMPLETE_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in INT ErrorCode); + +//! Function definition for an optional user-defined callback; executed immediately after a transfer completes. +/*! \fn KSTM_COMPLETE_RESULT KUSB_API KSTM_BEFORE_COMPLETE_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _ref PINT ErrorCode) +* \memberof KSTM_CALLBACK +* +* This callback function allows the user to accept or reject the transfer: +* - IN (Read, DeviceToHost) endpoints. +* - KSTM_COMPLETE_RESULT_VALID +* Continue normal processing; add the transfer to the internal complete list and make it available to \ref StmK_Read. +* - KSTM_COMPLETE_RESULT_INVALID +* Ignore this transfer. +* - OUT (Write, HostToDevice) endpoints. +* - KSTM_COMPLETE_RESULT_VALID +* Continue normal processing; add the transfer to the internal complete list and make it available subsequent \ref StmK_Write requests. +* - KSTM_COMPLETE_RESULT_INVALID +* Return this transfer to the internal queued list for automatic resubmission to the device. +* +*/ +typedef KSTM_COMPLETE_RESULT KUSB_API KSTM_BEFORE_COMPLETE_CB(_in PKSTM_INFO StreamInfo, _in PKSTM_XFER_CONTEXT XferContext, _in INT XferContextIndex, _in PINT ErrorCode); + +//! Stream callback structure. +/*! +* \fixedstruct{64} +* +* These optional callback functions are executed from the streams internal thread at various stages of operation. +* +*/ +typedef struct _KSTM_CALLBACK +{ + //! Executed when a transfer error occurs. + KSTM_ERROR_CB* Error; + + //! Executed to submit a transfer. + KSTM_SUBMIT_CB* Submit; + + //! Executed when a valid transfer completes. + KSTM_COMPLETE_CB* Complete; + + //! Executed for every transfer context when the stream is started with \ref StmK_Start. + KSTM_STARTED_CB* Started; + + //! Executed for every transfer context when the stream is stopped with \ref StmK_Stop. + KSTM_STOPPED_CB* Stopped; + + //! Executed immediately after a transfer completes. + KSTM_BEFORE_COMPLETE_CB* BeforeComplete; + + //! fixed structure padding. + UCHAR z_F_i_x_e_d[64 - sizeof(UINT_PTR) * 6]; + +} KSTM_CALLBACK; +//! Pointer to a \ref KSTM_CALLBACK structure. +typedef KSTM_CALLBACK* PKSTM_CALLBACK; +C_ASSERT(sizeof(KSTM_CALLBACK) == 64); + +/**@}*/ + +#endif +/////////////////////////////////////////////////////////////////////// +// L I B U S B K PUBLIC FUNCTIONS //////////////////////////////////// +/////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _LIBUSBK_LIBK_FUNCTIONS + /*! \addtogroup libk + * @{ + */ + +//! Gets the internal user context for the specified \ref KLIB_HANDLE. + /*! + * + * \param[out] Version + * Receives the libusbK library verson information. + * + * \returns NONE + */ + KUSB_EXP VOID KUSB_API LibK_GetVersion(_out PKLIB_VERSION Version); + +//! Gets the internal user context for the specified \ref KLIB_HANDLE. + /*! + * + * \param[in] Handle + * The handle containg the context to retrieve. + * + * \param[in] HandleType + * Handle type of \c Handle. + * + * \returns + * - on success, The user context value. + * - On failure, returns NULL and sets last error to \c ERROR_INVALID_HANDLE. + * + */ + KUSB_EXP KLIB_USER_CONTEXT KUSB_API LibK_GetContext( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType); + +//! Sets internal user context for the specified \ref KLIB_HANDLE. + /*! + * + * \param[in] Handle + * The handle containg the context to set. + * + * \param[in] HandleType + * Handle type of \c Handle. + * + * \param[in] ContextValue + * Value to assign to the handle user context space. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_SetContext( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue); + +//! Assigns a cleanup callback function to a \ref KLIB_HANDLE. + /*! + * + * \param[in] Handle + * The handle containg the cleanup callback function to set. + * + * \param[in] HandleType + * Handle type of \c Handle. + * + * \param[in] CleanupCB + * User supplied callback function to execute when the handles internal reference count reaches 0. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_SetCleanupCallback( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_HANDLE_CLEANUP_CB* CleanupCB); + +//! Initialize a driver API set. + /*! + * + * \param[out] DriverAPI + * A driver API structure to populate. + * + * \param[in] DriverID + * The driver id of the API set to retrieve. See \ref KUSB_DRVID + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_LoadDriverAPI( + _out PKUSB_DRIVER_API DriverAPI, + _in INT DriverID); + +//! Copies the driver API set out of a \ref KUSB_HANDLE + /*! + * + * \param[out] DriverAPI + * A driver API structure to populate. + * + * \param[in] UsbHandle + * Handle containing the desired driver API. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_CopyDriverAPI( + _out PKUSB_DRIVER_API DriverAPI, + _in KUSB_HANDLE UsbHandle); + +//! Initialize a driver API function. + /*! + * \param[out] ProcAddress + * Reference to a function pointer that will receive the API function pointer. + * + * \param[in] DriverID + * The driver id of the API to use. See \ref KUSB_DRVID + * + * \param[in] FunctionID + * The function id. See \ref KUSB_FNID + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_GetProcAddress( + _out KPROC* ProcAddress, + _in INT DriverID, + _in INT FunctionID); + +//! Sets the default user context for the specified \ref KLIB_HANDLE_TYPE. + /*! + * + * \param[in] HandleType + * The handle type which will be assigned the default ContextValue. + * + * \param[in] ContextValue + * Value assigned to the default user context for the specified \ref KLIB_HANDLE_TYPE. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_SetDefaultContext( + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue); + +//! Gets the default user context for the specified \ref KLIB_HANDLE_TYPE. + /*! + * + * \param[in] HandleType + * Handle type used to retrieve the default user context. + * + * \returns + * - on success, The default user context value. + * - On failure, returns NULL and sets last error to \c ERROR_INVALID_HANDLE. + * + */ + KUSB_EXP KLIB_USER_CONTEXT KUSB_API LibK_GetDefaultContext( + _in KLIB_HANDLE_TYPE HandleType); + +//! Initializes the global libusbK process context. + /*! + * + * If this function is not called at startup, libusbK initializes the global libusbK process context automatically. + * + * \param[in] Heap + * A handle to the memory heap libusbK will use for dynamic memory allocation. + * \note The process context itself is always allocated from the proccess heap. + * \note If \b Heap is \b NULL, dynamic memory is allocated from the proccess heap. + * + * \param[in] Reserved + * Reserved for future use. Must set to \b NULL. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LibK_Context_Init( + _inopt HANDLE Heap, + _in PVOID Reserved); + +//! Frees the global libusbK process context. + /*! + * + * If this function is not called on exit, libusbK frees the global libusbK process context automatically when it terminates. + * + * \returns NONE. + * + */ + KUSB_EXP VOID KUSB_API LibK_Context_Free(VOID); + + + /**@}*/ +#endif + +#ifndef _LIBUSBK_USBK_FUNCTIONS + /*! \addtogroup usbk + * @{ + */ + +//! Creates/opens a libusbK interface handle from the device list. This is a preferred method. + /*! + * + * \param[out] InterfaceHandle + * Receives a handle configured to the first (default) interface on the device. This handle is required by + * other libusbK routines that perform operations on the default interface. The handle is opaque. To release + * this handle, call the \ref UsbK_Free function. + * + * \param[in] DevInfo + * The device list element to open. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c UsbK_Init performs the same tasks as \ref UsbK_Initialize with the following exceptions: + * - Uses a \ref KLST_DEVINFO instead of a file handle created with the Windows CreateFile() API function. + * - File handles are managed internally and are closed when the last \ref KUSB_HANDLE is closed with + * \ref UsbK_Free. To obtain the internal file device handle, See \ref UsbK_GetProperty. + * + * \note + * A \c KUSB_HANDLE is required by other library routines that perform operations on a device. Once + * initialized, it can access all interfaces/endpoints of a device. An initialized handle can be cloned with + * \ref UsbK_Clone or \ref UsbK_GetAssociatedInterface. A Cloned handle will behave just as the orignal + * except in will maintain it's own \b selected interface setting. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_Init ( + _out KUSB_HANDLE* InterfaceHandle, + _in KLST_DEVINFO_HANDLE DevInfo); + +//! Frees a libusbK interface handle. + /*! + * + * \param[in] InterfaceHandle + * Handle to an interface on the device. This handle must be created by a previous call to \ref UsbK_Init, + * \ref UsbK_Initialize, \ref UsbK_GetAssociatedInterface, or \ref UsbK_Clone. + * + * \returns TRUE. + * + * The \ref UsbK_Free function releases resources alocated to the InterfaceHandle. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_Free ( + _in KUSB_HANDLE InterfaceHandle); + +//! Claims the specified interface by number or index. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] NumberOrIndex + * Interfaces can be claimed or released by a interface index or \c bInterfaceNumber. + * - Interface indexes always start from 0 and continue sequentially for all interfaces of the device. + * - An interface number always represents the actual \ref USB_INTERFACE_DESCRIPTOR::bInterfaceNumber. + * Interface numbers are not guaranteed to be zero based or sequential. + * + * \param[in] IsIndex + * If TRUE, \c NumberOrIndex represents an interface index.\n if FALSE \c NumberOrIndex represents a + * \c bInterfaceNumber. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * Claiming an interface allows applications a way to prevent other applications or multiple instances of the + * same application from using an interface at the same time. + * + * When an interface is claimed with \ref UsbK_ClaimInterface it performs the following actions: + * - Checks if the interface exists. If it does not, returns FALSE and sets last error to + * ERROR_NO_MORE_ITEMS. + * - The default (or current) interface for the device is changed to \c NumberOrIndex. + * - libusb0.sys and libusbK.sys: + * - A request to claim the interface is sent to the driver. If the interface is not claimed or already + * claimed by the application the request succeeds. If the interface is claimed by another application, + * \ref UsbK_ClaimInterface returns FALSE and sets last error to \c ERROR_BUSY. In this case the The + * default (or current) interface for the device is \b still changed to \c NumberOrIndex. + * - WinUSB.sys: All WinUSB device interfaces are claimed when the device is opened. This function performs + * identically to \ref UsbK_SelectInterface + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ClaimInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +//! Releases the specified interface by number or index. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] NumberOrIndex + * Interfaces can be claimed or released by a interface index or \c bInterfaceNumber. + * - Interface indexes always start from 0 and continue sequentially for all interfaces of the device. + * - An interface number always represents the actual \ref USB_INTERFACE_DESCRIPTOR::bInterfaceNumber. + * Interface numbers are not guaranteed to be zero based or sequential. + * + * \param[in] IsIndex + * If TRUE, \c NumberOrIndex represents an interface index.\n if FALSE \c NumberOrIndex represents a + * \c bInterfaceNumber. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * When an interface is release with \ref UsbK_ReleaseInterface it performs the following actions: + * - Checks if the interface exists. If it does not, returns FALSE and sets last error to + * ERROR_NO_MORE_ITEMS. + * - The default (or current) interface for the device is changed to the previously claimed interface. + * - libusb0.sys and libusbK.sys: + * - A request to release the interface is sent to the driver. If the interface is not claimed by a + * different application the request succeeds. If the interface is claimed by another application, + * \ref UsbK_ReleaseInterface returns FALSE and sets last error to \c ERROR_BUSY. In this case, the + * default/current interface for the device is \b still changed to the previously claimed interface. + * - WinUSB.sys: No other action needed, returns TRUE. + * + * \note + * When an interface is released, it is moved to the bottom if an interface stack making a previously claimed + * interface the current. This will continue to occur regardless of whether the interface is claimed. For + * this reason, \ref UsbK_ReleaseInterface can be used as a means to change the current/default interface of + * an \c InterfaceHandle without claiming the interface. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ReleaseInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +//! Sets the alternate setting of the specified interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] NumberOrIndex + * Interfaces can be specified by a interface index or \c bInterfaceNumber. + * - Interface indexes always start from 0 and continue sequentially for all interfaces of the device. + * - An interface number always represents the actual \ref USB_INTERFACE_DESCRIPTOR::bInterfaceNumber. + * Interface numbers are not guaranteed to be zero based or sequential. + * + * \param[in] IsIndex + * If TRUE, \c NumberOrIndex represents an interface index.\n if FALSE \c NumberOrIndex represents a + * \c bInterfaceNumber. + * + * \param[in] AltSettingNumber + * The bAlternateSetting to activate. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \ref UsbK_SetAltInterface performs the same task as \ref UsbK_SetCurrentAlternateSetting except it + * provides the option of specifying which interfaces alternate setting to activate. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _in UCHAR AltSettingNumber); + +//! Gets the alternate setting for the specified interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] NumberOrIndex + * Interfaces can be specified by a interface index or \c bInterfaceNumber. + * - Interface indexes always start from 0 and continue sequentially for all interfaces of the device. + * - An interface number always represents the actual \ref USB_INTERFACE_DESCRIPTOR::bInterfaceNumber. + * Interface numbers are not guaranteed to be zero based or sequential. + * + * \param[in] IsIndex + * If TRUE, \c NumberOrIndex represents an interface index.\n if FALSE \c NumberOrIndex represents a + * \c bInterfaceNumber. + * + * \param[out] AltSettingNumber + * On success, returns the active bAlternateSetting. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \ref UsbK_GetAltInterface performs the same task as \ref UsbK_GetCurrentAlternateSetting except it + * provides the option of specifying which interfaces alternate setting is to be retrieved. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _out PUCHAR AltSettingNumber); + +//! Gets the requested descriptor. This is a synchronous operation. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] DescriptorType + * A value that specifies the type of descriptor to return. This parameter corresponds to the bDescriptorType + * field of a standard device descriptor, whose values are described in the Universal Serial Bus + * specification. + * + * \param[in] Index + * The descriptor index. For an explanation of the descriptor index, see the Universal Serial Bus + * specification (www.usb.org). + * + * \param[in] LanguageID + * A value that specifies the language identifier, if the requested descriptor is a string descriptor. + * + * \param[out] Buffer + * A caller-allocated buffer that receives the requested descriptor. + * + * \param[in] BufferLength + * The length, in bytes, of Buffer. + * + * \param[out] LengthTransferred + * The number of bytes that were copied into Buffer. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * If the device descriptor or active config descriptor is requested, \ref UsbK_GetDescriptor retrieves + * cached data and this becomes a non-blocking, non I/O request. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetDescriptor ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR DescriptorType, + _in UCHAR Index, + _in USHORT LanguageID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred); + +//! Transmits control data over a default control endpoint. + /*! + * + * \param[in] InterfaceHandle + * A valid libusbK interface handle returned by: + * - \ref UsbK_Init + * - \ref UsbK_Initialize + * - \ref UsbK_GetAssociatedInterface + * - \ref UsbK_Clone + * + * \param[in] SetupPacket + * The 8-byte setup packet of type WINUSB_SETUP_PACKET. + * + * \param[in,out] Buffer + * A caller-allocated buffer that contains the data to transfer. + * + * \param[in] BufferLength + * The number of bytes to transfer, not including the setup packet. This number must be less than or equal to + * the size, in bytes, of Buffer. + * + * \param[out] LengthTransferred + * A pointer to a UINT variable that receives the actual number of transferred bytes. If the application + * does not expect any data to be transferred during the data phase (BufferLength is zero), LengthTransferred + * can be NULL. + * + * \param[in] Overlapped + * An optional pointer to an OVERLAPPED structure, which is used for asynchronous operations. If this + * parameter is specified, \ref UsbK_ControlTransfer immediately returns, and the event is signaled when the + * operation is complete. If Overlapped is not supplied, the \ref UsbK_ControlTransfer function transfers + * data synchronously. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. If an + * \c Overlapped member is supplied and the operation succeeds this function returns FALSE and sets last + * error to ERROR_IO_PENDING. + * + * A \ref UsbK_ControlTransfer is never cached. These requests always go directly to the usb device. + * + * \attention + * This function should not be used for operations supported by the library.\n e.g. + * \ref UsbK_SetConfiguration, \ref UsbK_SetAltInterface, etc.. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ControlTransfer ( + _in KUSB_HANDLE InterfaceHandle, + _in WINUSB_SETUP_PACKET SetupPacket, + _refopt PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +//! Sets the power policy for a device. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PolicyType + * A value that specifies the power policy to set. The following table describes symbolic constants that are + * defined in \ref lusbk_shared.h. + * + * - AUTO_SUSPEND (0x81) + * - Specifies the auto-suspend policy type; the power policy parameter must be specified by the caller in + * the Value parameter. + * - For auto-suspend, the Value parameter must point to a UCHAR variable. + * - If Value is TRUE (nonzero), the USB stack suspends the device if the device is idle. A device is idle + * if there are no transfers pending, or if the only pending transfers are IN transfers to interrupt or + * bulk endpoints. + * - The default value is determined by the value set in the DefaultIdleState registry setting. By default, + * this value is TRUE. + * + * - SUSPEND_DELAY (0x83) + * - Specifies the suspend-delay policy type; the power policy parameter must be specified by the caller in + * the Value parameter. + * - For suspend-delay, Value must point to a UINT variable. + * - Value specifies the minimum amount of time, in milliseconds, that the driver must wait post transfer + * before it can suspend the device. + * - The default value is determined by the value set in the DefaultIdleTimeout registry setting. By + * default, this value is five seconds. + * + * \param[in] ValueLength + * The size, in bytes, of the buffer at Value. + * + * \param[in] Value + * The new value for the power policy parameter. Data type and value for Value depends on the type of power + * policy passed in PolicyType. For more information, see PolicyType. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * The following list summarizes the effects of changes to power management states: + * - All pipe handles, interface handles, locks, and alternate settings are preserved across power management + * events. + * - Any transfers that are in progress are suspended when a device transfers to a low power state, and they + * are resumed when the device is restored to a working state. + * - The device and system must be in a working state before the client can restore a device-specific + * configuration. Clients can determine whether the device and system are in a working state from the + * WM_POWERBROADCAST message. + * - The client can indicate that an interface is idle by calling \ref UsbK_SetPowerPolicy. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +//! Gets the power policy for a device. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PolicyType + * A value that specifies the power policy parameter to retrieve in Value. The following table describes + * symbolic constants that are defined in \ref lusbk_shared.h. + * + * - AUTO_SUSPEND (0x81) + * - If the caller specifies a power policy of AUTO_SUSPEND, \ref UsbK_GetPowerPolicy returns the value of + * the auto suspend policy parameter in the Value parameter. + * - If Value is TRUE (that is, nonzero), the USB stack suspends the device when no transfers are pending + * or the only transfers pending are IN transfers on an interrupt or bulk endpoint. + * - The value of the DefaultIdleState registry value determines the default value of the auto suspend + * policy parameter. + * - The Value parameter must point to a UCHAR variable. + * + * - SUSPEND_DELAY (0x83) + * - If the caller specifies a power policy of SUSPEND_DELAY, \ref UsbK_GetPowerPolicy returns the value of + * the suspend delay policy parameter in Value. + * - The suspend delay policy parameter specifies the minimum amount of time, in milliseconds, that the + * driver must wait after any transfer before it can suspend the device. + * - Value must point to a UINT variable. + * + * \param[in,out] ValueLength + * A pointer to the size of the buffer that Value. On output, ValueLength receives the size of the data that + * was copied into the Value buffer. + * + * \param[out] Value + * A buffer that receives the specified power policy parameter. For more information, see PolicyType. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +//! Sets the device configuration number. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] ConfigurationNumber + * The configuration number to activate. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \ref UsbK_SetConfiguration is only supported with libusb0.sys. If the driver in not libusb0.sys, this + * function performs the following emulation actions: + * - If the requested configuration number is the current configuration number, returns TRUE. + * - If the requested configuration number is one other than the current configuration number, returns FALSE + * and set last error to \c ERROR_NO_MORE_ITEMS. + * + * This function will fail if there are pending I/O operations or there are other libusbK interface handles + * referencing the device. \sa UsbK_Free + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR ConfigurationNumber); + +//! Gets the device current configuration number. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[out] ConfigurationNumber + * On success, receives the active configuration number. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR ConfigurationNumber); + +//! Resets the usb device of the specified interface handle. (port cycle). + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ResetDevice ( + _in KUSB_HANDLE InterfaceHandle); + +//! Creates a libusbK handle for the device specified by a file handle. + /*! + * + * \attention + * This function is supported for WinUSB API compatibility only and is not intended for new development. + * libusbK library users should use \ref UsbK_Init instead. (regardless of the driver they've selected) + * + * \param[in] DeviceHandle + * The handle to the device that CreateFile returned. libusbK uses overlapped I/O, so FILE_FLAG_OVERLAPPED + * must be specified in the dwFlagsAndAttributes parameter of CreateFile call for DeviceHandle to have the + * characteristics necessary for this to function properly. + * + * \param[out] InterfaceHandle + * Receives a handle configured to the first (default) interface on the device. This handle is required by + * other libusbK routines that perform operations on the default interface. The handle is opaque. To release + * this handle, call the \ref UsbK_Free function. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * When \ref UsbK_Initialize is called, the policy settings of the interface are reset to the default values. + * + * The \ref UsbK_Initialize call queries the underlying USB stack for various descriptors and allocates + * enough memory to store the retrieved descriptor data. + * + * \ref UsbK_Initialize first retrieves the device descriptor and then gets the associated configuration + * descriptor. From the configuration descriptor, the call derives the associated interface descriptors and + * stores them in an array. The interfaces in the array are identified by zero-based indexes. An index value + * of 0 indicates the first interface (the default interface), a value of 1 indicates the second associated + * interface, and so on. \ref UsbK_Initialize parses the default interface descriptor for the endpoint + * descriptors and caches information such as the associated pipes or state specific data. The handle + * received in the InterfaceHandle parameter will have its default interface configured to the first + * interface in the array. + * + * If an application wants to use another interface on the device, it can call + * \ref UsbK_GetAssociatedInterface, or \ref UsbK_ClaimInterface. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_Initialize ( + _in HANDLE DeviceHandle, + _out KUSB_HANDLE* InterfaceHandle); + +//! Selects the specified interface by number or index as the current interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] NumberOrIndex + * Interfaces can be claimed or released by a interface index or \c bInterfaceNumber. + * - Interface indexes always start from 0 and continue sequentially for all interfaces of the device. + * - An interface number always represents the actual \ref USB_INTERFACE_DESCRIPTOR::bInterfaceNumber. + * Interface numbers are not guaranteed to be zero based or sequential. + * + * \param[in] IsIndex + * If TRUE, \c NumberOrIndex represents an interface index.\n if FALSE \c NumberOrIndex represents a + * \c bInterfaceNumber. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \sa UsbK_ClaimInterface + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SelectInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +//! Retrieves a handle for an associated interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] AssociatedInterfaceIndex + * An index that specifies the associated interface to retrieve. A value of 0 indicates the first associated + * interface, a value of 1 indicates the second associated interface, and so on. + * + * \param[out] AssociatedInterfaceHandle + * A handle for the associated interface. Callers must pass this interface handle to libusbK Functions + * exposed by libusbK.dll. To close this handle, call \ref UsbK_Free. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * The \ref UsbK_GetAssociatedInterface function retrieves an opaque handle for an associated interface. This + * is a synchronous operation. + * + * The first associated interface is the interface that immediately follows the current (or default) + * interface of the specified /c InterfaceHandle. + * + * The handle that \ref UsbK_GetAssociatedInterface returns must be released by calling \ref UsbK_Free. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetAssociatedInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AssociatedInterfaceIndex, + _out KUSB_HANDLE* AssociatedInterfaceHandle); + +//! Clones the specified interface handle. + /*! + * + * Each cloned interface handle maintains it's own selected interface. + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[out] DstInterfaceHandle + * On success, the cloned return handle. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_Clone ( + _in KUSB_HANDLE InterfaceHandle, + _out KUSB_HANDLE* DstInterfaceHandle); + +//! Retrieves the interface descriptor for the specified alternate interface settings for a particular interface handle. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] AltSettingIndex + * A value that indicates which alternate setting index to return. A value of 0 indicates the first alternate + * setting, a value of 1 indicates the second alternate setting, and so on. + * + * \param[out] UsbAltInterfaceDescriptor + * A pointer to a caller-allocated \ref USB_INTERFACE_DESCRIPTOR structure that contains information about + * the interface that AltSettingNumber specified. + * + * The \ref UsbK_QueryInterfaceSettings call searches the current/default interface array for the alternate + * interface specified by the caller in the AltSettingIndex. If the specified alternate interface is found, + * the function populates the caller-allocated USB_INTERFACE_DESCRIPTOR structure. If the specified alternate + * interface is not found, then the call fails with the ERROR_NO_MORE_ITEMS code. + * + * To change the current/default interface, see \ref UsbK_SelectInterface and \ref UsbK_ClaimInterface + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_QueryInterfaceSettings ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingIndex, + _out PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor); + +//! Retrieves information about the physical device that is associated with a libusbK handle. + /*! + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] InformationType + * A value that specifies which interface information value to retrieve. On input, InformationType must have + * the following value: \c DEVICE_SPEED (0x01). + * + * \param[in,out] BufferLength + * The maximum number of bytes to read. This number must be less than or equal to the size, in bytes, of + * Buffer. On output, BufferLength is set to the actual number of bytes that were copied into Buffer. + * + * \param[in,out] Buffer + * A caller-allocated buffer that receives the requested value. On output, Buffer indicates the device speed: + * - (0x01) low/full speed device. + * - (0x03) high speed device. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_QueryDeviceInformation ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT InformationType, + _ref PUINT BufferLength, + _ref PVOID Buffer); + +//! Sets the alternate setting of an interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] AltSettingNumber + * The value that is contained in the bAlternateSetting member of the \ref USB_INTERFACE_DESCRIPTOR + * structure. This structure can be populated by the \ref UsbK_QueryInterfaceSettings routine. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * Sets the active bAlternateSetting for the current/default interface. + * + * To change the default/current interface see \ref UsbK_ClaimInterface and \ref UsbK_ReleaseInterface + * \sa UsbK_SetAltInterface + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber); + +//! Gets the current alternate interface setting for an interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[out] AltSettingNumber + * A pointer to an unsigned character that receives an integer that indicates the current alternate setting. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * Gets the active bAlternateSetting for the current/default interface. + * + * To change the default/current interface see \ref UsbK_ClaimInterface and \ref UsbK_ReleaseInterface + * \sa UsbK_GetAltInterface + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR AltSettingNumber); + +//! Retrieves information about a pipe that is associated with an interface. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] AltSettingNumber + * A value that specifies the alternate interface to return the information for. + * + * \param[in] PipeIndex + * A value that specifies the pipe to return information about. This value is not the same as the + * bEndpointAddress field in the endpoint descriptor. A PipeIndex value of 0 signifies the first endpoint + * that is associated with the interface, a value of 1 signifies the second endpoint, and so on. PipeIndex + * must be less than the value in the bNumEndpoints field of the interface descriptor. + * + * \param[out] PipeInformation + * A pointer, on output, to a caller-allocated \ref WINUSB_PIPE_INFORMATION structure that contains pipe + * information. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * The \ref UsbK_QueryPipe function does not retrieve information about the control pipe. + * + * Each interface on the USB device can have multiple endpoints. To communicate with each of these endpoints, + * the bus driver creates pipes for each endpoint on the interface. The pipe indices are zero-based. + * Therefore for n number of endpoints, the pipes' indices are set from n-1. \ref UsbK_QueryPipe parses the + * configuration descriptor to get the interface specified by the caller. It searches the interface + * descriptor for the endpoint descriptor associated with the caller-specified pipe. If the endpoint is + * found, the function populates the caller-allocated \ref WINUSB_PIPE_INFORMATION structure with information + * from the endpoint descriptor. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_QueryPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber, + _in UCHAR PipeIndex, + _out PWINUSB_PIPE_INFORMATION PipeInformation); + +//! Sets the policy for a specific pipe associated with an endpoint on the device. This is a synchronous operation. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[in] PolicyType + * A UINT variable that specifies the policy parameter to change. The Value parameter contains the new value + * for the policy parameter. See the remarks section for information about each of the pipe policies and the + * resulting behavior. + * + * \param[in] ValueLength + * The size, in bytes, of the buffer at Value. + * + * \param[in] Value + * The new value for the policy parameter that PolicyType specifies. The size of this input parameter depends + * on the policy to change. For information about the size of this parameter, see the description of the + * PolicyType parameter. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * The following list describes symbolic constants that are defined in \ref lusbk_shared.h + * + * - \c SHORT_PACKET_TERMINATE (0x01) + * - The default value is \c FALSE. + * - To enable \c SHORT_PACKET_TERMINATE, in Value pass the address of a caller-allocated \c UCHAR variable + * set to \c TRUE (nonzero). + * - Enabling \c SHORT_PACKET_TERMINATE causes the driver to send a zero-length packet at the end of every + * write request to the host controller. + * + * - \c AUTO_CLEAR_STALL (0x02) + * - The default value is \c FALSE. To enable \c AUTO_CLEAR_STALL, in Value pass the address of a + * caller-allocated \c UCHAR variable set to \c TRUE (nonzero). + * - Enabling \c AUTO_CLEAR_STALL causes libusbK to reset the pipe in order to automatically clear the + * stall condition. Data continues to flow on the bulk and interrupt \c IN endpoints again as soon as a + * new or a queued transfer arrives on the endpoint. This policy parameter does not affect control pipes. + * - Disabling \c AUTO_CLEAR_STALL causes all transfers (that arrive to the endpoint after the stalled + * transfer) to fail until the caller manually resets the endpoint's pipe by calling \ref UsbK_ResetPipe. + * + * - \c PIPE_TRANSFER_TIMEOUT (0x03) + * - The default value is zero. To set a time-out value, in Value pass the address of a caller-allocated + * \c UINT variable that contains the time-out interval. + * - The \c PIPE_TRANSFER_TIMEOUT value specifies the time-out interval, in milliseconds. The host + * controller cancels transfers that do not complete within the specified time-out interval. + * - A value of zero (default) indicates that transfers do not time out because the host controller never + * cancels the transfer. + * + * - \c IGNORE_SHORT_PACKETS (0x04) + * - The default value is \c FALSE. To enable \c IGNORE_SHORT_PACKETS, in Value pass the address of a + * caller-allocated \c UCHAR variable set to \c TRUE (nonzero). + * - Enabling \c IGNORE_SHORT_PACKETS causes the host controller to not complete a read operation after it + * receives a short packet. Instead, the host controller completes the operation only after the host has + * read the specified number of bytes. + * - Disabling \c IGNORE_SHORT_PACKETS causes the host controller to complete a read operation when either + * the host has read the specified number of bytes or the host has received a short packet. + * + * - \c ALLOW_PARTIAL_READS (0x05) + * - The default value is \c TRUE (nonzero). To disable \c ALLOW_PARTIAL_READS, in Value pass the address + * of a caller-allocated \c UCHAR variable set to \c FALSE (zero). + * - Disabling \c ALLOW_PARTIAL_READS causes the read requests to fail whenever the device returns more + * data (on bulk and interrupt \c IN endpoints) than the caller requested. + * - Enabling \c ALLOW_PARTIAL_READS causes libusbK to save or discard the extra data when the device + * returns more data (on bulk and interrupt \c IN endpoints) than the caller requested. This behavior is + * defined by setting the \c AUTO_FLUSH value. + * + * - \c AUTO_FLUSH (0x06) + * - The default value is \c FALSE (zero). To enable \c AUTO_FLUSH, in Value pass the address of a + * caller-allocated \c UCHAR variable set to \c TRUE (nonzero). + * - \c AUTO_FLUSH must be used with \c ALLOW_PARTIAL_READS enabled. If \c ALLOW_PARTIAL_READS is \c TRUE, + * the value of \c AUTO_FLUSH determines the action taken by libusbK when the device returns more data + * than the caller requested. + * - Disabling \c ALLOW_PARTIAL_READS causes libusbK to ignore the \c AUTO_FLUSH value. + * - Disabling \c AUTO_FLUSH with \c ALLOW_PARTIAL_READS enabled causes libusbK to save the extra data, add + * the data to the beginning of the caller's next read request, and send it to the caller in the next + * read operation. + * - Enabling \c AUTO_FLUSH with \c ALLOW_PARTIAL_READS enabled causes libusbK to discard the extra data + * remaining from the read request. + * + * - \c RAW_IO (0x07) + * - The default value is \c FALSE (zero). To enable \c RAW_IO, in Value pass the address of a + * caller-allocated \c UCHAR variable set to \c TRUE (nonzero). + * - Enabling \c RAW_IO causes libusbK to send data directly to the \c USB driver stack, bypassing + * libusbK's queuing and error handling mechanism. + * - The buffers that are passed to \ref UsbK_ReadPipe must be configured by the caller as follows: + * - The buffer length must be a multiple of the maximum endpoint packet size. + * - The length must be less than or equal to the value of \c MAXIMUM_TRANSFER_SIZE retrieved by + * \ref UsbK_GetPipePolicy. + * - Disabling \c RAW_IO (\c FALSE) does not impose any restriction on the buffers that are passed to + * \ref UsbK_ReadPipe. + * + * - \c RESET_PIPE_ON_RESUME (0x09) + * - The default value is \c FALSE (zero). To enable \c RESET_PIPE_ON_RESUME, in Value pass the address of + * a caller-allocated \c UCHAR variable set to \c TRUE (nonzero). + * - \c TRUE (or a nonzero value) indicates that on resume from suspend, libusbK resets the endpoint before + * it allows the caller to send new requests to the endpoint. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_SetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +//! Gets the policy for a specific pipe (endpoint). + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[in] PolicyType + * A UINT variable that specifies the policy parameter to retrieve. The current value for the policy + * parameter is retrieved the Value parameter. + * + * \param[in,out] ValueLength + * A pointer to the size, in bytes, of the buffer that Value points to. On output, ValueLength receives the + * size, in bytes, of the data that was copied into the Value buffer. + * + * \param[out] Value + * A pointer to a buffer that receives the specified pipe policy value. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +//! Reads data from the specified pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[out] Buffer + * A caller-allocated buffer that receives the data that is read. + * + * \param[in] BufferLength + * The maximum number of bytes to read. This number must be less than or equal to the size, in bytes, of + * Buffer. + * + * \param[out] LengthTransferred + * A pointer to a UINT variable that receives the actual number of bytes that were copied into Buffer. For + * more information, see Remarks. + * + * \param[in] Overlapped + * An optional pointer to an overlapped structure for asynchronous operations. This can be a \ref KOVL_HANDLE + * or a pointer to a standard windows OVERLAPPED structure. If this parameter is specified, \c UsbK_ReadPipe + * returns immediately rather than waiting synchronously for the operation to complete before returning. An + * event is signaled when the operation is complete. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +//! Writes data to a pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[in] Buffer + * A caller-allocated buffer the data is written from. + * + * \param[in] BufferLength + * The maximum number of bytes to write. This number must be less than or equal to the size, in bytes, of + * Buffer. + * + * \param[out] LengthTransferred + * A pointer to a UINT variable that receives the actual number of bytes that were transferred from Buffer. + * For more information, see Remarks. + * + * \param[in] Overlapped + * An optional pointer to an overlapped structure for asynchronous operations. This can be a \ref KOVL_HANDLE + * or a pointer to a standard windows OVERLAPPED structure. If this parameter is specified, \c UsbK_WritePipe + * returns immediately rather than waiting synchronously for the operation to complete before returning. An + * event is signaled when the operation is complete. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_WritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +//! Resets the data toggle and clears the stall condition on a pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_ResetPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +//! Aborts all of the pending transfers for a pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_AbortPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +//! Discards any data that is cached in a pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_FlushPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +//! Reads from an isochronous pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[out] Buffer + * A caller-allocated buffer that receives the data that is read. + * + * \param[in] BufferLength + * The maximum number of bytes to read. This number must be less than or equal to the size, in bytes, of + * Buffer. + * + * \param[in] Overlapped + * A \b required pointer to an overlapped structure for asynchronous operations. This can be a + * \ref KOVL_HANDLE or a pointer to a standard windows OVERLAPPED structure. If this parameter is specified, + * \c UsbK_IsoReadPipe returns immediately rather than waiting synchronously for the operation to complete + * before returning. An event is signaled when the operation is complete. + * + * \param[in,out] IsoContext + * Pointer to an isochronous transfer context created with \ref IsoK_Init. If \c IsoContext is NULL, + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \par Overlapped I/O considerations + * If an \c Overlapped parameter is specified and the transfer is submitted successfully, the function + * returns \b FALSE and sets last error to \c ERROR_IO_PENDING. When using overlapped I/O, users may ignore + * the return results of this function and instead use the return results from one of the \ref ovlk wait + * functions or from \ref UsbK_GetOverlappedResult. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_IsoReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +//! Writes to an isochronous pipe. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] PipeID + * An 8-bit value that consists of a 7-bit address and a direction bit. This parameter corresponds to the + * bEndpointAddress field in the endpoint descriptor. + * + * \param[in] Buffer + * A caller-allocated buffer that receives the data that is read. + * + * \param[in] BufferLength + * The maximum number of bytes to write. This number must be less than or equal to the size, in bytes, of + * Buffer. + * + * \param[in] Overlapped + * An optional pointer to an overlapped structure for asynchronous operations. This can be a \ref KOVL_HANDLE + * or a pointer to a standard windows OVERLAPPED structure. If this parameter is specified, + * \c UsbK_IsoWritePipe returns immediately rather than waiting synchronously for the operation to complete + * before returning. An event is signaled when the operation is complete. + * + * \param[in,out] IsoContext + * Pointer to an isochronous transfer context created with \ref IsoK_Init. See remarks below. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_IsoWritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +//! Retrieves the current USB frame number. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[out] FrameNumber + * A pointer to a location that receives the current 32-bit frame number on the USB bus (from the host + * controller driver). + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetCurrentFrameNumber ( + _in KUSB_HANDLE InterfaceHandle, + _out PUINT FrameNumber); + +//! Retrieves the results of an overlapped operation on the specified libusbK handle. + /*! + * + * \param[in] InterfaceHandle + * An initialized usb handle, see \ref UsbK_Init. + * + * \param[in] Overlapped + * A pointer to a standard windows OVERLAPPED structure that was specified when the overlapped operation was + * started. + * + * \param[out] lpNumberOfBytesTransferred + * A pointer to a variable that receives the number of bytes that were actually transferred by a read or + * write operation. + * + * \param[in] bWait + * If this parameter is TRUE, the function does not return until the operation has been completed. If this + * parameter is FALSE and the operation is still pending, the function returns FALSE and the GetLastError + * function returns ERROR_IO_INCOMPLETE. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * This function is like the Win32 API routine, GetOverlappedResult, with one difference; instead of passing + * a file handle that is returned from CreateFile, the caller passes an interface handle that is returned + * from \ref UsbK_Initialize, \ref UsbK_Init, or \ref UsbK_GetAssociatedInterface. The caller can use either + * API routine, if the appropriate handle is passed. The \ref UsbK_GetOverlappedResult function extracts the + * file handle from the interface handle and then calls GetOverlappedResult. \n + * + * The results that are reported by the \ref UsbK_GetOverlappedResult function are those from the specified + * handle's last overlapped operation to which the specified standard windows OVERLAPPED structure was + * provided, and for which the operation's results were pending. A pending operation is indicated when the + * function that started the operation returns FALSE, and the GetLastError routine returns ERROR_IO_PENDING. + * When an I/O operation is pending, the function that started the operation resets the hEvent member of the + * standard windows OVERLAPPED structure to the nonsignaled state. Then when the pending operation has been + * completed, the system sets the event object to the signaled state. \n + * + * The caller can specify that an event object is manually reset in the standard windows OVERLAPPED + * structure. If an automatic reset event object is used, the event handle must not be specified in any other + * wait operation in the interval between starting the overlapped operation and the call to + * \ref UsbK_GetOverlappedResult. For example, the event object is sometimes specified in one of the wait + * routines to wait for the operation to be completed. When the wait routine returns, the system sets an + * auto-reset event's state to nonsignaled, and a successive call to \ref UsbK_GetOverlappedResult with the + * bWait parameter set to TRUE causes the function to be blocked indefinitely. + * + * If the bWait parameter is TRUE, \ref UsbK_GetOverlappedResult determines whether the pending operation has + * been completed by waiting for the event object to be in the signaled state. + * + * If the hEvent member of the standard windows OVERLAPPED structure is NULL, the system uses the state of + * the file handle to signal when the operation has been completed. Do not use file handles for this purpose. + * It is better to use an event object because of the confusion that can occur when multiple concurrent + * overlapped operations are performed on the same file. In this situation, you cannot know which operation + * caused the state of the object to be signaled. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetOverlappedResult ( + _in KUSB_HANDLE InterfaceHandle, + _in LPOVERLAPPED Overlapped, + _out PUINT lpNumberOfBytesTransferred, + _in BOOL bWait); + +//! Gets a USB device (driver specific) property from usb handle. + /*! + * + * \param[in] InterfaceHandle + * USB handle of the property to retrieve. + * + * \param[in] PropertyType + * The propety type to retrieve. + * + * \param[in,out] PropertySize + * Size in bytes of \c Value. + * + * \param[out] Value + * On success, receives the proprty data. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API UsbK_GetProperty ( + _in KUSB_HANDLE InterfaceHandle, + _in KUSB_PROPERTY PropertyType, + _ref PUINT PropertySize, + _out PVOID Value); + + /*! @} */ + + +#endif + +#ifndef _LIBUSBK_LSTK_FUNCTIONS + /*! \addtogroup lstk + *@{ + */ + +//! Initializes a new usb device list containing all supported devices. + /*! + * + * \param[out] DeviceList + * Pointer reference that will receive a populated device list. + * + * \param[in] Flags + * Search, filter, and listing options. see \c KLST_FLAG + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c LstK_Init populates \c DeviceList with connected usb devices that can be used by libusbK. + * + * \note if \ref LstK_Init returns TRUE, the device list must be freed with \ref LstK_Free when it is no + * longer needed. + * + */ + KUSB_EXP BOOL KUSB_API LstK_Init( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags); + +//! Initializes a new usb device list containing only devices matching a specific class GUID. + /*! + * + * \param[out] DeviceList + * Pointer reference that will receive a populated device list. + * + * \param[in] Flags + * Search, filter, and listing options. see \c KLST_FLAG + * + * \param[in] PatternMatch + * Pattern Search filter. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c LstK_InitEx populates \c DeviceList with usb devices that can be used by libusbK. Only device + * matching the \ref KLST_PATTERN_MATCH string are included in the list. + * + * \note + * This function significantly improves performance when used with a device interface guid pattern patch. + * + * \note if \ref LstK_InitEx returns TRUE, the device list must be freed with \ref LstK_Free when it it's no + * longer needed. + * + */ + KUSB_EXP BOOL KUSB_API LstK_InitEx( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags, + _in PKLST_PATTERN_MATCH PatternMatch); + + //! Frees a usb device list. + /*! + * + * \note if \ref LstK_Init returns TRUE, the device list must be freed with \ref LstK_Free when it is no + * longer needed. + * + * \param[in] DeviceList + * The \c DeviceList to free. + * + * \returns NONE + * + * Frees all resources that were allocated to \c DeviceList by \ref LstK_Init. + * + */ + KUSB_EXP BOOL KUSB_API LstK_Free( + _in KLST_HANDLE DeviceList); + +//! Enumerates \ref KLST_DEVINFO elements of a \ref KLST_HANDLE. + /*! + * + * \param[in] DeviceList + * The \c DeviceList to enumerate. + * + * \param[in] EnumDevListCB + * Function to call for each iteration. + * + * \param[in] Context + * Optional user context pointer. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * Calls \c EnumDevListCB for each element in the device list or until \c EnumDevListCB returns FALSE. + * + */ + KUSB_EXP BOOL KUSB_API LstK_Enumerate( + _in KLST_HANDLE DeviceList, + _in KLST_ENUM_DEVINFO_CB* EnumDevListCB, + _inopt PVOID Context); + +//! Gets the \ref KLST_DEVINFO element for the current position. + /*! + * + * \param[in] DeviceList + * The \c DeviceList to retrieve a current \ref KLST_DEVINFO for. + * + * \param[out] DeviceInfo + * The device information. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * After a \c DeviceList is created or after the \ref LstK_MoveReset method is called, the \c LstK_MoveNext + * method must be called to advance the device list enumerator to the first element of the \c DeviceList + * before calling \c LstK_Current otherwise, \c DeviceInfo is undefined. + * + * \c LstK_Current returns \c FALSE and sets last error to \c ERROR_NO_MORE_ITEMS if the last call to + * \c LstK_MoveNext returned \c FALSE, which indicates the end of the \c DeviceList. + * + * \c LstK_Current does not move the position of the device list enumerator, and consecutive calls to + * \c LstK_Current return the same object until either \c LstK_MoveNext or \ref LstK_MoveReset is called. + * + */ + KUSB_EXP BOOL KUSB_API LstK_Current( + _in KLST_HANDLE DeviceList, + _out KLST_DEVINFO_HANDLE* DeviceInfo); + +//! Advances the device list current \ref KLST_DEVINFO position. + /*! + * \param[in] DeviceList + * A usb device list returned by \ref LstK_Init + * + * \param[out] DeviceInfo + * On success, contains a pointer to the device information for the current enumerators position. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * After a \c DeviceList is created or after \ref LstK_MoveReset is called, an enumerator is positioned + * before the first element of the \c DeviceList and the \b first call to \c LstK_MoveNext moves the + * enumerator over the first element of the \c DeviceList. + * + * If \c LstK_MoveNext passes the end of the \c DeviceList, the enumerator is positioned after the last + * element in the \c DeviceList and \c LstK_MoveNext returns \c FALSE. When the enumerator is at this + * position, a subsequent call to \c LstK_MoveNext will reset the enumerator and it continues from the + * beginning. + * + */ + KUSB_EXP BOOL KUSB_API LstK_MoveNext( + _in KLST_HANDLE DeviceList, + _outopt KLST_DEVINFO_HANDLE* DeviceInfo); + +//! Sets the device list to its initial position, which is before the first element in the list. + /*! + * + * \param[in] DeviceList + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP VOID KUSB_API LstK_MoveReset( + _in KLST_HANDLE DeviceList); + +//! Find a device by vendor and product id + /*! + * + * \param[in] DeviceList + * The \c DeviceList to retrieve a current \ref KLST_DEVINFO for. + * + * \param[in] Vid + * ID is used in conjunction with the \c Pid to uniquely identify USB devices, providing traceability to the + * OEM. + * + * \param[in] Pid + * ID is used in conjunction with the \c Pid to uniquely identify USB devices, providing traceability to the + * OEM. + * + * \param[out] DeviceInfo + * On success, the device information pointer, otherwise NULL. + * + * \returns + * - TRUE if the device was found + * - FALSE if the device was \b not found or an error occurred. + * - Sets last error to \c ERROR_NO_MORE_ITEMS if the device was \b not found. + * + * Searches all elements in \c DeviceList for usb device matching the specified. + * + */ + KUSB_EXP BOOL KUSB_API LstK_FindByVidPid( + _in KLST_HANDLE DeviceList, + _in INT Vid, + _in INT Pid, + _out KLST_DEVINFO_HANDLE* DeviceInfo); + +//! Counts the number of device info elements in a device list. + /*! + * + * \param[in] DeviceList + * The deice list to count. + * + * \param[in,out] Count + * On success, receives the number of \ref KLST_DEVINFO elements in the list. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API LstK_Count( + _in KLST_HANDLE DeviceList, + _ref PUINT Count); + + + /**@}*/ + +#endif + +#ifndef _LIBUSBK_HOTK_FUNCTIONS + /*! \addtogroup hotk + * @{ + */ + +//! Creates a new hot-plug handle for USB device arrival/removal event monitoring. + /*! + * + * \param[out] Handle + * Reference to a handle pointer that will receive the initialized hot-plug handle. + * + * \param[in,out] InitParams + * Hot plug handle initialization structure. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API HotK_Init( + _out KHOT_HANDLE* Handle, + _ref PKHOT_PARAMS InitParams); + +//! Frees the specified hot-plug handle. + /*! + * + * \param[in] Handle + * hot-plug handle pointer to free. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API HotK_Free( + _in KHOT_HANDLE Handle); + + //! Frees all hot-plug handles initialized with \ref HotK_Init. + /*! + * + */ + KUSB_EXP VOID KUSB_API HotK_FreeAll(VOID); + + /**@}*/ + +#endif + +#ifndef _LIBUSBK_OVLK_FUNCTIONS + /*! \addtogroup ovlk + * @{ + */ + +//! Gets a preallocated \c OverlappedK structure from the specified/default pool. + /*! + * + * \param[out] OverlappedK + * On Success, receives the overlapped handle. + * + * \param[in] PoolHandle + * The overlapped pool used to retrieve the next available \c OverlappedK. + * + * \returns On success, the next unused overlappedK available in the pool. Otherwise NULL. Use + * \c GetLastError() to get extended error information. + * + * After calling \ref OvlK_Acquire or \ref OvlK_ReUse the \c OverlappedK is ready to be used in an I/O + * operation. See one of the \c UsbK core transfer functions such as \ref UsbK_ReadPipe or + * \ref UsbK_WritePipe for more information. + * + * If the pools internal refurbished list (a re-usable list of \c OverlappedK structures) is not empty, the + * \ref OvlK_Acquire function will choose an overlapped from the refurbished list. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_Acquire( + _out KOVL_HANDLE* OverlappedK, + _in KOVL_POOL_HANDLE PoolHandle); + +//! Returns an \c OverlappedK structure to it's pool. + /*! + * + * \param[in] OverlappedK + * The overlappedK to release. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * When an overlapped is returned to pool, it resources are \b not freed. Instead, it is added to an internal + * refurbished list (a re-usable list of \c OverlappedK structures). + * + * \warning This function must not be called when the OverlappedK is in-use. If unsure, consider using + * \ref OvlK_WaitAndRelease instead. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_Release( + _in KOVL_HANDLE OverlappedK); + + +//! Creates a new overlapped pool. + /*! + * + * \param[out] PoolHandle + * On success, receives the new pool handle. + * + * \param[in] UsbHandle + * USB handle to associate with the pool. + * + * \param[in] MaxOverlappedCount + * Maximum number of overkappedK handles allowed in the pool. + * + * \param[in] Flags + * Pool flags. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_Init ( + _out KOVL_POOL_HANDLE* PoolHandle, + _in KUSB_HANDLE UsbHandle, + _in INT MaxOverlappedCount, + _inopt KOVL_POOL_FLAG Flags); + +//! Destroys the specified pool and all resources it created. + /*! + * + * \param[in] PoolHandle + * The overlapped pool to destroy. Once destroyed, the pool and all resources which belong to it can no + * longer be used. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \warning A pool should not be destroyed until all OverlappedKs acquired from it are no longer in-use. For + * more information see \ref OvlK_WaitAndRelease or \ref OvlK_Release. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_Free( + _in KOVL_POOL_HANDLE PoolHandle); + + +//! Returns the internal event handle used to signal IO operations. + /*! + * + * \param[in] OverlappedK + * The overlappedK used to return the internal event handle. + * + * \returns On success, The manual reset event handle being used by this overlappedK. Otherwise NULL. Use + * \c GetLastError() to get extended error information. + * + * \ref OvlK_GetEventHandle is useful for applications that must to their own event handling. It exposes the + * windows \c OVERLAPPED \c hEvent used for i/o completion signaling. This event handle can be used by the + * standard event wait functions; /c WaitForMultipleObjectsEx for example. + * + * \warning Use \ref OvlK_GetEventHandle with caution. Event handles returned by this function should never + * be used unless the OverlappedK has been \b acquired by the application. + * + */ + KUSB_EXP HANDLE KUSB_API OvlK_GetEventHandle( + _in KOVL_HANDLE OverlappedK); + +//! Waits for overlapped I/O completion, and performs actions specified in \c WaitFlags. + /*! + * + * \param[in] OverlappedK + * The overlappedK to wait on. + * + * \param[in] TimeoutMS + * Number of milliseconds to wait for overlapped completion. + * + * \param[in] WaitFlags + * See /ref KOVL_WAIT_FLAG + * + * \param[out] TransferredLength + * On success, returns the number of bytes transferred by this overlappedK. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. See + * the remarks section below for details on relevant error codes. + * + * \c OvlK_Wait waits the time interval specified in \c TimeoutMS for the overlapped I/O operation to + * complete. Different actions can then taken depending on the flags specified in \c WaitFlags. + * + * \WINERRORTABLE + * + * \WINERROR{ERROR_CANCELLED,1223} + * - The I/O was cancelled by the user. The transfer complete event was not signalled within the alotted + * transfer timeout time and the OvlK_Wait function issued a CancelIoEx/CancelIo request because the + * \ref KOVL_WAIT_FLAG_CANCEL_ON_TIMEOUT flag bit was set. + * \ENDWINERROR + * + * \WINERROR{ERROR_OPERATION_ABORTED,995} + * - The transfer complete event is signalled but the overlapped result was allready cancelled. The + * overlapped I/O may have bee cancelled for one of the following reasons: + * - Driver cancelled because of pipe timeout policy expiration. + * - The device was disconnected. + * - A \ref UsbK_AbortPipe request was issued. + * \ENDWINERROR + * + * \ENDWINERRORTABLE + * + */ + KUSB_EXP BOOL KUSB_API OvlK_Wait( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength); + +//! Waits for overlapped I/O completion on the oldest acquired OverlappedK handle and performs actions specified in \c WaitFlags. + /*! + * + * \param[in] PoolHandle + * The pool handle containing one or more acuired OverlappedKs. + * + * \param[out] OverlappedK + * On success, set to the oldest overlappedK in the acquired list. + * + * \param[in] TimeoutMS + * See /ref OvlK_Wait + * + * \param[in] WaitFlags + * See /ref KOVL_WAIT_FLAG + * + * \param[out] TransferredLength + * See /ref OvlK_Wait + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. See + * See /ref OvlK_Wait + */ + KUSB_EXP BOOL KUSB_API OvlK_WaitOldest( + _in KOVL_POOL_HANDLE PoolHandle, + _outopt KOVL_HANDLE* OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength); + +//! Waits for overlapped I/O completion, cancels on a timeout error. + /*! + * + * \param[in] OverlappedK + * The overlappedK to wait on. + * + * \param[in] TimeoutMS + * Number of milliseconds to wait for overlapped completion. + * + * \param[out] TransferredLength + * On success, returns the number of bytes transferred by this overlappedK. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. See + * \ref OvlK_Wait for details on relevant win32 error codes. + * + * \note This convenience function calls \ref OvlK_Wait with \ref KOVL_WAIT_FLAG_CANCEL_ON_TIMEOUT. + * + * \c OvlK_WaitOrCancel waits the the time interval specified by \c TimeoutMS for an overlapped result. If + * the \c TimeoutMS interval expires the I/O operation is cancelled. The \c OverlappedK is not released back + * to its pool. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_WaitOrCancel( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength); + +//! Waits for overlapped I/O completion, cancels on a timeout error and always releases the OvlK handle back to its pool. + /*! + * + * \param[in] OverlappedK + * The overlappedK to wait on. + * + * \param[in] TimeoutMS + * Number of milliseconds to wait for overlapped completion. + * + * \param[out] TransferredLength + * On success, returns the number of bytes transferred by this overlappedK. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. See + * \ref OvlK_Wait for details on relevant win32 error codes. + * + * \note This convenience function calls \ref OvlK_Wait with \ref KOVL_WAIT_FLAG_RELEASE_ALWAYS. + * + * \c OvlK_WaitAndRelease waits the the time interval specified by \c TimeoutMS for an overlapped result. + * When \c OvlK_WaitOrCancel returns, the I/O operation has either been completed or cancelled. The + * \c OverlappedK is always released back to its pool where it can be re-acquired with \ref OvlK_Acquire. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_WaitAndRelease( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength); + +//! Checks for i/o completion; returns immediately. (polling) + /*! + * + * \param[in] OverlappedK + * The overlappedK to check for completion. + * + * \warning \ref OvlK_IsComplete does \b no validation on the OverlappedK. It's purpose is to check the event + * signal state as fast as possible. + * + * \returns TRUE if the \c OverlappedK has completed, otherwise FALSE. + * + * \c OvlK_IsComplete quickly checks if the \c OverlappedK i/o operation has completed. + */ + KUSB_EXP BOOL KUSB_API OvlK_IsComplete( + _in KOVL_HANDLE OverlappedK); + +//! Initializes an overlappedK for re-use. The overlappedK is not return to its pool. + /*! + * + * \param[in] OverlappedK + * The overlappedK to re-use. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * This function performs the following actions: + * - Resets the overlapped event to non-signaled via ResetEvent(). + * - Clears the internal overlapped information. + * - Clears the 'Internal' and 'InternalHigh' members of the windows overlapped structure. + * + * \note + * Re-using OverlappedKs is the most efficient means of OverlappedK management. When an OverlappedK is + * "re-used" it is not returned to the pool. Instead, the application retains ownership for use in another + * i/o operation. + * + */ + KUSB_EXP BOOL KUSB_API OvlK_ReUse( + _in KOVL_HANDLE OverlappedK); + + /**@}*/ + +#endif + +#ifndef _LIBUSBK_STMK_FUNCTIONS + + /*! \addtogroup stmk + * @{ + */ + +//! Initializes a new uni-directional pipe stream. + /*! + * + * \param[out] StreamHandle + * On success, receives the new stream handle. + * + * \param[in] UsbHandle + * Usb handle to associate with this stream. + * + * \param[in] PipeID + * Endpoint address of USB pipe to associate with this stream. + * + * \param[in] MaxTransferSize + * Maximum number of bytes transferred at once. Larger transfers committed with the stream read/write + * functions are automatically split into multiple smaller chunks. + * + * \param[in] MaxPendingTransfers + * Maximum number of transfers allowed to be outstanding and the total number of transfer contexts that are + * allocated to the stream. + * + * \param[in] MaxPendingIO + * Maximum number of I/O requests the internal stream thread is allowed to have submit at any given time. + * (Pending I/O) + * + * \param[in] Callbacks + * Optional user callback functions. If specified, these callback functions will be executed in real time + * (from within the context of the internal stream thread) as transfers go through the various states. + * + * \param[in] Flags + * Additional stream flags. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \par + * When a stream is initialized, it validates input parameters and allocates the required memory for the + * transfer context array and transfer lists from a private memory heap. The stream is not started and no I/O + * requests are sent to the device until \ref StmK_Start is executed. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Init( + _out KSTM_HANDLE* StreamHandle, + _in KUSB_HANDLE UsbHandle, + _in UCHAR PipeID, + _in INT MaxTransferSize, + _in INT MaxPendingTransfers, + _in INT MaxPendingIO, + _inopt PKSTM_CALLBACK Callbacks, + _inopt KSTM_FLAG Flags); + +//! Frees resources allocated by a stream handle. + /*! + * + * \param[in] StreamHandle + * The stream handle to free. + * + * \returns TRUE. + * + * If the stream is currently started it is automatically stopped before its resources are freed. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Free( + _in KSTM_HANDLE StreamHandle); + +//! Starts the internal stream thread. + /*! + * + * \param[in] StreamHandle + * The stream to start. A stream handle is created with \ref StmK_Init. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \par + * When a stream is started, an internal thread is created for managing pipe I/O operations. If a + * \ref KSTM_CALLBACK::Started callback function is assgined, it is executed \b for each transfer context. + * (\b MaxPendingTransfers) See \ref StmK_Init. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Start( + _in KSTM_HANDLE StreamHandle); + +//! Stops the internal stream thread. + /*! + * + * \param[in] StreamHandle + * The stream to stop. + * + * \param[in] TimeoutCancelMS + * Number of milliseconds the internal stream thread should wait for pending I/O to complete before + * cancelling all pending requests. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Stop( + _in KSTM_HANDLE StreamHandle, + _in INT TimeoutCancelMS); + +//! Reads data from the stream buffer. + /*! + * + * \param[in] StreamHandle + * The stream to read. + * + * \param[out] Buffer + * A caller-allocated buffer that receives the data that is read. + * + * \param[in] Offset + * Read start offset of \c Buffer. + * + * \param[in] Length + * Size of \c Buffer. + * + * \param[out] TransferredLength + * On success, receives the actual number of bytes that were copied into \c Buffer. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * - Read Stream Operations: + * -# The internal stream thread will always try and keep reads pending as specified by \b MaxPendingIO in + * \ref StmK_Init. + * -# As the stream submits transfers, it increments the \b PendingIO and \b PendingTransfer counts. As it + * completes transfers, it decrements the \b PendingIO count. As the user processes transfers with + * \ref StmK_Read, it decrements the \b PendingTransfer count and release control of the transfer context + * back to the stream where it is re-used. + * -# When the pending I/O count reaches \c MaxPendingIO, the stream completes the oldest + * \b PendingTransfer and moves it into a FIFO complete where it awaits user processing via the + * \ref StmK_Read function. + * -# If the stream has not exhausted its MaxPendingTransfers count, another read request is submitted + * immediately to satisfy \b MaxPendingIO. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Read( + _in KSTM_HANDLE StreamHandle, + _out PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength); + +//! Writes data to the stream buffer. + /*! + * + * \param[in] StreamHandle + * The stream to write. + * + * \param[in] Buffer + * A caller-allocated buffer the data is written from. + * + * \param[in] Offset + * Write start offset of \c Buffer. + * + * \param[in] Length + * Number of bytes to copy into the stream buffer. + * + * \param[out] TransferredLength + * On success, receives the actual number of bytes that were copied into the stream buffer. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * - Write Stream Operations: + * -# The internal stream thread will always try and exhaust all pending transfers submitted by the user + * via \ref StmK_Write. + * -# As the user submits transfers via \ref StmK_Write, the \b PendingTransfer count is inceremented and + * transfers are added to a queued FIFO list where they await processing by the internal stream thread. + * -# While the queued FIFO list is not empty and \b PendingIO count is less than \b MaxPendingIO, The + * \b PendingIO count increments and the request is sent to the device. + * -# When a transfer completes, the internal pending I/O count is decremented and the transfers is moved + * back into the idle list where it can be reused again by subsequent \ref StmK_Write requests. + * + */ + KUSB_EXP BOOL KUSB_API StmK_Write( + _in KSTM_HANDLE StreamHandle, + _in PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength); + /**@}*/ + +#endif + +#ifndef _LIBUSBK_ISOK_FUNCTIONS + /*! \addtogroup isok + * @{ + */ + +//! Creates a new isochronous transfer context. + /*! + * + * \param[out] IsoContext + * Receives a new isochronous transfer context. + * + * \param[in] NumberOfPackets + * The number of \ref KISO_PACKET structures allocated to \c IsoContext. Assigned to + * \ref KISO_CONTEXT::NumberOfPackets. The \ref KISO_CONTEXT::NumberOfPackets field is assignable by + * \c IsoK_Init only and must not be changed by the user. + * + * \param[in] StartFrame + * The USB frame number this request must start on (or \b 0 for ASAP) and assigned to + * \ref KISO_CONTEXT::StartFrame. The \ref KISO_CONTEXT::StartFrame may be chamged by the user in subsequent + * request. For more information, see \ref KISO_CONTEXT::StartFrame. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c IsoK_Init is performs the following tasks in order: + * -# Allocates the \c IsoContext and the required \ref KISO_PACKET structures. + * -# Zero-initializes all ISO context memory. + * -# Assigns \b NumberOfPackets, \b PipeID, and \b StartFrame to \c IsoContext. + * + */ + KUSB_EXP BOOL KUSB_API IsoK_Init( + _out PKISO_CONTEXT* IsoContext, + _in INT NumberOfPackets, + _inopt INT StartFrame); + +//! Destroys an isochronous transfer context. + /*! + * \param[in] IsoContext + * A pointer to an isochronous transfer context created with \ref IsoK_Init. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + */ + KUSB_EXP BOOL KUSB_API IsoK_Free( + _in PKISO_CONTEXT IsoContext); + +//! Convenience function for setting the offset of all ISO packets of an isochronous transfer context. + /*! + * \param[in] IsoContext + * A pointer to an isochronous transfer context. + * + * \param[in] PacketSize + * The packet size used to calculate and assign the absolute data offset for each \ref KISO_PACKET in + * \c IsoContext. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c IsoK_SetPackets updates all \ref KISO_PACKET::Offset fields in a \ref KISO_CONTEXT so all offset are + * \c PacketSize apart. For example: + * - The offset of the first (0-index) packet is 0. + * - The offset of the second (1-index) packet is PacketSize. + * - The offset of the third (2-index) packet is PacketSize*2. + * + * \code + * for (packetIndex = 0; packetIndex < IsoContext->NumberOfPackets; packetIndex++) + * IsoContext->IsoPackets[packetIndex].Offset = packetIndex * PacketSize; + * \endcode + * + */ + KUSB_EXP BOOL KUSB_API IsoK_SetPackets( + _in PKISO_CONTEXT IsoContext, + _in INT PacketSize); + +//! Convenience function for setting all fields of a \ref KISO_PACKET. + /*! + * \param[in] IsoContext + * A pointer to an isochronous transfer context. + * + * \param[in] PacketIndex + * The packet index to set. + * + * \param[in] IsoPacket + * Pointer to a user allocated \c KISO_PACKET which is copied into the PKISO_CONTEXT::IsoPackets array at the + * specified index. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + */ + KUSB_EXP BOOL KUSB_API IsoK_SetPacket( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _in PKISO_PACKET IsoPacket); + +//! Convenience function for getting all fields of a \ref KISO_PACKET. + /*! + * \param[in] IsoContext + * A pointer to an isochronous transfer context. + * + * \param[in] PacketIndex + * The packet index to get. + * + * \param[out] IsoPacket + * Pointer to a user allocated \c KISO_PACKET which receives a copy of the ISO packet in the + * PKISO_CONTEXT::IsoPackets array at the specified index. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + */ + KUSB_EXP BOOL KUSB_API IsoK_GetPacket( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _out PKISO_PACKET IsoPacket); + +//! Convenience function for enumerating ISO packets of an isochronous transfer context. + /*! + * \param[in] IsoContext + * A pointer to an isochronous transfer context. + * + * \param[in] EnumPackets + * Pointer to a user supplied callback function which is executed for all ISO packets in \c IsoContext or + * until the user supplied callback function returns \c FALSE. + * + * \param[in] StartPacketIndex + * The zero-based ISO packet index to begin enumeration at. + * + * \param[in] UserState + * A user defined value which is passed as a parameter to the user supplied callback function. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + */ + KUSB_EXP BOOL KUSB_API IsoK_EnumPackets( + _in PKISO_CONTEXT IsoContext, + _in KISO_ENUM_PACKETS_CB* EnumPackets, + _inopt INT StartPacketIndex, + _inopt PVOID UserState); + +//! Convenience function for re-using an isochronous transfer context in a subsequent request. + /*! + * \param[in,out] IsoContext + * A pointer to an isochronous transfer context. + * + * \returns On success, TRUE. Otherwise FALSE. Use \c GetLastError() to get extended error information. + * + * \c IsoK_ReUse does the following: + * -# Zero-initializes the \b Length and \b Status fields of all \ref KISO_PACKET structures. + * -# Zero-initializes the \b StartFrame and \b ErrorCount of the \ref KISO_CONTEXT. + * + */ + KUSB_EXP BOOL KUSB_API IsoK_ReUse( + _ref PKISO_CONTEXT IsoContext); + + /*! @} */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _LIBUSBK_H__ diff --git a/libs/libusbK/includes/lusbk_dynapi.c b/libs/libusbK/includes/lusbk_dynapi.c new file mode 100644 index 0000000..3b41432 --- /dev/null +++ b/libs/libusbK/includes/lusbk_dynapi.c @@ -0,0 +1,1915 @@ +/*!******************************************************************** +libusbK - Multi-driver USB library. +Copyright (C) 2012 Travis Lee Robinson. All Rights Reserved. +libusb-win32.sourceforge.net + +Development : Travis Lee Robinson (libusbdotnet@gmail.com) +Testing : Xiaofan Chen (xiaofanc@gmail.com) + +At the discretion of the user of this library, this software may be +licensed under the terms of the GNU Public License v3 or a BSD-Style +license as outlined in the following files: +* LICENSE-gpl3.txt +* LICENSE-bsd.txt + +License files are located in a license folder at the root of source and +binary distributions. +********************************************************************!*/ + +#include +#include "libusbk.h" + +#define mLoadLibraryExA LoadLibraryExA +#define mFreeLibrary FreeLibrary + +HMODULE mLibusbK_ModuleHandle = NULL; + +VOID LibusbK_DynApi_Free(VOID); +INT LibusbK_DynApi_Init(_inopt LPCSTR DllFullPathName); + +// Function typedefs: + +typedef VOID KUSB_API LibK_GetVersion_T(_out PKLIB_VERSION Version); + +typedef KLIB_USER_CONTEXT KUSB_API LibK_GetContext_T( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType); + +typedef BOOL KUSB_API LibK_SetContext_T( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue); + +typedef BOOL KUSB_API LibK_SetCleanupCallback_T( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_HANDLE_CLEANUP_CB* CleanupCB); + +typedef BOOL KUSB_API LibK_LoadDriverAPI_T( + _out PKUSB_DRIVER_API DriverAPI, + _in INT DriverID); + +typedef BOOL KUSB_API LibK_CopyDriverAPI_T( + _out PKUSB_DRIVER_API DriverAPI, + _in KUSB_HANDLE UsbHandle); + +typedef BOOL KUSB_API LibK_GetProcAddress_T( + _out KPROC* ProcAddress, + _in INT DriverID, + _in INT FunctionID); + +typedef BOOL KUSB_API LibK_SetDefaultContext_T( + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue); + +typedef KLIB_USER_CONTEXT KUSB_API LibK_GetDefaultContext_T( + _in KLIB_HANDLE_TYPE HandleType); + +typedef BOOL KUSB_API LibK_Context_Init_T( + _inopt HANDLE Heap, + _in PVOID Reserved); + +typedef VOID KUSB_API LibK_Context_Free_T(VOID); + +typedef BOOL KUSB_API UsbK_Init_T ( + _out KUSB_HANDLE* InterfaceHandle, + _in KLST_DEVINFO_HANDLE DevInfo); + +typedef BOOL KUSB_API UsbK_Free_T ( + _in KUSB_HANDLE InterfaceHandle); + +typedef BOOL KUSB_API UsbK_ClaimInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API UsbK_ReleaseInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API UsbK_SetAltInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _in UCHAR AltSettingNumber); + +typedef BOOL KUSB_API UsbK_GetAltInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _out PUCHAR AltSettingNumber); + +typedef BOOL KUSB_API UsbK_GetDescriptor_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR DescriptorType, + _in UCHAR Index, + _in USHORT LanguageID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred); + +typedef BOOL KUSB_API UsbK_ControlTransfer_T ( + _in KUSB_HANDLE InterfaceHandle, + _in WINUSB_SETUP_PACKET SetupPacket, + _refopt PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API UsbK_SetPowerPolicy_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +typedef BOOL KUSB_API UsbK_GetPowerPolicy_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +typedef BOOL KUSB_API UsbK_SetConfiguration_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR ConfigurationNumber); + +typedef BOOL KUSB_API UsbK_GetConfiguration_T ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR ConfigurationNumber); + +typedef BOOL KUSB_API UsbK_ResetDevice_T ( + _in KUSB_HANDLE InterfaceHandle); + +typedef BOOL KUSB_API UsbK_Initialize_T ( + _in HANDLE DeviceHandle, + _out KUSB_HANDLE* InterfaceHandle); + +typedef BOOL KUSB_API UsbK_SelectInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex); + +typedef BOOL KUSB_API UsbK_GetAssociatedInterface_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AssociatedInterfaceIndex, + _out KUSB_HANDLE* AssociatedInterfaceHandle); + +typedef BOOL KUSB_API UsbK_Clone_T ( + _in KUSB_HANDLE InterfaceHandle, + _out KUSB_HANDLE* DstInterfaceHandle); + +typedef BOOL KUSB_API UsbK_QueryInterfaceSettings_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingIndex, + _out PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor); + +typedef BOOL KUSB_API UsbK_QueryDeviceInformation_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT InformationType, + _ref PUINT BufferLength, + _ref PVOID Buffer); + +typedef BOOL KUSB_API UsbK_SetCurrentAlternateSetting_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber); + +typedef BOOL KUSB_API UsbK_GetCurrentAlternateSetting_T ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR AltSettingNumber); + +typedef BOOL KUSB_API UsbK_QueryPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber, + _in UCHAR PipeIndex, + _out PWINUSB_PIPE_INFORMATION PipeInformation); + +typedef BOOL KUSB_API UsbK_SetPipePolicy_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value); + +typedef BOOL KUSB_API UsbK_GetPipePolicy_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value); + +typedef BOOL KUSB_API UsbK_ReadPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API UsbK_WritePipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped); + +typedef BOOL KUSB_API UsbK_ResetPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API UsbK_AbortPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API UsbK_FlushPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID); + +typedef BOOL KUSB_API UsbK_IsoReadPipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +typedef BOOL KUSB_API UsbK_IsoWritePipe_T ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext); + +typedef BOOL KUSB_API UsbK_GetCurrentFrameNumber_T ( + _in KUSB_HANDLE InterfaceHandle, + _out PUINT FrameNumber); + +typedef BOOL KUSB_API UsbK_GetOverlappedResult_T ( + _in KUSB_HANDLE InterfaceHandle, + _in LPOVERLAPPED Overlapped, + _out PUINT lpNumberOfBytesTransferred, + _in BOOL bWait); + +typedef BOOL KUSB_API UsbK_GetProperty_T ( + _in KUSB_HANDLE InterfaceHandle, + _in KUSB_PROPERTY PropertyType, + _ref PUINT PropertySize, + _out PVOID Value); + +typedef BOOL KUSB_API LstK_Init_T( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags); + +typedef BOOL KUSB_API LstK_InitEx_T( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags, + _in PKLST_PATTERN_MATCH PatternMatch); + +typedef BOOL KUSB_API LstK_Free_T( + _in KLST_HANDLE DeviceList); + +typedef BOOL KUSB_API LstK_Enumerate_T( + _in KLST_HANDLE DeviceList, + _in KLST_ENUM_DEVINFO_CB* EnumDevListCB, + _inopt PVOID Context); + +typedef BOOL KUSB_API LstK_Current_T( + _in KLST_HANDLE DeviceList, + _out KLST_DEVINFO_HANDLE* DeviceInfo); + +typedef BOOL KUSB_API LstK_MoveNext_T( + _in KLST_HANDLE DeviceList, + _outopt KLST_DEVINFO_HANDLE* DeviceInfo); + +typedef VOID KUSB_API LstK_MoveReset_T( + _in KLST_HANDLE DeviceList); + +typedef BOOL KUSB_API LstK_FindByVidPid_T( + _in KLST_HANDLE DeviceList, + _in INT Vid, + _in INT Pid, + _out KLST_DEVINFO_HANDLE* DeviceInfo); + +typedef BOOL KUSB_API LstK_Count_T( + _in KLST_HANDLE DeviceList, + _ref PUINT Count); + +typedef BOOL KUSB_API HotK_Init_T( + _out KHOT_HANDLE* Handle, + _ref PKHOT_PARAMS InitParams); + +typedef BOOL KUSB_API HotK_Free_T( + _in KHOT_HANDLE Handle); + +typedef VOID KUSB_API HotK_FreeAll_T(VOID); + +typedef BOOL KUSB_API OvlK_Acquire_T( + _out KOVL_HANDLE* OverlappedK, + _in KOVL_POOL_HANDLE PoolHandle); + +typedef BOOL KUSB_API OvlK_Release_T( + _in KOVL_HANDLE OverlappedK); + +typedef BOOL KUSB_API OvlK_Init_T ( + _out KOVL_POOL_HANDLE* PoolHandle, + _in KUSB_HANDLE UsbHandle, + _in INT MaxOverlappedCount, + _inopt KOVL_POOL_FLAG Flags); + +typedef BOOL KUSB_API OvlK_Free_T( + _in KOVL_POOL_HANDLE PoolHandle); + +typedef HANDLE KUSB_API OvlK_GetEventHandle_T( + _in KOVL_HANDLE OverlappedK); + +typedef BOOL KUSB_API OvlK_Wait_T( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API OvlK_WaitOldest_T( + _in KOVL_POOL_HANDLE PoolHandle, + _outopt KOVL_HANDLE* OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API OvlK_WaitOrCancel_T( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API OvlK_WaitAndRelease_T( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API OvlK_IsComplete_T( + _in KOVL_HANDLE OverlappedK); + +typedef BOOL KUSB_API OvlK_ReUse_T( + _in KOVL_HANDLE OverlappedK); + +typedef BOOL KUSB_API StmK_Init_T( + _out KSTM_HANDLE* StreamHandle, + _in KUSB_HANDLE UsbHandle, + _in UCHAR PipeID, + _in INT MaxTransferSize, + _in INT MaxPendingTransfers, + _in INT MaxPendingIO, + _inopt PKSTM_CALLBACK Callbacks, + _inopt KSTM_FLAG Flags); + +typedef BOOL KUSB_API StmK_Free_T( + _in KSTM_HANDLE StreamHandle); + +typedef BOOL KUSB_API StmK_Start_T( + _in KSTM_HANDLE StreamHandle); + +typedef BOOL KUSB_API StmK_Stop_T( + _in KSTM_HANDLE StreamHandle, + _in INT TimeoutCancelMS); + +typedef BOOL KUSB_API StmK_Read_T( + _in KSTM_HANDLE StreamHandle, + _out PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API StmK_Write_T( + _in KSTM_HANDLE StreamHandle, + _in PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength); + +typedef BOOL KUSB_API IsoK_Init_T( + _out PKISO_CONTEXT* IsoContext, + _in INT NumberOfPackets, + _inopt INT StartFrame); + +typedef BOOL KUSB_API IsoK_Free_T( + _in PKISO_CONTEXT IsoContext); + +typedef BOOL KUSB_API IsoK_SetPackets_T( + _in PKISO_CONTEXT IsoContext, + _in INT PacketSize); + +typedef BOOL KUSB_API IsoK_SetPacket_T( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _in PKISO_PACKET IsoPacket); + +typedef BOOL KUSB_API IsoK_GetPacket_T( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _out PKISO_PACKET IsoPacket); + +typedef BOOL KUSB_API IsoK_EnumPackets_T( + _in PKISO_CONTEXT IsoContext, + _in KISO_ENUM_PACKETS_CB* EnumPackets, + _inopt INT StartPacketIndex, + _inopt PVOID UserState); + +typedef BOOL KUSB_API IsoK_ReUse_T( + _ref PKISO_CONTEXT IsoContext); + + + +/////////////////////////////////////////////////////////////////////// + +// Function pointers: + +static LibK_GetVersion_T* pLibK_GetVersion = NULL; + +static LibK_GetContext_T* pLibK_GetContext = NULL; + +static LibK_SetContext_T* pLibK_SetContext = NULL; + +static LibK_SetCleanupCallback_T* pLibK_SetCleanupCallback = NULL; + +static LibK_LoadDriverAPI_T* pLibK_LoadDriverAPI = NULL; + +static LibK_CopyDriverAPI_T* pLibK_CopyDriverAPI = NULL; + +static LibK_GetProcAddress_T* pLibK_GetProcAddress = NULL; + +static LibK_SetDefaultContext_T* pLibK_SetDefaultContext = NULL; + +static LibK_GetDefaultContext_T* pLibK_GetDefaultContext = NULL; + +static LibK_Context_Init_T* pLibK_Context_Init = NULL; + +static LibK_Context_Free_T* pLibK_Context_Free = NULL; + +static UsbK_Init_T* pUsbK_Init = NULL; + +static UsbK_Free_T* pUsbK_Free = NULL; + +static UsbK_ClaimInterface_T* pUsbK_ClaimInterface = NULL; + +static UsbK_ReleaseInterface_T* pUsbK_ReleaseInterface = NULL; + +static UsbK_SetAltInterface_T* pUsbK_SetAltInterface = NULL; + +static UsbK_GetAltInterface_T* pUsbK_GetAltInterface = NULL; + +static UsbK_GetDescriptor_T* pUsbK_GetDescriptor = NULL; + +static UsbK_ControlTransfer_T* pUsbK_ControlTransfer = NULL; + +static UsbK_SetPowerPolicy_T* pUsbK_SetPowerPolicy = NULL; + +static UsbK_GetPowerPolicy_T* pUsbK_GetPowerPolicy = NULL; + +static UsbK_SetConfiguration_T* pUsbK_SetConfiguration = NULL; + +static UsbK_GetConfiguration_T* pUsbK_GetConfiguration = NULL; + +static UsbK_ResetDevice_T* pUsbK_ResetDevice = NULL; + +static UsbK_Initialize_T* pUsbK_Initialize = NULL; + +static UsbK_SelectInterface_T* pUsbK_SelectInterface = NULL; + +static UsbK_GetAssociatedInterface_T* pUsbK_GetAssociatedInterface = NULL; + +static UsbK_Clone_T* pUsbK_Clone = NULL; + +static UsbK_QueryInterfaceSettings_T* pUsbK_QueryInterfaceSettings = NULL; + +static UsbK_QueryDeviceInformation_T* pUsbK_QueryDeviceInformation = NULL; + +static UsbK_SetCurrentAlternateSetting_T* pUsbK_SetCurrentAlternateSetting = NULL; + +static UsbK_GetCurrentAlternateSetting_T* pUsbK_GetCurrentAlternateSetting = NULL; + +static UsbK_QueryPipe_T* pUsbK_QueryPipe = NULL; + +static UsbK_SetPipePolicy_T* pUsbK_SetPipePolicy = NULL; + +static UsbK_GetPipePolicy_T* pUsbK_GetPipePolicy = NULL; + +static UsbK_ReadPipe_T* pUsbK_ReadPipe = NULL; + +static UsbK_WritePipe_T* pUsbK_WritePipe = NULL; + +static UsbK_ResetPipe_T* pUsbK_ResetPipe = NULL; + +static UsbK_AbortPipe_T* pUsbK_AbortPipe = NULL; + +static UsbK_FlushPipe_T* pUsbK_FlushPipe = NULL; + +static UsbK_IsoReadPipe_T* pUsbK_IsoReadPipe = NULL; + +static UsbK_IsoWritePipe_T* pUsbK_IsoWritePipe = NULL; + +static UsbK_GetCurrentFrameNumber_T* pUsbK_GetCurrentFrameNumber = NULL; + +static UsbK_GetOverlappedResult_T* pUsbK_GetOverlappedResult = NULL; + +static UsbK_GetProperty_T* pUsbK_GetProperty = NULL; + +static LstK_Init_T* pLstK_Init = NULL; + +static LstK_InitEx_T* pLstK_InitEx = NULL; + +static LstK_Free_T* pLstK_Free = NULL; + +static LstK_Enumerate_T* pLstK_Enumerate = NULL; + +static LstK_Current_T* pLstK_Current = NULL; + +static LstK_MoveNext_T* pLstK_MoveNext = NULL; + +static LstK_MoveReset_T* pLstK_MoveReset = NULL; + +static LstK_FindByVidPid_T* pLstK_FindByVidPid = NULL; + +static LstK_Count_T* pLstK_Count = NULL; + +static HotK_Init_T* pHotK_Init = NULL; + +static HotK_Free_T* pHotK_Free = NULL; + +static HotK_FreeAll_T* pHotK_FreeAll = NULL; + +static OvlK_Acquire_T* pOvlK_Acquire = NULL; + +static OvlK_Release_T* pOvlK_Release = NULL; + +static OvlK_Init_T* pOvlK_Init = NULL; + +static OvlK_Free_T* pOvlK_Free = NULL; + +static OvlK_GetEventHandle_T* pOvlK_GetEventHandle = NULL; + +static OvlK_Wait_T* pOvlK_Wait = NULL; + +static OvlK_WaitOldest_T* pOvlK_WaitOldest = NULL; + +static OvlK_WaitOrCancel_T* pOvlK_WaitOrCancel = NULL; + +static OvlK_WaitAndRelease_T* pOvlK_WaitAndRelease = NULL; + +static OvlK_IsComplete_T* pOvlK_IsComplete = NULL; + +static OvlK_ReUse_T* pOvlK_ReUse = NULL; + +static StmK_Init_T* pStmK_Init = NULL; + +static StmK_Free_T* pStmK_Free = NULL; + +static StmK_Start_T* pStmK_Start = NULL; + +static StmK_Stop_T* pStmK_Stop = NULL; + +static StmK_Read_T* pStmK_Read = NULL; + +static StmK_Write_T* pStmK_Write = NULL; + +static IsoK_Init_T* pIsoK_Init = NULL; + +static IsoK_Free_T* pIsoK_Free = NULL; + +static IsoK_SetPackets_T* pIsoK_SetPackets = NULL; + +static IsoK_SetPacket_T* pIsoK_SetPacket = NULL; + +static IsoK_GetPacket_T* pIsoK_GetPacket = NULL; + +static IsoK_EnumPackets_T* pIsoK_EnumPackets = NULL; + +static IsoK_ReUse_T* pIsoK_ReUse = NULL; + + + +/////////////////////////////////////////////////////////////////////// + + +VOID LibusbK_DynApi_Free(VOID) +{ + if (mLibusbK_ModuleHandle) + { + mFreeLibrary(mLibusbK_ModuleHandle); + mLibusbK_ModuleHandle = NULL; + + // Set all function pointers to null: + + pLibK_GetVersion = NULL; + + pLibK_GetContext = NULL; + + pLibK_SetContext = NULL; + + pLibK_SetCleanupCallback = NULL; + + pLibK_LoadDriverAPI = NULL; + + pLibK_CopyDriverAPI = NULL; + + pLibK_GetProcAddress = NULL; + + pLibK_SetDefaultContext = NULL; + + pLibK_GetDefaultContext = NULL; + + pLibK_Context_Init = NULL; + + pLibK_Context_Free = NULL; + + pUsbK_Init = NULL; + + pUsbK_Free = NULL; + + pUsbK_ClaimInterface = NULL; + + pUsbK_ReleaseInterface = NULL; + + pUsbK_SetAltInterface = NULL; + + pUsbK_GetAltInterface = NULL; + + pUsbK_GetDescriptor = NULL; + + pUsbK_ControlTransfer = NULL; + + pUsbK_SetPowerPolicy = NULL; + + pUsbK_GetPowerPolicy = NULL; + + pUsbK_SetConfiguration = NULL; + + pUsbK_GetConfiguration = NULL; + + pUsbK_ResetDevice = NULL; + + pUsbK_Initialize = NULL; + + pUsbK_SelectInterface = NULL; + + pUsbK_GetAssociatedInterface = NULL; + + pUsbK_Clone = NULL; + + pUsbK_QueryInterfaceSettings = NULL; + + pUsbK_QueryDeviceInformation = NULL; + + pUsbK_SetCurrentAlternateSetting = NULL; + + pUsbK_GetCurrentAlternateSetting = NULL; + + pUsbK_QueryPipe = NULL; + + pUsbK_SetPipePolicy = NULL; + + pUsbK_GetPipePolicy = NULL; + + pUsbK_ReadPipe = NULL; + + pUsbK_WritePipe = NULL; + + pUsbK_ResetPipe = NULL; + + pUsbK_AbortPipe = NULL; + + pUsbK_FlushPipe = NULL; + + pUsbK_IsoReadPipe = NULL; + + pUsbK_IsoWritePipe = NULL; + + pUsbK_GetCurrentFrameNumber = NULL; + + pUsbK_GetOverlappedResult = NULL; + + pUsbK_GetProperty = NULL; + + pLstK_Init = NULL; + + pLstK_InitEx = NULL; + + pLstK_Free = NULL; + + pLstK_Enumerate = NULL; + + pLstK_Current = NULL; + + pLstK_MoveNext = NULL; + + pLstK_MoveReset = NULL; + + pLstK_FindByVidPid = NULL; + + pLstK_Count = NULL; + + pHotK_Init = NULL; + + pHotK_Free = NULL; + + pHotK_FreeAll = NULL; + + pOvlK_Acquire = NULL; + + pOvlK_Release = NULL; + + pOvlK_Init = NULL; + + pOvlK_Free = NULL; + + pOvlK_GetEventHandle = NULL; + + pOvlK_Wait = NULL; + + pOvlK_WaitOldest = NULL; + + pOvlK_WaitOrCancel = NULL; + + pOvlK_WaitAndRelease = NULL; + + pOvlK_IsComplete = NULL; + + pOvlK_ReUse = NULL; + + pStmK_Init = NULL; + + pStmK_Free = NULL; + + pStmK_Start = NULL; + + pStmK_Stop = NULL; + + pStmK_Read = NULL; + + pStmK_Write = NULL; + + pIsoK_Init = NULL; + + pIsoK_Free = NULL; + + pIsoK_SetPackets = NULL; + + pIsoK_SetPacket = NULL; + + pIsoK_GetPacket = NULL; + + pIsoK_EnumPackets = NULL; + + pIsoK_ReUse = NULL; + + + + /////////////////////////////////////////////////////////////////////// + } +} + +INT LibusbK_DynApi_Init(_inopt LPCSTR DllFullPathName) +{ + LPCSTR dllFullPathName = (DllFullPathName == NULL) ? "libusbK.dll" : DllFullPathName; + INT funcLoadFailCount = 0; + + if (mLibusbK_ModuleHandle) LibusbK_DynApi_Free(); + + if (DllFullPathName) + mLibusbK_ModuleHandle = mLoadLibraryExA(dllFullPathName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + else + mLibusbK_ModuleHandle = mLoadLibraryExA(dllFullPathName, NULL, 0); + + if (mLibusbK_ModuleHandle == NULL) return -1; + + + // Function loads: + + if ((pLibK_GetVersion = (LibK_GetVersion_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_GetVersion")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_GetVersion.\n"); + } + + if ((pLibK_GetContext = (LibK_GetContext_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_GetContext")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_GetContext.\n"); + } + + if ((pLibK_SetContext = (LibK_SetContext_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_SetContext")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_SetContext.\n"); + } + + if ((pLibK_SetCleanupCallback = (LibK_SetCleanupCallback_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_SetCleanupCallback")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_SetCleanupCallback.\n"); + } + + if ((pLibK_LoadDriverAPI = (LibK_LoadDriverAPI_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_LoadDriverAPI")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_LoadDriverAPI.\n"); + } + + if ((pLibK_CopyDriverAPI = (LibK_CopyDriverAPI_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_CopyDriverAPI")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_CopyDriverAPI.\n"); + } + + if ((pLibK_GetProcAddress = (LibK_GetProcAddress_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_GetProcAddress")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_GetProcAddress.\n"); + } + + if ((pLibK_SetDefaultContext = (LibK_SetDefaultContext_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_SetDefaultContext")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_SetDefaultContext.\n"); + } + + if ((pLibK_GetDefaultContext = (LibK_GetDefaultContext_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_GetDefaultContext")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_GetDefaultContext.\n"); + } + + if ((pLibK_Context_Init = (LibK_Context_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_Context_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_Context_Init.\n"); + } + + if ((pLibK_Context_Free = (LibK_Context_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "LibK_Context_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LibK_Context_Free.\n"); + } + + if ((pUsbK_Init = (UsbK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_Init.\n"); + } + + if ((pUsbK_Free = (UsbK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_Free.\n"); + } + + if ((pUsbK_ClaimInterface = (UsbK_ClaimInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ClaimInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ClaimInterface.\n"); + } + + if ((pUsbK_ReleaseInterface = (UsbK_ReleaseInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ReleaseInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ReleaseInterface.\n"); + } + + if ((pUsbK_SetAltInterface = (UsbK_SetAltInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SetAltInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SetAltInterface.\n"); + } + + if ((pUsbK_GetAltInterface = (UsbK_GetAltInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetAltInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetAltInterface.\n"); + } + + if ((pUsbK_GetDescriptor = (UsbK_GetDescriptor_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetDescriptor")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetDescriptor.\n"); + } + + if ((pUsbK_ControlTransfer = (UsbK_ControlTransfer_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ControlTransfer")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ControlTransfer.\n"); + } + + if ((pUsbK_SetPowerPolicy = (UsbK_SetPowerPolicy_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SetPowerPolicy")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SetPowerPolicy.\n"); + } + + if ((pUsbK_GetPowerPolicy = (UsbK_GetPowerPolicy_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetPowerPolicy")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetPowerPolicy.\n"); + } + + if ((pUsbK_SetConfiguration = (UsbK_SetConfiguration_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SetConfiguration")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SetConfiguration.\n"); + } + + if ((pUsbK_GetConfiguration = (UsbK_GetConfiguration_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetConfiguration")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetConfiguration.\n"); + } + + if ((pUsbK_ResetDevice = (UsbK_ResetDevice_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ResetDevice")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ResetDevice.\n"); + } + + if ((pUsbK_Initialize = (UsbK_Initialize_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_Initialize")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_Initialize.\n"); + } + + if ((pUsbK_SelectInterface = (UsbK_SelectInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SelectInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SelectInterface.\n"); + } + + if ((pUsbK_GetAssociatedInterface = (UsbK_GetAssociatedInterface_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetAssociatedInterface")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetAssociatedInterface.\n"); + } + + if ((pUsbK_Clone = (UsbK_Clone_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_Clone")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_Clone.\n"); + } + + if ((pUsbK_QueryInterfaceSettings = (UsbK_QueryInterfaceSettings_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_QueryInterfaceSettings")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_QueryInterfaceSettings.\n"); + } + + if ((pUsbK_QueryDeviceInformation = (UsbK_QueryDeviceInformation_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_QueryDeviceInformation")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_QueryDeviceInformation.\n"); + } + + if ((pUsbK_SetCurrentAlternateSetting = (UsbK_SetCurrentAlternateSetting_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SetCurrentAlternateSetting")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SetCurrentAlternateSetting.\n"); + } + + if ((pUsbK_GetCurrentAlternateSetting = (UsbK_GetCurrentAlternateSetting_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetCurrentAlternateSetting")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetCurrentAlternateSetting.\n"); + } + + if ((pUsbK_QueryPipe = (UsbK_QueryPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_QueryPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_QueryPipe.\n"); + } + + if ((pUsbK_SetPipePolicy = (UsbK_SetPipePolicy_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_SetPipePolicy")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_SetPipePolicy.\n"); + } + + if ((pUsbK_GetPipePolicy = (UsbK_GetPipePolicy_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetPipePolicy")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetPipePolicy.\n"); + } + + if ((pUsbK_ReadPipe = (UsbK_ReadPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ReadPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ReadPipe.\n"); + } + + if ((pUsbK_WritePipe = (UsbK_WritePipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_WritePipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_WritePipe.\n"); + } + + if ((pUsbK_ResetPipe = (UsbK_ResetPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_ResetPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_ResetPipe.\n"); + } + + if ((pUsbK_AbortPipe = (UsbK_AbortPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_AbortPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_AbortPipe.\n"); + } + + if ((pUsbK_FlushPipe = (UsbK_FlushPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_FlushPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_FlushPipe.\n"); + } + + if ((pUsbK_IsoReadPipe = (UsbK_IsoReadPipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_IsoReadPipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_IsoReadPipe.\n"); + } + + if ((pUsbK_IsoWritePipe = (UsbK_IsoWritePipe_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_IsoWritePipe")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_IsoWritePipe.\n"); + } + + if ((pUsbK_GetCurrentFrameNumber = (UsbK_GetCurrentFrameNumber_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetCurrentFrameNumber")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetCurrentFrameNumber.\n"); + } + + if ((pUsbK_GetOverlappedResult = (UsbK_GetOverlappedResult_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetOverlappedResult")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetOverlappedResult.\n"); + } + + if ((pUsbK_GetProperty = (UsbK_GetProperty_T*)GetProcAddress(mLibusbK_ModuleHandle, "UsbK_GetProperty")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function UsbK_GetProperty.\n"); + } + + if ((pLstK_Init = (LstK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_Init.\n"); + } + + if ((pLstK_InitEx = (LstK_InitEx_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_InitEx")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_InitEx.\n"); + } + + if ((pLstK_Free = (LstK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_Free.\n"); + } + + if ((pLstK_Enumerate = (LstK_Enumerate_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_Enumerate")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_Enumerate.\n"); + } + + if ((pLstK_Current = (LstK_Current_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_Current")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_Current.\n"); + } + + if ((pLstK_MoveNext = (LstK_MoveNext_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_MoveNext")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_MoveNext.\n"); + } + + if ((pLstK_MoveReset = (LstK_MoveReset_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_MoveReset")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_MoveReset.\n"); + } + + if ((pLstK_FindByVidPid = (LstK_FindByVidPid_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_FindByVidPid")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_FindByVidPid.\n"); + } + + if ((pLstK_Count = (LstK_Count_T*)GetProcAddress(mLibusbK_ModuleHandle, "LstK_Count")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function LstK_Count.\n"); + } + + if ((pHotK_Init = (HotK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "HotK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function HotK_Init.\n"); + } + + if ((pHotK_Free = (HotK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "HotK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function HotK_Free.\n"); + } + + if ((pHotK_FreeAll = (HotK_FreeAll_T*)GetProcAddress(mLibusbK_ModuleHandle, "HotK_FreeAll")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function HotK_FreeAll.\n"); + } + + if ((pOvlK_Acquire = (OvlK_Acquire_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_Acquire")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_Acquire.\n"); + } + + if ((pOvlK_Release = (OvlK_Release_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_Release")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_Release.\n"); + } + + if ((pOvlK_Init = (OvlK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_Init.\n"); + } + + if ((pOvlK_Free = (OvlK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_Free.\n"); + } + + if ((pOvlK_GetEventHandle = (OvlK_GetEventHandle_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_GetEventHandle")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_GetEventHandle.\n"); + } + + if ((pOvlK_Wait = (OvlK_Wait_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_Wait")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_Wait.\n"); + } + + if ((pOvlK_WaitOldest = (OvlK_WaitOldest_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_WaitOldest")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_WaitOldest.\n"); + } + + if ((pOvlK_WaitOrCancel = (OvlK_WaitOrCancel_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_WaitOrCancel")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_WaitOrCancel.\n"); + } + + if ((pOvlK_WaitAndRelease = (OvlK_WaitAndRelease_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_WaitAndRelease")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_WaitAndRelease.\n"); + } + + if ((pOvlK_IsComplete = (OvlK_IsComplete_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_IsComplete")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_IsComplete.\n"); + } + + if ((pOvlK_ReUse = (OvlK_ReUse_T*)GetProcAddress(mLibusbK_ModuleHandle, "OvlK_ReUse")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function OvlK_ReUse.\n"); + } + + if ((pStmK_Init = (StmK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Init.\n"); + } + + if ((pStmK_Free = (StmK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Free.\n"); + } + + if ((pStmK_Start = (StmK_Start_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Start")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Start.\n"); + } + + if ((pStmK_Stop = (StmK_Stop_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Stop")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Stop.\n"); + } + + if ((pStmK_Read = (StmK_Read_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Read")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Read.\n"); + } + + if ((pStmK_Write = (StmK_Write_T*)GetProcAddress(mLibusbK_ModuleHandle, "StmK_Write")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function StmK_Write.\n"); + } + + if ((pIsoK_Init = (IsoK_Init_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_Init")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_Init.\n"); + } + + if ((pIsoK_Free = (IsoK_Free_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_Free")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_Free.\n"); + } + + if ((pIsoK_SetPackets = (IsoK_SetPackets_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_SetPackets")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_SetPackets.\n"); + } + + if ((pIsoK_SetPacket = (IsoK_SetPacket_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_SetPacket")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_SetPacket.\n"); + } + + if ((pIsoK_GetPacket = (IsoK_GetPacket_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_GetPacket")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_GetPacket.\n"); + } + + if ((pIsoK_EnumPackets = (IsoK_EnumPackets_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_EnumPackets")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_EnumPackets.\n"); + } + + if ((pIsoK_ReUse = (IsoK_ReUse_T*)GetProcAddress(mLibusbK_ModuleHandle, "IsoK_ReUse")) == NULL) + { + funcLoadFailCount++; + OutputDebugStringA("Failed loading function IsoK_ReUse.\n"); + } + + + + /////////////////////////////////////////////////////////////////////// + + return funcLoadFailCount; +} + +// Function wrappers: + +KUSB_EXP VOID KUSB_API LibK_GetVersion(_out PKLIB_VERSION Version) +{ + pLibK_GetVersion(Version); +} + +KUSB_EXP KLIB_USER_CONTEXT KUSB_API LibK_GetContext( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType) +{ + return pLibK_GetContext(Handle, HandleType); +} + +KUSB_EXP BOOL KUSB_API LibK_SetContext( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue) +{ + return pLibK_SetContext(Handle, HandleType, ContextValue); +} + +KUSB_EXP BOOL KUSB_API LibK_SetCleanupCallback( + _in KLIB_HANDLE Handle, + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_HANDLE_CLEANUP_CB* CleanupCB) +{ + return pLibK_SetCleanupCallback(Handle, HandleType, CleanupCB); +} + +KUSB_EXP BOOL KUSB_API LibK_LoadDriverAPI( + _out PKUSB_DRIVER_API DriverAPI, + _in INT DriverID) +{ + return pLibK_LoadDriverAPI(DriverAPI, DriverID); +} + +KUSB_EXP BOOL KUSB_API LibK_CopyDriverAPI( + _out PKUSB_DRIVER_API DriverAPI, + _in KUSB_HANDLE UsbHandle) +{ + return pLibK_CopyDriverAPI(DriverAPI, UsbHandle); +} + +KUSB_EXP BOOL KUSB_API LibK_GetProcAddress( + _out KPROC* ProcAddress, + _in INT DriverID, + _in INT FunctionID) +{ + return pLibK_GetProcAddress(ProcAddress, DriverID, FunctionID); +} + +KUSB_EXP BOOL KUSB_API LibK_SetDefaultContext( + _in KLIB_HANDLE_TYPE HandleType, + _in KLIB_USER_CONTEXT ContextValue) +{ + return pLibK_SetDefaultContext(HandleType, ContextValue); +} + +KUSB_EXP KLIB_USER_CONTEXT KUSB_API LibK_GetDefaultContext( + _in KLIB_HANDLE_TYPE HandleType) +{ + return pLibK_GetDefaultContext(HandleType); +} + +KUSB_EXP BOOL KUSB_API LibK_Context_Init( + _inopt HANDLE Heap, + _in PVOID Reserved) +{ + return pLibK_Context_Init(Heap, Reserved); +} + +KUSB_EXP VOID KUSB_API LibK_Context_Free(VOID) +{ + pLibK_Context_Free(); +} + +KUSB_EXP BOOL KUSB_API UsbK_Init ( + _out KUSB_HANDLE* InterfaceHandle, + _in KLST_DEVINFO_HANDLE DevInfo) +{ + return pUsbK_Init(InterfaceHandle, DevInfo); +} + +KUSB_EXP BOOL KUSB_API UsbK_Free ( + _in KUSB_HANDLE InterfaceHandle) +{ + return pUsbK_Free(InterfaceHandle); +} + +KUSB_EXP BOOL KUSB_API UsbK_ClaimInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex) +{ + return pUsbK_ClaimInterface(InterfaceHandle, NumberOrIndex, IsIndex); +} + +KUSB_EXP BOOL KUSB_API UsbK_ReleaseInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex) +{ + return pUsbK_ReleaseInterface(InterfaceHandle, NumberOrIndex, IsIndex); +} + +KUSB_EXP BOOL KUSB_API UsbK_SetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _in UCHAR AltSettingNumber) +{ + return pUsbK_SetAltInterface(InterfaceHandle, NumberOrIndex, IsIndex, AltSettingNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetAltInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex, + _out PUCHAR AltSettingNumber) +{ + return pUsbK_GetAltInterface(InterfaceHandle, NumberOrIndex, IsIndex, AltSettingNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetDescriptor ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR DescriptorType, + _in UCHAR Index, + _in USHORT LanguageID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred) +{ + return pUsbK_GetDescriptor(InterfaceHandle, DescriptorType, Index, LanguageID, Buffer, BufferLength, LengthTransferred); +} + +KUSB_EXP BOOL KUSB_API UsbK_ControlTransfer ( + _in KUSB_HANDLE InterfaceHandle, + _in WINUSB_SETUP_PACKET SetupPacket, + _refopt PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped) +{ + return pUsbK_ControlTransfer(InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); +} + +KUSB_EXP BOOL KUSB_API UsbK_SetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value) +{ + return pUsbK_SetPowerPolicy(InterfaceHandle, PolicyType, ValueLength, Value); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetPowerPolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value) +{ + return pUsbK_GetPowerPolicy(InterfaceHandle, PolicyType, ValueLength, Value); +} + +KUSB_EXP BOOL KUSB_API UsbK_SetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR ConfigurationNumber) +{ + return pUsbK_SetConfiguration(InterfaceHandle, ConfigurationNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetConfiguration ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR ConfigurationNumber) +{ + return pUsbK_GetConfiguration(InterfaceHandle, ConfigurationNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_ResetDevice ( + _in KUSB_HANDLE InterfaceHandle) +{ + return pUsbK_ResetDevice(InterfaceHandle); +} + +KUSB_EXP BOOL KUSB_API UsbK_Initialize ( + _in HANDLE DeviceHandle, + _out KUSB_HANDLE* InterfaceHandle) +{ + return pUsbK_Initialize(DeviceHandle, InterfaceHandle); +} + +KUSB_EXP BOOL KUSB_API UsbK_SelectInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR NumberOrIndex, + _in BOOL IsIndex) +{ + return pUsbK_SelectInterface(InterfaceHandle, NumberOrIndex, IsIndex); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetAssociatedInterface ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AssociatedInterfaceIndex, + _out KUSB_HANDLE* AssociatedInterfaceHandle) +{ + return pUsbK_GetAssociatedInterface(InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); +} + +KUSB_EXP BOOL KUSB_API UsbK_Clone ( + _in KUSB_HANDLE InterfaceHandle, + _out KUSB_HANDLE* DstInterfaceHandle) +{ + return pUsbK_Clone(InterfaceHandle, DstInterfaceHandle); +} + +KUSB_EXP BOOL KUSB_API UsbK_QueryInterfaceSettings ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingIndex, + _out PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor) +{ + return pUsbK_QueryInterfaceSettings(InterfaceHandle, AltSettingIndex, UsbAltInterfaceDescriptor); +} + +KUSB_EXP BOOL KUSB_API UsbK_QueryDeviceInformation ( + _in KUSB_HANDLE InterfaceHandle, + _in UINT InformationType, + _ref PUINT BufferLength, + _ref PVOID Buffer) +{ + return pUsbK_QueryDeviceInformation(InterfaceHandle, InformationType, BufferLength, Buffer); +} + +KUSB_EXP BOOL KUSB_API UsbK_SetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber) +{ + return pUsbK_SetCurrentAlternateSetting(InterfaceHandle, AltSettingNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetCurrentAlternateSetting ( + _in KUSB_HANDLE InterfaceHandle, + _out PUCHAR AltSettingNumber) +{ + return pUsbK_GetCurrentAlternateSetting(InterfaceHandle, AltSettingNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_QueryPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR AltSettingNumber, + _in UCHAR PipeIndex, + _out PWINUSB_PIPE_INFORMATION PipeInformation) +{ + return pUsbK_QueryPipe(InterfaceHandle, AltSettingNumber, PipeIndex, PipeInformation); +} + +KUSB_EXP BOOL KUSB_API UsbK_SetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _in UINT ValueLength, + _in PVOID Value) +{ + return pUsbK_SetPipePolicy(InterfaceHandle, PipeID, PolicyType, ValueLength, Value); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetPipePolicy ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in UINT PolicyType, + _ref PUINT ValueLength, + _out PVOID Value) +{ + return pUsbK_GetPipePolicy(InterfaceHandle, PipeID, PolicyType, ValueLength, Value); +} + +KUSB_EXP BOOL KUSB_API UsbK_ReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped) +{ + return pUsbK_ReadPipe(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); +} + +KUSB_EXP BOOL KUSB_API UsbK_WritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _outopt PUINT LengthTransferred, + _inopt LPOVERLAPPED Overlapped) +{ + return pUsbK_WritePipe(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); +} + +KUSB_EXP BOOL KUSB_API UsbK_ResetPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID) +{ + return pUsbK_ResetPipe(InterfaceHandle, PipeID); +} + +KUSB_EXP BOOL KUSB_API UsbK_AbortPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID) +{ + return pUsbK_AbortPipe(InterfaceHandle, PipeID); +} + +KUSB_EXP BOOL KUSB_API UsbK_FlushPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID) +{ + return pUsbK_FlushPipe(InterfaceHandle, PipeID); +} + +KUSB_EXP BOOL KUSB_API UsbK_IsoReadPipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _out PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext) +{ + return pUsbK_IsoReadPipe(InterfaceHandle, PipeID, Buffer, BufferLength, Overlapped, IsoContext); +} + +KUSB_EXP BOOL KUSB_API UsbK_IsoWritePipe ( + _in KUSB_HANDLE InterfaceHandle, + _in UCHAR PipeID, + _in PUCHAR Buffer, + _in UINT BufferLength, + _in LPOVERLAPPED Overlapped, + _refopt PKISO_CONTEXT IsoContext) +{ + return pUsbK_IsoWritePipe(InterfaceHandle, PipeID, Buffer, BufferLength, Overlapped, IsoContext); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetCurrentFrameNumber ( + _in KUSB_HANDLE InterfaceHandle, + _out PUINT FrameNumber) +{ + return pUsbK_GetCurrentFrameNumber(InterfaceHandle, FrameNumber); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetOverlappedResult ( + _in KUSB_HANDLE InterfaceHandle, + _in LPOVERLAPPED Overlapped, + _out PUINT lpNumberOfBytesTransferred, + _in BOOL bWait) +{ + return pUsbK_GetOverlappedResult(InterfaceHandle, Overlapped, lpNumberOfBytesTransferred, bWait); +} + +KUSB_EXP BOOL KUSB_API UsbK_GetProperty ( + _in KUSB_HANDLE InterfaceHandle, + _in KUSB_PROPERTY PropertyType, + _ref PUINT PropertySize, + _out PVOID Value) +{ + return pUsbK_GetProperty(InterfaceHandle, PropertyType, PropertySize, Value); +} + +KUSB_EXP BOOL KUSB_API LstK_Init( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags) +{ + return pLstK_Init(DeviceList, Flags); +} + +KUSB_EXP BOOL KUSB_API LstK_InitEx( + _out KLST_HANDLE* DeviceList, + _in KLST_FLAG Flags, + _in PKLST_PATTERN_MATCH PatternMatch) +{ + return pLstK_InitEx(DeviceList, Flags, PatternMatch); +} + +KUSB_EXP BOOL KUSB_API LstK_Free( + _in KLST_HANDLE DeviceList) +{ + return pLstK_Free(DeviceList); +} + +KUSB_EXP BOOL KUSB_API LstK_Enumerate( + _in KLST_HANDLE DeviceList, + _in KLST_ENUM_DEVINFO_CB* EnumDevListCB, + _inopt PVOID Context) +{ + return pLstK_Enumerate(DeviceList, EnumDevListCB, Context); +} + +KUSB_EXP BOOL KUSB_API LstK_Current( + _in KLST_HANDLE DeviceList, + _out KLST_DEVINFO_HANDLE* DeviceInfo) +{ + return pLstK_Current(DeviceList, DeviceInfo); +} + +KUSB_EXP BOOL KUSB_API LstK_MoveNext( + _in KLST_HANDLE DeviceList, + _outopt KLST_DEVINFO_HANDLE* DeviceInfo) +{ + return pLstK_MoveNext(DeviceList, DeviceInfo); +} + +KUSB_EXP VOID KUSB_API LstK_MoveReset( + _in KLST_HANDLE DeviceList) +{ + pLstK_MoveReset(DeviceList); +} + +KUSB_EXP BOOL KUSB_API LstK_FindByVidPid( + _in KLST_HANDLE DeviceList, + _in INT Vid, + _in INT Pid, + _out KLST_DEVINFO_HANDLE* DeviceInfo) +{ + return pLstK_FindByVidPid(DeviceList, Vid, Pid, DeviceInfo); +} + +KUSB_EXP BOOL KUSB_API LstK_Count( + _in KLST_HANDLE DeviceList, + _ref PUINT Count) +{ + return pLstK_Count(DeviceList, Count); +} + +KUSB_EXP BOOL KUSB_API HotK_Init( + _out KHOT_HANDLE* Handle, + _ref PKHOT_PARAMS InitParams) +{ + return pHotK_Init(Handle, InitParams); +} + +KUSB_EXP BOOL KUSB_API HotK_Free( + _in KHOT_HANDLE Handle) +{ + return pHotK_Free(Handle); +} + +KUSB_EXP VOID KUSB_API HotK_FreeAll(VOID) +{ + pHotK_FreeAll(); +} + +KUSB_EXP BOOL KUSB_API OvlK_Acquire( + _out KOVL_HANDLE* OverlappedK, + _in KOVL_POOL_HANDLE PoolHandle) +{ + return pOvlK_Acquire(OverlappedK, PoolHandle); +} + +KUSB_EXP BOOL KUSB_API OvlK_Release( + _in KOVL_HANDLE OverlappedK) +{ + return pOvlK_Release(OverlappedK); +} + +KUSB_EXP BOOL KUSB_API OvlK_Init ( + _out KOVL_POOL_HANDLE* PoolHandle, + _in KUSB_HANDLE UsbHandle, + _in INT MaxOverlappedCount, + _inopt KOVL_POOL_FLAG Flags) +{ + return pOvlK_Init(PoolHandle, UsbHandle, MaxOverlappedCount, Flags); +} + +KUSB_EXP BOOL KUSB_API OvlK_Free( + _in KOVL_POOL_HANDLE PoolHandle) +{ + return pOvlK_Free(PoolHandle); +} + +KUSB_EXP HANDLE KUSB_API OvlK_GetEventHandle( + _in KOVL_HANDLE OverlappedK) +{ + return pOvlK_GetEventHandle(OverlappedK); +} + +KUSB_EXP BOOL KUSB_API OvlK_Wait( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength) +{ + return pOvlK_Wait(OverlappedK, TimeoutMS, WaitFlags, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API OvlK_WaitOldest( + _in KOVL_POOL_HANDLE PoolHandle, + _outopt KOVL_HANDLE* OverlappedK, + _inopt INT TimeoutMS, + _inopt KOVL_WAIT_FLAG WaitFlags, + _out PUINT TransferredLength) +{ + return pOvlK_WaitOldest(PoolHandle, OverlappedK, TimeoutMS, WaitFlags, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API OvlK_WaitOrCancel( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength) +{ + return pOvlK_WaitOrCancel(OverlappedK, TimeoutMS, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API OvlK_WaitAndRelease( + _in KOVL_HANDLE OverlappedK, + _inopt INT TimeoutMS, + _out PUINT TransferredLength) +{ + return pOvlK_WaitAndRelease(OverlappedK, TimeoutMS, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API OvlK_IsComplete( + _in KOVL_HANDLE OverlappedK) +{ + return pOvlK_IsComplete(OverlappedK); +} + +KUSB_EXP BOOL KUSB_API OvlK_ReUse( + _in KOVL_HANDLE OverlappedK) +{ + return pOvlK_ReUse(OverlappedK); +} + +KUSB_EXP BOOL KUSB_API StmK_Init( + _out KSTM_HANDLE* StreamHandle, + _in KUSB_HANDLE UsbHandle, + _in UCHAR PipeID, + _in INT MaxTransferSize, + _in INT MaxPendingTransfers, + _in INT MaxPendingIO, + _inopt PKSTM_CALLBACK Callbacks, + _inopt KSTM_FLAG Flags) +{ + return pStmK_Init(StreamHandle, UsbHandle, PipeID, MaxTransferSize, MaxPendingTransfers, MaxPendingIO, Callbacks, Flags); +} + +KUSB_EXP BOOL KUSB_API StmK_Free( + _in KSTM_HANDLE StreamHandle) +{ + return pStmK_Free(StreamHandle); +} + +KUSB_EXP BOOL KUSB_API StmK_Start( + _in KSTM_HANDLE StreamHandle) +{ + return pStmK_Start(StreamHandle); +} + +KUSB_EXP BOOL KUSB_API StmK_Stop( + _in KSTM_HANDLE StreamHandle, + _in INT TimeoutCancelMS) +{ + return pStmK_Stop(StreamHandle, TimeoutCancelMS); +} + +KUSB_EXP BOOL KUSB_API StmK_Read( + _in KSTM_HANDLE StreamHandle, + _out PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength) +{ + return pStmK_Read(StreamHandle, Buffer, Offset, Length, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API StmK_Write( + _in KSTM_HANDLE StreamHandle, + _in PUCHAR Buffer, + _in INT Offset, + _in INT Length, + _out PUINT TransferredLength) +{ + return pStmK_Write(StreamHandle, Buffer, Offset, Length, TransferredLength); +} + +KUSB_EXP BOOL KUSB_API IsoK_Init( + _out PKISO_CONTEXT* IsoContext, + _in INT NumberOfPackets, + _inopt INT StartFrame) +{ + return pIsoK_Init(IsoContext, NumberOfPackets, StartFrame); +} + +KUSB_EXP BOOL KUSB_API IsoK_Free( + _in PKISO_CONTEXT IsoContext) +{ + return pIsoK_Free(IsoContext); +} + +KUSB_EXP BOOL KUSB_API IsoK_SetPackets( + _in PKISO_CONTEXT IsoContext, + _in INT PacketSize) +{ + return pIsoK_SetPackets(IsoContext, PacketSize); +} + +KUSB_EXP BOOL KUSB_API IsoK_SetPacket( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _in PKISO_PACKET IsoPacket) +{ + return pIsoK_SetPacket(IsoContext, PacketIndex, IsoPacket); +} + +KUSB_EXP BOOL KUSB_API IsoK_GetPacket( + _in PKISO_CONTEXT IsoContext, + _in INT PacketIndex, + _out PKISO_PACKET IsoPacket) +{ + return pIsoK_GetPacket(IsoContext, PacketIndex, IsoPacket); +} + +KUSB_EXP BOOL KUSB_API IsoK_EnumPackets( + _in PKISO_CONTEXT IsoContext, + _in KISO_ENUM_PACKETS_CB* EnumPackets, + _inopt INT StartPacketIndex, + _inopt PVOID UserState) +{ + return pIsoK_EnumPackets(IsoContext, EnumPackets, StartPacketIndex, UserState); +} + +KUSB_EXP BOOL KUSB_API IsoK_ReUse( + _ref PKISO_CONTEXT IsoContext) +{ + return pIsoK_ReUse(IsoContext); +} + + + +/////////////////////////////////////////////////////////////////////// diff --git a/libs/libusbK/includes/lusbk_shared.h b/libs/libusbK/includes/lusbk_shared.h new file mode 100644 index 0000000..ddfa3fa --- /dev/null +++ b/libs/libusbK/includes/lusbk_shared.h @@ -0,0 +1,309 @@ +/*! \file lusbk_shared.h +* \brief Types and defines shared with the driver. +*/ + +#ifndef __LUSBK_SHARED_H_ +#define __LUSBK_SHARED_H_ + +#ifndef __USB_H__ + +//! Values used in the \c bmAttributes field of a \ref USB_ENDPOINT_DESCRIPTOR +typedef enum _USBD_PIPE_TYPE +{ + //! Indicates a control endpoint + UsbdPipeTypeControl, + + //! Indicates an isochronous endpoint + UsbdPipeTypeIsochronous, + + //! Indicates a bulk endpoint + UsbdPipeTypeBulk, + + //! Indicates an interrupt endpoint + UsbdPipeTypeInterrupt, +} USBD_PIPE_TYPE; + +#endif + +#if !defined(__WINUSB_COMPAT_IO_H__) && !defined(__WUSBIO_H__) + +// pipe policy types /////////////// +#define SHORT_PACKET_TERMINATE 0x01 +#define AUTO_CLEAR_STALL 0x02 +#define PIPE_TRANSFER_TIMEOUT 0x03 +#define IGNORE_SHORT_PACKETS 0x04 +#define ALLOW_PARTIAL_READS 0x05 +#define AUTO_FLUSH 0x06 +#define RAW_IO 0x07 +#define MAXIMUM_TRANSFER_SIZE 0x08 +#define RESET_PIPE_ON_RESUME 0x09 + +// libusbK ISO pipe policy types /// +#define ISO_START_LATENCY 0x20 +#define ISO_ALWAYS_START_ASAP 0x21 +#define ISO_NUM_FIXED_PACKETS 0x22 + +// http://msdn.microsoft.com/en-us/library/windows/hardware/ff552359%28v=vs.85%29.aspx +// Settings.Parallel.NumberOfPresentedRequests +// Maximum number of transfers that can be asynchronously delivered at a +// time. Available in version 1.9 and later versions of KMDF. +#define SIMUL_PARALLEL_REQUESTS 0x30 + +// Power policy types ////////////// +#define AUTO_SUSPEND 0x81 +#define SUSPEND_DELAY 0x83 + +// Device Information types //////// +#define DEVICE_SPEED 0x01 + +// Device Speeds +#define LowSpeed 0x01 +#define FullSpeed 0x02 +#define HighSpeed 0x03 + +//! The \c WINUSB_PIPE_INFORMATION structure contains pipe information that the \ref UsbK_QueryPipe routine retrieves. +typedef struct _WINUSB_PIPE_INFORMATION +{ + //! A \c USBD_PIPE_TYPE enumeration value that specifies the pipe type + USBD_PIPE_TYPE PipeType; + + //! The pipe identifier (ID) + UCHAR PipeId; + + //! The maximum size, in bytes, of the packets that are transmitted on the pipe + USHORT MaximumPacketSize; + + //! The pipe interval + UCHAR Interval; + +} WINUSB_PIPE_INFORMATION; +//! Pointer to a \ref WINUSB_PIPE_INFORMATION structure +typedef WINUSB_PIPE_INFORMATION* PWINUSB_PIPE_INFORMATION; +C_ASSERT(sizeof(WINUSB_PIPE_INFORMATION) == 12); + +#include + +//! The \c WINUSB_SETUP_PACKET structure describes a USB setup packet. +/*! +* It is often more convient to use this structure in combination with a \ref KUSB_SETUP_PACKET. +* For example: +* \code + +* \endcode +*/ +typedef struct _WINUSB_SETUP_PACKET +{ + //! The request type. The values that are assigned to this member are defined in Table 9.2 of section 9.3 of the Universal Serial Bus (USB) specification (www.usb.org). + UCHAR RequestType; + + //! The device request. The values that are assigned to this member are defined in Table 9.3 of section 9.4 of the Universal Serial Bus (USB) specification. + UCHAR Request; + + //! The meaning of this member varies according to the request. For an explanation of this member, see the Universal Serial Bus (USB) specification. + USHORT Value; + + //! The meaning of this member varies according to the request. For an explanation of this member, see the Universal Serial Bus (USB) specification. + USHORT Index; + + //! The number of bytes to transfer. (not including the \c WINUSB_SETUP_PACKET itself) + USHORT Length; + +} WINUSB_SETUP_PACKET; +//! pointer to a \c WINUSB_SETUP_PACKET structure +typedef WINUSB_SETUP_PACKET* PWINUSB_SETUP_PACKET; +C_ASSERT(sizeof(WINUSB_SETUP_PACKET) == 8); + +#include + +#endif // __WUSBIO_H__ __WINUSB_COMPAT_IO_H__ + +#include + +/*! \addtogroup isok +* @{ +*/ + +//! Structure describing an isochronous transfer packet. +typedef struct _KISO_PACKET +{ + //! Specifies the offset, in bytes, of the buffer for this packet from the beginning of the entire isochronous transfer data buffer. + /*! + * \c Offset represents an absolute data offset from the start of the \c Buffer parameter \ref UsbK_IsoReadPipe or \ref UsbK_IsoWritePipe. + * + * \note This field is assigned by the user application only and used by the driver upon transfer submission and completion. + */ + UINT Offset; + + //! Set by the host controller to indicate the actual number of bytes received by the device for isochronous IN transfers. Length not used for isochronous OUT transfers. + /*! + * \note This field is is not user assignable and is updated by the driver upon transfer completion. + */ + USHORT Length; + + //! Contains the 16 least significant USBD status bits, on return from the host controller driver, of this transfer packet. + /*! + * See MSDN for USBD status codes: USBD status code reference + * + * \note This field is is not user assignable and is updated by the driver upon transfer completion. + */ + USHORT Status; + +} KISO_PACKET; +//! pointer to a \c KISO_PACKET structure +typedef KISO_PACKET* PKISO_PACKET; + +#pragma warning(disable:4200) + +//! Additional ISO transfer flags. +typedef enum _KISO_FLAG +{ + KISO_FLAG_NONE = 0, + + //! Do not start the transfer immediately, instead use \ref KISO_CONTEXT::StartFrame. + /*! + * By default, isochronous transfers start on the next frame and \ref KISO_CONTEXT::StartFrame is + * ignored. If this flag is specified, the transfer is postponed until the current usb frame number + * equals that specified by \ref KISO_CONTEXT::StartFrame. + * + * Under certain circumstances, the driver can specify 0 for \ref KISO_CONTEXT::StartFrame, and the bus + * driver will begin the transaction in the next available frame. + * + * Specifing \b 0 for \ref KISO_CONTEXT::StartFrame (start transfer ASAP) is restricted to the first + * transaction on a newly opened or reset pipe. Furthermore, the USB stack contains a bug in Microsoft + * Windows Server 2003 and Windows XP that limits the use of this to an isochronous context with 255 or fewer + * packets. + * + * For more information about resetting pipes, see \ref UsbK_ResetPipe. + */ + KISO_FLAG_SET_START_FRAME = 0x00000001, +} KISO_FLAG; + +//! Structure describing a user defined isochronous transfer. +/*! +* +* \fixedstruct{16} +* +* The \ref KISO_CONTEXT::StartFrame member of the \ref KISO_CONTEXT specifies the starting USB frame number +* for the transaction. The driver can use \ref UsbK_GetCurrentFrameNumber to request the current frame +* number. +* +* In full-speed transmissions, the frame number for any particular packet will be the sum of the start frame +* number and the packet index. For instance, the fourth packet in the \ref KISO_CONTEXT has an index of 3, so +* its frame number will be StartFrame + 3. In a write transfer, the port driver loads this frame with the +* buffer data at the data buffer offset specified by IsoPacket[3].Offset. +* +* When the driver processes the \ref KISO_CONTEXT, it discards all packets in the \ref KISO_CONTEXT whose +* frame numbers are lower than the current frame number. The port driver sets the Status member of the packet +* descriptor for each discarded packet to USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW +* or USBD_STATUS_ISO_NOT_ACCESSED_LATE. Even if it discards some packets, the port driver attempts to +* transmit those packets in the \ref KISO_CONTEXT whose frame numbers are higher than the current frame +* number. +* +* The check for a valid StartFrame member is slightly more complicated in high-speed transmissions because +* the port driver loads each packet into a high-speed microframe; however, the value in StartFrame refers to +* the 1 millisecond (full-speed) frame number, not the microframe. For example, if the StartFrame value +* recorded in the \ref KISO_CONTEXT is one less than the current frame, the port driver will discard as many +* as eight packets. The exact number of packets that the port driver discards depends on the period +* associated with the isochronous pipe. +* +* High-speed isochronous pipes can have periods of 1, 2, 4, or 8. The period number specifies the frequency +* with which the port driver inserts packets into the data stream. If the period is 2, for example, the port +* driver will insert a packet into the data stream every two microframes. This means that it will only use +* four of the eight microframes available within each 1-millisecond frame for isochronous data transmission. +* +* In general, the higher the period, the fewer packets the port driver will discard when a \ref KISO_CONTEXT +* arrives late. Assume the period on an isochronous pipe is 2. With a period of 2, each 1-millisecond speed +* frame will carry four packets of isochronous data for that pipe. So, for example, if CurrentFrame - +* StartFrame = 3, the port driver will discard 3 * 4 = 12 packets. On the other hand, if the period is 4, +* each 1-millisecond frame carries only two packets of isochronous data for the pipe. Therefore, if the +* \ref KISO_CONTEXT arrives three 1-millisecond frames late, as in the previous example, the port driver will +* discard 3 * 2 = 6 packets, instead of 12 packets. +* +* For all types of isochronous pipe, the distance between the current frame and the StartFrame value +* specified in the \ref KISO_CONTEXT must be less than USBD_ISO_START_FRAME_RANGE. If StartFrame is not +* within the proper range, the driver sets the Status member of the \ref KISO_PACKET +* \c USBD_STATUS_BAD_START_FRAME and discards the entire \ref KISO_CONTEXT. The following code example shows +* the precise check that the port driver does on the \ref KISO_CONTEXT start frame: +* \code +* if (abs((CurrentFrame - StartFrame)) > USBD_ISO_START_FRAME_RANGE) +* { +* // discard the KISO_CONTEXT +* } +* \endcode +* +*/ +typedef struct _KISO_CONTEXT +{ + //! Additional ISO transfer flags. See \ref KISO_FLAG. + KISO_FLAG Flags; + + //! Specifies the frame number that the transfer should begin on (0 for ASAP). + /*! + * This variable must be within a system-defined range of the current frame. The range is specified by the + * constant \ref USBD_ISO_START_FRAME_RANGE. + * + * If /ref KISO_FLAG_SET_START_FRAME was specified, this member contains the frame number that the transfer should begin on. + * When the request is returned by the host controller driver, this member is updated to reflect the frame number this transfer + * did begin on. + * + * \note This field may be assigned by the user application and is updated by the driver upon transfer + * completion. + */ + UINT StartFrame; + + //! Contains the number of packets that completed with an error condition on return from the host controller driver. + /*! + * \note This field is is not user assignable and is updated by the driver upon transfer completion. + */ + SHORT ErrorCount; + + //! Specifies the number of packets that are described by the variable-length array member \c IsoPacket. + /* + * \note This field is assigned by the user application only and used by the driver upon transfer submission + * and completion. + */ + SHORT NumberOfPackets; + + //! Contains the URB Hdr.Status value on return from the host controller driver. + /*! + * \note This field is is not user assignable and is updated by the driver upon transfer completion. + * + * The USB bus driver always returns a value of USBD_STATUS_SUCCESS in + * Hdr.Status, unless every packet in the transfer generated an error or + * the request was not well-formed and could not be executed at all. The + * following table includes possible error codes returned in Hdr.Status: + * - USBD_STATUS_ISOCH_REQUEST_FAILED + * Indicates that every packet of an isochronous request was completed with + * errors. + * - USBD_STATUS_BAD_START_FRAME + * Indicates that the requested start frame is not within + * USBD_ISO_START_FRAME_RANGE of the current USB frame. + * - USBD_ISO_NOT_ACCESSED_LATE + * Indicates that every packet was submitted too late for the packet to be + * sent, based on the requested start frame. + * - USBD_STATUS_INVALID_PARAMETER + * Indicates that one of the URB parameters was incorrect. + */ + UINT UrbHdrStatus; + + //! Contains a variable-length array of \c KISO_PACKET structures that describe the isochronous transfer packets to be transferred on the USB bus. + /* + * \note This field is assigned by the user application, used by the driver upon transfer submission, and + * updated by the driver upon transfer completion. + */ + KISO_PACKET IsoPackets[0]; + +} KISO_CONTEXT; +C_ASSERT(sizeof(KISO_CONTEXT) == 16); + +//! pointer to a \c KISO_CONTEXT structure +typedef KISO_CONTEXT* PKISO_CONTEXT; + +/*! @} */ + +#pragma warning(default:4200) + +#include + +#endif // __LUSBK_SHARED_H_ + diff --git a/libs/libusbK/license/AUTHORS-libusb0.txt b/libs/libusbK/license/AUTHORS-libusb0.txt new file mode 100644 index 0000000..3ad12f7 --- /dev/null +++ b/libs/libusbK/license/AUTHORS-libusb0.txt @@ -0,0 +1,20 @@ +This software is distributed under the following licenses: +Driver: GNU General Public License (GPL) +Library: GNU Lesser General Public (LGPL) +Test Files: GNU Lesser General Public (LGPL) +Filter Installer: GNU Lesser General Public (LGPL) + +Library, Test Programs: + +Stephan Meyer, +Johannes Erdfelt, +Thomas Sailer, + +Drivers, Installer: + +Stephan Meyer, +Travis Robinson, + +Testing, Technical support: + +Xiaofan Chen, diff --git a/libs/libusbK/license/AUTHORS-libusbK.txt b/libs/libusbK/license/AUTHORS-libusbK.txt new file mode 100644 index 0000000..99f27a4 --- /dev/null +++ b/libs/libusbK/license/AUTHORS-libusbK.txt @@ -0,0 +1,40 @@ +CONTRIBUTORS +----------------------------------------------------------------------- +Development : Travis Lee Robinson (libusbdotnet@gmail.com) +Testing : Xiaofan Chen (xiaofanc@gmail.com) + +LICENSE +----------------------------------------------------------------------- +Copyright (c) 2011-2012 Travis Lee Robinson. All rights reserved. + +APPLICABLE FOR ALL LIBUSBK BINARIES AND SOURCE CODE UNLESS OTHERWISE +SPECIFIED. PLEASE SEE INDIVIDUAL COMPONENTS LICENSING TERMS FOR DETAILS. + +NOTE: Portions of dpscat use source code from libwdi which is licensed +for LGPL use only. (See dpscat.c) + +NOTE: libusbK-inf-wizard.exe is linked to libwdi which is licensed for +LGPL use only. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Travis Lee Robinson nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TRAVIS ROBINSON BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libs/libusbK/license/LICENSE-bsd.txt b/libs/libusbK/license/LICENSE-bsd.txt new file mode 100644 index 0000000..b80c667 --- /dev/null +++ b/libs/libusbK/license/LICENSE-bsd.txt @@ -0,0 +1,33 @@ +Copyright (c) 2011-2012 Travis Lee Robinson. All rights reserved. + +APPLICABLE FOR ALL LIBUSBK BINARIES AND SOURCE CODE UNLESS OTHERWISE +SPECIFIED. PLEASE SEE INDIVIDUAL COMPONENTS LICENSING TERMS FOR DETAILS. + +NOTE: Portions of dpscat use source code from libwdi which is licensed +for LGPL use only. (See dpscat.c) + +NOTE: libusbK-inf-wizard.exe is linked to libwdi which is licensed for +LGPL use only. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Travis Lee Robinson nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TRAVIS ROBINSON BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libs/libusbK/license/LICENSE-gpl3.txt b/libs/libusbK/license/LICENSE-gpl3.txt new file mode 100644 index 0000000..eff3f9a --- /dev/null +++ b/libs/libusbK/license/LICENSE-gpl3.txt @@ -0,0 +1,686 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TRAVIS ROBINSON BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/libs/libusbK/license/LICENSE-lgpl3.txt b/libs/libusbK/license/LICENSE-lgpl3.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/libs/libusbK/license/LICENSE-lgpl3.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/libs/zip_libs/include/JlCompress.h b/libs/zip_libs/include/JlCompress.h new file mode 100644 index 0000000..49c5086 --- /dev/null +++ b/libs/zip_libs/include/JlCompress.h @@ -0,0 +1,197 @@ +#ifndef JLCOMPRESSFOLDER_H_ +#define JLCOMPRESSFOLDER_H_ + +/* +Copyright (C) 2010 Roberto Pompermaier +Copyright (C) 2005-2016 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include "quazip.h" +#include "quazipfile.h" +#include "quazipfileinfo.h" +#include +#include +#include +#include + +/// Utility class for typical operations. +/** + This class contains a number of useful static functions to perform + simple operations, such as mass ZIP packing or extraction. + */ +class QUAZIP_EXPORT JlCompress { +private: + static QStringList extractDir(QuaZip &zip, const QString &dir); + static QStringList getFileList(QuaZip *zip); + static QString extractFile(QuaZip &zip, QString fileName, QString fileDest); + static QStringList extractFiles(QuaZip &zip, const QStringList &files, const QString &dir); + /// Compress a single file. + /** + \param zip Opened zip to compress the file to. + \param fileName The full path to the source file. + \param fileDest The full name of the file inside the archive. + \return true if success, false otherwise. + */ + static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); + /// Compress a subdirectory. + /** + \param parentZip Opened zip containing the parent directory. + \param dir The full path to the directory to pack. + \param parentDir The full path to the directory corresponding to + the root of the ZIP. + \param recursive Whether to pack sub-directories as well or only + files. + \return true if success, false otherwise. + */ + static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive, + QDir::Filters filters); + /// Extract a single file. + /** + \param zip The opened zip archive to extract from. + \param fileName The full name of the file to extract. + \param fileDest The full path to the destination file. + \return true if success, false otherwise. + */ + static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); + /// Remove some files. + /** + \param listFile The list of files to remove. + \return true if success, false otherwise. + */ + static bool removeFile(QStringList listFile); + +public: + /// Compress a single file. + /** + \param fileCompressed The name of the archive. + \param file The file to compress. + \return true if success, false otherwise. + */ + static bool compressFile(QString fileCompressed, QString file); + /// Compress a list of files. + /** + \param fileCompressed The name of the archive. + \param files The file list to compress. + \return true if success, false otherwise. + */ + static bool compressFiles(QString fileCompressed, QStringList files); + /// Compress a whole directory. + /** + Does not compress hidden files. See compressDir(QString, QString, bool, QDir::Filters). + + \param fileCompressed The name of the archive. + \param dir The directory to compress. + \param recursive Whether to pack the subdirectories as well, or + just regular files. + \return true if success, false otherwise. + */ + static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); + /** + * @brief Compress a whole directory. + * + * Unless filters are specified explicitly, packs + * only regular non-hidden files (and subdirs, if @c recursive is true). + * If filters are specified, they are OR-combined with + * %QDir::AllDirs|%QDir::NoDotAndDotDot when searching for dirs + * and with QDir::Files when searching for files. + * + * @param fileCompressed path to the resulting archive + * @param dir path to the directory being compressed + * @param recursive if true, then the subdirectories are packed as well + * @param filters what to pack, filters are applied both when searching + * for subdirs (if packing recursively) and when looking for files to pack + * @return true on success, false otherwise + */ + static bool compressDir(QString fileCompressed, QString dir, + bool recursive, QDir::Filters filters); + +public: + /// Extract a single file. + /** + \param fileCompressed The name of the archive. + \param fileName The file to extract. + \param fileDest The destination file, assumed to be identical to + \a file if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); + /// Extract a list of files. + /** + \param fileCompressed The name of the archive. + \param files The file list to extract. + \param dir The directory to put the files to, the current + directory if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); + /// Extract a whole archive. + /** + \param fileCompressed The name of the archive. + \param dir The directory to extract to, the current directory if + left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractDir(QString fileCompressed, QString dir = QString()); + /// Get the file list. + /** + \return The list of the files in the archive, or, more precisely, the + list of the entries, including both files and directories if they + are present separately. + */ + static QStringList getFileList(QString fileCompressed); + /// Extract a single file. + /** + \param ioDevice pointer to device with compressed data. + \param fileName The file to extract. + \param fileDest The destination file, assumed to be identical to + \a file if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QString extractFile(QIODevice *ioDevice, QString fileName, QString fileDest = QString()); + /// Extract a list of files. + /** + \param ioDevice pointer to device with compressed data. + \param files The file list to extract. + \param dir The directory to put the files to, the current + directory if left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractFiles(QIODevice *ioDevice, QStringList files, QString dir = QString()); + /// Extract a whole archive. + /** + \param ioDevice pointer to device with compressed data. + \param dir The directory to extract to, the current directory if + left empty. + \return The list of the full paths of the files extracted, empty on failure. + */ + static QStringList extractDir(QIODevice *ioDevice, QString dir = QString()); + /// Get the file list. + /** + \return The list of the files in the archive, or, more precisely, the + list of the entries, including both files and directories if they + are present separately. + */ + static QStringList getFileList(QIODevice *ioDevice); +}; + +#endif /* JLCOMPRESSFOLDER_H_ */ diff --git a/libs/zip_libs/include/crc32.h b/libs/zip_libs/include/crc32.h new file mode 100644 index 0000000..9e0c778 --- /dev/null +++ b/libs/zip_libs/include/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/libs/zip_libs/include/crypt.h b/libs/zip_libs/include/crypt.h new file mode 100644 index 0000000..ddee28e --- /dev/null +++ b/libs/zip_libs/include/crypt.h @@ -0,0 +1,135 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#include "quazip_global.h" + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t FAR * pcrc_32_tab UNUSED) +{ + //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const z_crc_t FAR * pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/libs/zip_libs/include/deflate.h b/libs/zip_libs/include/deflate.h new file mode 100644 index 0000000..23ecdd3 --- /dev/null +++ b/libs/zip_libs/include/deflate.h @@ -0,0 +1,349 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef ZLIB_DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/libs/zip_libs/include/gzguts.h b/libs/zip_libs/include/gzguts.h new file mode 100644 index 0000000..990a4d2 --- /dev/null +++ b/libs/zip_libs/include/gzguts.h @@ -0,0 +1,218 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/libs/zip_libs/include/inffast.h b/libs/zip_libs/include/inffast.h new file mode 100644 index 0000000..e5c1aa4 --- /dev/null +++ b/libs/zip_libs/include/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/libs/zip_libs/include/inffixed.h b/libs/zip_libs/include/inffixed.h new file mode 100644 index 0000000..d628327 --- /dev/null +++ b/libs/zip_libs/include/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/libs/zip_libs/include/inflate.h b/libs/zip_libs/include/inflate.h new file mode 100644 index 0000000..a46cce6 --- /dev/null +++ b/libs/zip_libs/include/inflate.h @@ -0,0 +1,125 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/libs/zip_libs/include/inftrees.h b/libs/zip_libs/include/inftrees.h new file mode 100644 index 0000000..baa53a0 --- /dev/null +++ b/libs/zip_libs/include/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/libs/zip_libs/include/ioapi.h b/libs/zip_libs/include/ioapi.h new file mode 100644 index 0000000..bbb94c8 --- /dev/null +++ b/libs/zip_libs/include/ioapi.h @@ -0,0 +1,207 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + Modified by Sergey A. Tachenov to allow QIODevice API usage. + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef OF +#define OF _Z_OF +#endif + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, voidpf file, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; + close_file_func zfakeclose_file; // for no-auto-close flag +} zlib_filefunc64_def; + +void fill_qiodevice64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZFAKECLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zfakeclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode)); +int call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/zip_libs/include/quaadler32.h b/libs/zip_libs/include/quaadler32.h new file mode 100644 index 0000000..e8847f4 --- /dev/null +++ b/libs/zip_libs/include/quaadler32.h @@ -0,0 +1,54 @@ +#ifndef QUAADLER32_H +#define QUAADLER32_H + +/* +Copyright (C) 2010 Adam Walczak +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include + +#include "quachecksum32.h" + +/// Adler32 checksum +/** \class QuaAdler32 quaadler32.h + * This class wrappers the adler32 function with the QuaChecksum32 interface. + * See QuaChecksum32 for more info. + */ +class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 +{ + +public: + QuaAdler32(); + + quint32 calculate(const QByteArray &data); + + void reset(); + void update(const QByteArray &buf); + quint32 value(); + +private: + quint32 checksum; +}; + +#endif //QUAADLER32_H diff --git a/libs/zip_libs/include/quachecksum32.h b/libs/zip_libs/include/quachecksum32.h new file mode 100644 index 0000000..40ff451 --- /dev/null +++ b/libs/zip_libs/include/quachecksum32.h @@ -0,0 +1,78 @@ +#ifndef QUACHECKSUM32_H +#define QUACHECKSUM32_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include +#include "quazip_global.h" + +/// Checksum interface. +/** \class QuaChecksum32 quachecksum32.h + * This is an interface for 32 bit checksums. + * Classes implementing this interface can calcunate a certin + * checksum in a single step: + * \code + * QChecksum32 *crc32 = new QuaCrc32(); + * rasoult = crc32->calculate(data); + * \endcode + * or by streaming the data: + * \code + * QChecksum32 *crc32 = new QuaCrc32(); + * while(!fileA.atEnd()) + * crc32->update(fileA.read(bufSize)); + * resoultA = crc32->value(); + * crc32->reset(); + * while(!fileB.atEnd()) + * crc32->update(fileB.read(bufSize)); + * resoultB = crc32->value(); + * \endcode + */ +class QUAZIP_EXPORT QuaChecksum32 +{ + +public: + ///Calculates the checksum for data. + /** \a data source data + * \return data checksum + * + * This function has no efect on the value returned by value(). + */ + virtual quint32 calculate(const QByteArray &data) = 0; + + ///Resets the calculation on a checksun for a stream. + virtual void reset() = 0; + + ///Updates the calculated checksum for the stream + /** \a buf next portion of data from the stream + */ + virtual void update(const QByteArray &buf) = 0; + + ///Value of the checksum calculated for the stream passed throw update(). + /** \return checksum + */ + virtual quint32 value() = 0; +}; + +#endif //QUACHECKSUM32_H diff --git a/libs/zip_libs/include/quacrc32.h b/libs/zip_libs/include/quacrc32.h new file mode 100644 index 0000000..af7703b --- /dev/null +++ b/libs/zip_libs/include/quacrc32.h @@ -0,0 +1,50 @@ +#ifndef QUACRC32_H +#define QUACRC32_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include "quachecksum32.h" + +///CRC32 checksum +/** \class QuaCrc32 quacrc32.h +* This class wrappers the crc32 function with the QuaChecksum32 interface. +* See QuaChecksum32 for more info. +*/ +class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { + +public: + QuaCrc32(); + + quint32 calculate(const QByteArray &data); + + void reset(); + void update(const QByteArray &buf); + quint32 value(); + +private: + quint32 checksum; +}; + +#endif //QUACRC32_H diff --git a/libs/zip_libs/include/quagzipfile.h b/libs/zip_libs/include/quagzipfile.h new file mode 100644 index 0000000..e2f9d97 --- /dev/null +++ b/libs/zip_libs/include/quagzipfile.h @@ -0,0 +1,108 @@ +#ifndef QUAZIP_QUAGZIPFILE_H +#define QUAZIP_QUAGZIPFILE_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include +#include "quazip_global.h" + +#include + +class QuaGzipFilePrivate; + +/// GZIP file +/** + This class is a wrapper around GZIP file access functions in zlib. Unlike QuaZip classes, it doesn't allow reading from a GZIP file opened as QIODevice, for example, if your GZIP file is in QBuffer. It only provides QIODevice access to a GZIP file contents, but the GZIP file itself must be identified by its name on disk or by descriptor id. + */ +class QUAZIP_EXPORT QuaGzipFile: public QIODevice { + Q_OBJECT +public: + /// Empty constructor. + /** + Must call setFileName() before trying to open. + */ + QuaGzipFile(); + /// Empty constructor with a parent. + /** + Must call setFileName() before trying to open. + \param parent The parent object, as per QObject logic. + */ + QuaGzipFile(QObject *parent); + /// Constructor. + /** + \param fileName The name of the GZIP file. + \param parent The parent object, as per QObject logic. + */ + QuaGzipFile(const QString &fileName, QObject *parent = NULL); + /// Destructor. + virtual ~QuaGzipFile(); + /// Sets the name of the GZIP file to be opened. + void setFileName(const QString& fileName); + /// Returns the name of the GZIP file. + QString getFileName() const; + /// Returns true. + /** + Strictly speaking, zlib supports seeking for GZIP files, but it is + poorly implemented, because there is no way to implement it + properly. For reading, seeking backwards is very slow, and for + writing, it is downright impossible. Therefore, QuaGzipFile does not + support seeking at all. + */ + virtual bool isSequential() const; + /// Opens the file. + /** + \param mode Can be either QIODevice::Write or QIODevice::Read. + ReadWrite and Append aren't supported. + */ + virtual bool open(QIODevice::OpenMode mode); + /// Opens the file. + /** + \overload + \param fd The file descriptor to read/write the GZIP file from/to. + \param mode Can be either QIODevice::Write or QIODevice::Read. + ReadWrite and Append aren't supported. + */ + virtual bool open(int fd, QIODevice::OpenMode mode); + /// Flushes data to file. + /** + The data is written using Z_SYNC_FLUSH mode. Doesn't make any sense + when reading. + */ + virtual bool flush(); + /// Closes the file. + virtual void close(); +protected: + /// Implementation of QIODevice::readData(). + virtual qint64 readData(char *data, qint64 maxSize); + /// Implementation of QIODevice::writeData(). + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + // not implemented by design to disable copy + QuaGzipFile(const QuaGzipFile &that); + QuaGzipFile& operator=(const QuaGzipFile &that); + QuaGzipFilePrivate *d; +}; + +#endif // QUAZIP_QUAGZIPFILE_H diff --git a/libs/zip_libs/include/quaziodevice.h b/libs/zip_libs/include/quaziodevice.h new file mode 100644 index 0000000..63499c3 --- /dev/null +++ b/libs/zip_libs/include/quaziodevice.h @@ -0,0 +1,102 @@ +#ifndef QUAZIP_QUAZIODEVICE_H +#define QUAZIP_QUAZIODEVICE_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include +#include "quazip_global.h" + +#include + +class QuaZIODevicePrivate; + +/// A class to compress/decompress QIODevice. +/** + This class can be used to compress any data written to QIODevice or + decompress it back. Compressing data sent over a QTcpSocket is a good + example. + */ +class QUAZIP_EXPORT QuaZIODevice: public QIODevice { + Q_OBJECT +public: + /// Constructor. + /** + \param io The QIODevice to read/write. + \param parent The parent object, as per QObject logic. + */ + QuaZIODevice(QIODevice *io, QObject *parent = NULL); + /// Destructor. + ~QuaZIODevice(); + /// Flushes data waiting to be written. + /** + Unfortunately, as QIODevice doesn't support flush() by itself, the + only thing this method does is write the compressed data into the + device using Z_SYNC_FLUSH mode. If you need the compressed data to + actually be flushed from the buffer of the underlying QIODevice, you + need to call its flush() method as well, providing it supports it + (like QTcpSocket does). Example: + \code + QuaZIODevice dev(&sock); + dev.open(QIODevice::Write); + dev.write(yourDataGoesHere); + dev.flush(); + sock->flush(); // this actually sends data to network + \endcode + + This may change in the future versions of QuaZIP by implementing an + ugly hack: trying to cast the QIODevice using qobject_cast to known + flush()-supporting subclasses, and calling flush if the resulting + pointer is not zero. + */ + virtual bool flush(); + /// Opens the device. + /** + \param mode Neither QIODevice::ReadWrite nor QIODevice::Append are + not supported. + */ + virtual bool open(QIODevice::OpenMode mode); + /// Closes this device, but not the underlying one. + /** + The underlying QIODevice is not closed in case you want to write + something else to it. + */ + virtual void close(); + /// Returns the underlying device. + QIODevice *getIoDevice() const; + /// Returns true. + virtual bool isSequential() const; + /// Returns true iff the end of the compressed stream is reached. + virtual bool atEnd() const; + /// Returns the number of the bytes buffered. + virtual qint64 bytesAvailable() const; +protected: + /// Implementation of QIODevice::readData(). + virtual qint64 readData(char *data, qint64 maxSize); + /// Implementation of QIODevice::writeData(). + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + QuaZIODevicePrivate *d; +}; +#endif // QUAZIP_QUAZIODEVICE_H diff --git a/libs/zip_libs/include/quazip.h b/libs/zip_libs/include/quazip.h new file mode 100644 index 0000000..ae2c8f4 --- /dev/null +++ b/libs/zip_libs/include/quazip.h @@ -0,0 +1,571 @@ +#ifndef QUA_ZIP_H +#define QUA_ZIP_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include +#include + +#include "zip.h" +#include "unzip.h" + +#include "quazip_global.h" +#include "quazipfileinfo.h" + +// just in case it will be defined in the later versions of the ZIP/UNZIP +#ifndef UNZ_OPENERROR +// define additional error code +#define UNZ_OPENERROR -1000 +#endif + +class QuaZipPrivate; + +/// ZIP archive. +/** \class QuaZip quazip.h + * This class implements basic interface to the ZIP archive. It can be + * used to read table contents of the ZIP archive and retreiving + * information about the files inside it. + * + * You can also use this class to open files inside archive by passing + * pointer to the instance of this class to the constructor of the + * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) + * for the possible pitfalls. + * + * This class is indended to provide interface to the ZIP subpackage of + * the ZIP/UNZIP package as well as to the UNZIP subpackage. But + * currently it supports only UNZIP. + * + * The use of this class is simple - just create instance using + * constructor, then set ZIP archive file name using setFile() function + * (if you did not passed the name to the constructor), then open() and + * then use different functions to work with it! Well, if you are + * paranoid, you may also wish to call close before destructing the + * instance, to check for errors on close. + * + * You may also use getUnzFile() and getZipFile() functions to get the + * ZIP archive handle and use it with ZIP/UNZIP package API directly. + * + * This class supports localized file names inside ZIP archive, but you + * have to set up proper codec with setCodec() function. By default, + * locale codec will be used, which is probably ok for UNIX systems, but + * will almost certainly fail with ZIP archives created in Windows. This + * is because Windows ZIP programs have strange habit of using DOS + * encoding for file names in ZIP archives. For example, ZIP archive + * with cyrillic names created in Windows will have file names in \c + * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one + * function is not much trouble, but for true platform independency it + * would be nice to have some mechanism for file name encoding auto + * detection using locale information. Does anyone know a good way to do + * it? + **/ +class QUAZIP_EXPORT QuaZip { + friend class QuaZipPrivate; + public: + /// Useful constants. + enum Constants { + MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from + \c UNZ_MAXFILENAMEINZIP constant in + unzip.c. */ + }; + /// Open mode of the ZIP file. + enum Mode { + mdNotOpen, ///< ZIP file is not open. This is the initial mode. + mdUnzip, ///< ZIP file is open for reading files inside it. + mdCreate, ///< ZIP file was created with open() call. + mdAppend, /**< ZIP file was opened in append mode. This refers to + * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package + * and means that zip is appended to some existing file + * what is useful when that file contains + * self-extractor code. This is obviously \em not what + * you whant to use to add files to the existing ZIP + * archive. + **/ + mdAdd ///< ZIP file was opened for adding files in the archive. + }; + /// Case sensitivity for the file names. + /** This is what you specify when accessing files in the archive. + * Works perfectly fine with any characters thanks to Qt's great + * unicode support. This is different from ZIP/UNZIP API, where + * only US-ASCII characters was supported. + **/ + enum CaseSensitivity { + csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. + csSensitive=1, ///< Case sensitive. + csInsensitive=2 ///< Case insensitive. + }; + /// Returns the actual case sensitivity for the specified QuaZIP one. + /** + \param cs The value to convert. + \returns If CaseSensitivity::csDefault, then returns the default + file name case sensitivity for the platform. Otherwise, just + returns the appropriate value from the Qt::CaseSensitivity enum. + */ + static Qt::CaseSensitivity convertCaseSensitivity( + CaseSensitivity cs); + private: + QuaZipPrivate *p; + // not (and will not be) implemented + QuaZip(const QuaZip& that); + // not (and will not be) implemented + QuaZip& operator=(const QuaZip& that); + public: + /// Constructs QuaZip object. + /** Call setName() before opening constructed object. */ + QuaZip(); + /// Constructs QuaZip object associated with ZIP file \a zipName. + QuaZip(const QString& zipName); + /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. + /** The IO device must be seekable, otherwise an error will occur when opening. */ + QuaZip(QIODevice *ioDevice); + /// Destroys QuaZip object. + /** Calls close() if necessary. */ + ~QuaZip(); + /// Opens ZIP file. + /** + * Argument \a mode specifies open mode of the ZIP archive. See Mode + * for details. Note that there is zipOpen2() function in the + * ZIP/UNZIP API which accepts \a globalcomment argument, but it + * does not use it anywhere, so this open() function does not have this + * argument. See setComment() if you need to set global comment. + * + * If the ZIP file is accessed via explicitly set QIODevice, then + * this device is opened in the necessary mode. If the device was + * already opened by some other means, then QuaZIP checks if the + * open mode is compatible to the mode needed for the requested operation. + * If necessary, seeking is performed to position the device properly. + * + * \return \c true if successful, \c false otherwise. + * + * \note ZIP/UNZIP API open calls do not return error code - they + * just return \c NULL indicating an error. But to make things + * easier, quazip.h header defines additional error code \c + * UNZ_ERROROPEN and getZipError() will return it if the open call + * of the ZIP/UNZIP API returns \c NULL. + * + * Argument \a ioApi specifies IO function set for ZIP/UNZIP + * package to use. See unzip.h, zip.h and ioapi.h for details. Note + * that IO API for QuaZip is different from the original package. + * The file path argument was changed to be of type \c voidpf, and + * QuaZip passes a QIODevice pointer there. This QIODevice is either + * set explicitly via setIoDevice() or the QuaZip(QIODevice*) + * constructor, or it is created internally when opening the archive + * by its file name. The default API (qioapi.cpp) just delegates + * everything to the QIODevice API. Not only this allows to use a + * QIODevice instead of file name, but also has a nice side effect + * of raising the file size limit from 2G to 4G (in non-zip64 archives). + * + * \note If the zip64 support is needed, the ioApi argument \em must be NULL + * because due to the backwards compatibility issues it can be used to + * provide a 32-bit API only. + * + * \note If the \ref QuaZip::setAutoClose() "no-auto-close" feature is used, + * then the \a ioApi argument \em should be NULL because the old API + * doesn't support the 'fake close' operation, causing slight memory leaks + * and other possible troubles (like closing the output device in case + * when an error occurs during opening). + * + * In short: just forget about the \a ioApi argument and you'll be + * fine. + **/ + bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); + /// Closes ZIP file. + /** Call getZipError() to determine if the close was successful. + * + * If the file was opened by name, then the underlying QIODevice is closed + * and deleted. + * + * If the underlying QIODevice was set explicitly using setIoDevice() or + * the appropriate constructor, then it is closed if the auto-close flag + * is set (which it is by default). Call setAutoClose() to clear the + * auto-close flag if this behavior is undesirable. + * + * Since Qt 5.1, the QSaveFile was introduced. It breaks the QIODevice API + * by making close() private and crashing the application if it is called + * from the base class where it is public. It is an excellent example + * of poor design that illustrates why you should never ever break + * an is-a relationship between the base class and a subclass. QuaZIP + * works around this bug by checking if the QIODevice is an instance + * of QSaveFile, using qobject_cast<>, and if it is, calls + * QSaveFile::commit() instead of close(). It is a really ugly hack, + * but at least it makes your programs work instead of crashing. Note that + * if the auto-close flag is cleared, then this is a non-issue, and + * commit() isn't called. + */ + void close(); + /// Sets the codec used to encode/decode file names inside archive. + /** This is necessary to access files in the ZIP archive created + * under Windows with non-latin characters in file names. For + * example, file names with cyrillic letters will be in \c IBM866 + * encoding. + **/ + void setFileNameCodec(QTextCodec *fileNameCodec); + /// Sets the codec used to encode/decode file names inside archive. + /** \overload + * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); + **/ + void setFileNameCodec(const char *fileNameCodecName); + /// Returns the codec used to encode/decode comments inside archive. + QTextCodec* getFileNameCodec() const; + /// Sets the codec used to encode/decode comments inside archive. + /** This codec defaults to locale codec, which is probably ok. + **/ + void setCommentCodec(QTextCodec *commentCodec); + /// Sets the codec used to encode/decode comments inside archive. + /** \overload + * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); + **/ + void setCommentCodec(const char *commentCodecName); + /// Returns the codec used to encode/decode comments inside archive. + QTextCodec* getCommentCodec() const; + /// Returns the name of the ZIP file. + /** Returns null string if no ZIP file name has been set, for + * example when the QuaZip instance is set up to use a QIODevice + * instead. + * \sa setZipName(), setIoDevice(), getIoDevice() + **/ + QString getZipName() const; + /// Sets the name of the ZIP file. + /** Does nothing if the ZIP file is open. + * + * Does not reset error code returned by getZipError(). + * \sa setIoDevice(), getIoDevice(), getZipName() + **/ + void setZipName(const QString& zipName); + /// Returns the device representing this ZIP file. + /** Returns null string if no device has been set explicitly, for + * example when opening a ZIP file by name. + * \sa setIoDevice(), getZipName(), setZipName() + **/ + QIODevice *getIoDevice() const; + /// Sets the device representing the ZIP file. + /** Does nothing if the ZIP file is open. + * + * Does not reset error code returned by getZipError(). + * \sa getIoDevice(), getZipName(), setZipName() + **/ + void setIoDevice(QIODevice *ioDevice); + /// Returns the mode in which ZIP file was opened. + Mode getMode() const; + /// Returns \c true if ZIP file is open, \c false otherwise. + bool isOpen() const; + /// Returns the error code of the last operation. + /** Returns \c UNZ_OK if the last operation was successful. + * + * Error code resets to \c UNZ_OK every time you call any function + * that accesses something inside ZIP archive, even if it is \c + * const (like getEntriesCount()). open() and close() calls reset + * error code too. See documentation for the specific functions for + * details on error detection. + **/ + int getZipError() const; + /// Returns number of the entries in the ZIP central directory. + /** Returns negative error code in the case of error. The same error + * code will be returned by subsequent getZipError() call. + **/ + int getEntriesCount() const; + /// Returns global comment in the ZIP file. + QString getComment() const; + /// Sets the global comment in the ZIP file. + /** The comment will be written to the archive on close operation. + * QuaZip makes a distinction between a null QByteArray() comment + * and an empty "" comment in the QuaZip::mdAdd mode. + * A null comment is the default and it means "don't change + * the comment". An empty comment removes the original comment. + * + * \sa open() + **/ + void setComment(const QString& comment); + /// Sets the current file to the first file in the archive. + /** Returns \c true on success, \c false otherwise. Call + * getZipError() to get the error code. + **/ + bool goToFirstFile(); + /// Sets the current file to the next file in the archive. + /** Returns \c true on success, \c false otherwise. Call + * getZipError() to determine if there was an error. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * \note If the end of file was reached, getZipError() will return + * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make + * things like this easier: + * \code + * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { + * // do something + * } + * if(zip.getZipError()==UNZ_OK) { + * // ok, there was no error + * } + * \endcode + **/ + bool goToNextFile(); + /// Sets current file by its name. + /** Returns \c true if successful, \c false otherwise. Argument \a + * cs specifies case sensitivity of the file name. Call + * getZipError() in the case of a failure to get error code. + * + * This is not a wrapper to unzLocateFile() function. That is + * because I had to implement locale-specific case-insensitive + * comparison. + * + * Here are the differences from the original implementation: + * + * - If the file was not found, error code is \c UNZ_OK, not \c + * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). + * - If this function fails, it unsets the current file rather than + * resetting it back to what it was before the call. + * + * If \a fileName is null string then this function unsets the + * current file and return \c true. Note that you should close the + * file first if it is open! See + * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * \sa setFileNameCodec(), CaseSensitivity + **/ + bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); + /// Returns \c true if the current file has been set. + bool hasCurrentFile() const; + /// Retrieves information about the current file. + /** Fills the structure pointed by \a info. Returns \c true on + * success, \c false otherwise. In the latter case structure pointed + * by \a info remains untouched. If there was an error, + * getZipError() returns error code. + * + * Should be used only in QuaZip::mdUnzip mode. + * + * Does nothing and returns \c false in any of the following cases. + * - ZIP is not open; + * - ZIP does not have current file. + * + * In both cases getZipError() returns \c UNZ_OK since there + * is no ZIP/UNZIP API call. + * + * This overload doesn't support zip64, but will work OK on zip64 archives + * except that if one of the sizes (compressed or uncompressed) is greater + * than 0xFFFFFFFFu, it will be set to exactly 0xFFFFFFFFu. + * + * \sa getCurrentFileInfo(QuaZipFileInfo64* info)const + * \sa QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo&)const + **/ + bool getCurrentFileInfo(QuaZipFileInfo* info)const; + /// Retrieves information about the current file. + /** \overload + * + * This function supports zip64. If the archive doesn't use zip64, it is + * completely equivalent to getCurrentFileInfo(QuaZipFileInfo* info) + * except for the argument type. + * + * \sa + **/ + bool getCurrentFileInfo(QuaZipFileInfo64* info)const; + /// Returns the current file name. + /** Equivalent to calling getCurrentFileInfo() and then getting \c + * name field of the QuaZipFileInfo structure, but faster and more + * convenient. + * + * Should be used only in QuaZip::mdUnzip mode. + **/ + QString getCurrentFileName()const; + /// Returns \c unzFile handle. + /** You can use this handle to directly call UNZIP part of the + * ZIP/UNZIP package functions (see unzip.h). + * + * \warning When using the handle returned by this function, please + * keep in mind that QuaZip class is unable to detect any changes + * you make in the ZIP file state (e. g. changing current file, or + * closing the handle). So please do not do anything with this + * handle that is possible to do with the functions of this class. + * Or at least return the handle in the original state before + * calling some another function of this class (including implicit + * destructor calls and calls from the QuaZipFile objects that refer + * to this QuaZip instance!). So if you have changed the current + * file in the ZIP archive - then change it back or you may + * experience some strange behavior or even crashes. + **/ + unzFile getUnzFile(); + /// Returns \c zipFile handle. + /** You can use this handle to directly call ZIP part of the + * ZIP/UNZIP package functions (see zip.h). Warnings about the + * getUnzFile() function also apply to this function. + **/ + zipFile getZipFile(); + /// Changes the data descriptor writing mode. + /** + According to the ZIP format specification, a file inside archive + may have a data descriptor immediately following the file + data. This is reflected by a special flag in the local file header + and in the central directory. By default, QuaZIP sets this flag + and writes the data descriptor unless both method and level were + set to 0, in which case it operates in 1.0-compatible mode and + never writes data descriptors. + + By setting this flag to false, it is possible to disable data + descriptor writing, thus increasing compatibility with archive + readers that don't understand this feature of the ZIP file format. + + Setting this flag affects all the QuaZipFile instances that are + opened after this flag is set. + + The data descriptor writing mode is enabled by default. + + Note that if the ZIP archive is written into a QIODevice for which + QIODevice::isSequential() returns \c true, then the data descriptor + is mandatory and will be written even if this flag is set to false. + + \param enabled If \c true, enable local descriptor writing, + disable it otherwise. + + \sa QuaZipFile::isDataDescriptorWritingEnabled() + */ + void setDataDescriptorWritingEnabled(bool enabled); + /// Returns the data descriptor default writing mode. + /** + \sa setDataDescriptorWritingEnabled() + */ + bool isDataDescriptorWritingEnabled() const; + /// Returns a list of files inside the archive. + /** + \return A list of file names or an empty list if there + was an error or if the archive is empty (call getZipError() to + figure out which). + \sa getFileInfoList() + */ + QStringList getFileNameList() const; + /// Returns information list about all files inside the archive. + /** + \return A list of QuaZipFileInfo objects or an empty list if there + was an error or if the archive is empty (call getZipError() to + figure out which). + + This function doesn't support zip64, but will still work with zip64 + archives, converting results using QuaZipFileInfo64::toQuaZipFileInfo(). + If all file sizes are below 4 GB, it will work just fine. + + \sa getFileNameList() + \sa getFileInfoList64() + */ + QList getFileInfoList() const; + /// Returns information list about all files inside the archive. + /** + \overload + + This function supports zip64. + + \sa getFileNameList() + \sa getFileInfoList() + */ + QList getFileInfoList64() const; + /// Enables the zip64 mode. + /** + * @param zip64 If \c true, the zip64 mode is enabled, disabled otherwise. + * + * Once this is enabled, all new files (until the mode is disabled again) + * will be created in the zip64 mode, thus enabling the ability to write + * files larger than 4 GB. By default, the zip64 mode is off due to + * compatibility reasons. + * + * Note that this does not affect the ability to read zip64 archives in any + * way. + * + * \sa isZip64Enabled() + */ + void setZip64Enabled(bool zip64); + /// Returns whether the zip64 mode is enabled. + /** + * @return \c true if and only if the zip64 mode is enabled. + * + * \sa setZip64Enabled() + */ + bool isZip64Enabled() const; + /// Returns the auto-close flag. + /** + @sa setAutoClose() + */ + bool isAutoClose() const; + /// Sets or unsets the auto-close flag. + /** + By default, QuaZIP opens the underlying QIODevice when open() is called, + and closes it when close() is called. In some cases, when the device + is set explicitly using setIoDevice(), it may be desirable to + leave the device open. If the auto-close flag is unset using this method, + then the device isn't closed automatically if it was set explicitly. + + If it is needed to clear this flag, it is recommended to do so before + opening the archive because otherwise QuaZIP may close the device + during the open() call if an error is encountered after the device + is opened. + + If the device was not set explicitly, but rather the setZipName() or + the appropriate constructor was used to set the ZIP file name instead, + then the auto-close flag has no effect, and the internal device + is closed nevertheless because there is no other way to close it. + + @sa isAutoClose() + @sa setIoDevice() + */ + void setAutoClose(bool autoClose) const; + /// Sets the default file name codec to use. + /** + * The default codec is used by the constructors, so calling this function + * won't affect the QuaZip instances already created at that moment. + * + * The codec specified here can be overriden by calling setFileNameCodec(). + * If neither function is called, QTextCodec::codecForLocale() will be used + * to decode or encode file names. Use this function with caution if + * the application uses other libraries that depend on QuaZIP. Those + * libraries can either call this function by themselves, thus overriding + * your setting or can rely on the default encoding, thus failing + * mysteriously if you change it. For these reasons, it isn't recommended + * to use this function if you are developing a library, not an application. + * Instead, ask your library users to call it in case they need specific + * encoding. + * + * In most cases, using setFileNameCodec() instead is the right choice. + * However, if you depend on third-party code that uses QuaZIP, then the + * reasons stated above can actually become a reason to use this function + * in case the third-party code in question fails because it doesn't + * understand the encoding you need and doesn't provide a way to specify it. + * This applies to the JlCompress class as well, as it was contributed and + * doesn't support explicit encoding parameters. + * + * In short: use setFileNameCodec() when you can, resort to + * setDefaultFileNameCodec() when you don't have access to the QuaZip + * instance. + * + * @param codec The codec to use by default. If NULL, resets to default. + */ + static void setDefaultFileNameCodec(QTextCodec *codec); + /** + * @overload + * Equivalent to calling + * setDefltFileNameCodec(QTextCodec::codecForName(codecName)). + */ + static void setDefaultFileNameCodec(const char *codecName); +}; + +#endif diff --git a/libs/zip_libs/include/quazip_global.h b/libs/zip_libs/include/quazip_global.h new file mode 100644 index 0000000..7e3798a --- /dev/null +++ b/libs/zip_libs/include/quazip_global.h @@ -0,0 +1,59 @@ +#ifndef QUAZIP_GLOBAL_H +#define QUAZIP_GLOBAL_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include + +/** + This is automatically defined when building a static library, but when + including QuaZip sources directly into a project, QUAZIP_STATIC should + be defined explicitly to avoid possible troubles with unnecessary + importing/exporting. + */ +#ifdef QUAZIP_STATIC +#define QUAZIP_EXPORT +#else +/** + * When building a DLL with MSVC, QUAZIP_BUILD must be defined. + * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. + */ +#if defined(QUAZIP_BUILD) + #define QUAZIP_EXPORT Q_DECL_EXPORT +#else + #define QUAZIP_EXPORT Q_DECL_IMPORT +#endif +#endif // QUAZIP_STATIC + +#ifdef __GNUC__ +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif + +#define QUAZIP_EXTRA_NTFS_MAGIC 0x000Au +#define QUAZIP_EXTRA_NTFS_TIME_MAGIC 0x0001u + +#endif // QUAZIP_GLOBAL_H diff --git a/libs/zip_libs/include/quazipdir.h b/libs/zip_libs/include/quazipdir.h new file mode 100644 index 0000000..4626b17 --- /dev/null +++ b/libs/zip_libs/include/quazipdir.h @@ -0,0 +1,223 @@ +#ifndef QUAZIP_QUAZIPDIR_H +#define QUAZIP_QUAZIPDIR_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +class QuaZipDirPrivate; + +#include "quazip.h" +#include "quazipfileinfo.h" +#include +#include +#include + +/// Provides ZIP archive navigation. +/** +* This class is modelled after QDir, and is designed to provide similar +* features for ZIP archives. +* +* The only significant difference from QDir is that the root path is not +* '/', but an empty string since that's how the file paths are stored in +* the archive. However, QuaZipDir understands the paths starting with +* '/'. It is important in a few places: +* +* - In the cd() function. +* - In the constructor. +* - In the exists() function. +* - In the relativePath() function. +* +* Note that since ZIP uses '/' on all platforms, the '\' separator is +* not supported. +*/ +class QUAZIP_EXPORT QuaZipDir { +private: + QSharedDataPointer d; +public: + /// The copy constructor. + QuaZipDir(const QuaZipDir &that); + /// Constructs a QuaZipDir instance pointing to the specified directory. + /** + If \a dir is not specified, points to the root of the archive. + The same happens if the \a dir is "/". + */ + QuaZipDir(QuaZip *zip, const QString &dir = QString()); + /// Destructor. + ~QuaZipDir(); + /// The assignment operator. + bool operator==(const QuaZipDir &that); + /// operator!= + /** + \return \c true if either this and \a that use different QuaZip + instances or if they point to different directories. + */ + inline bool operator!=(const QuaZipDir &that) {return !operator==(that);} + /// operator== + /** + \return \c true if both this and \a that use the same QuaZip + instance and point to the same directory. + */ + QuaZipDir& operator=(const QuaZipDir &that); + /// Returns the name of the entry at the specified position. + QString operator[](int pos) const; + /// Returns the current case sensitivity mode. + QuaZip::CaseSensitivity caseSensitivity() const; + /// Changes the 'current' directory. + /** + * If the path starts with '/', it is interpreted as an absolute + * path from the root of the archive. Otherwise, it is interpreted + * as a path relative to the current directory as was set by the + * previous cd() or the constructor. + * + * Note that the subsequent path() call will not return a path + * starting with '/' in all cases. + */ + bool cd(const QString &dirName); + /// Goes up. + bool cdUp(); + /// Returns the number of entries in the directory. + uint count() const; + /// Returns the current directory name. + /** + The name doesn't include the path. + */ + QString dirName() const; + /// Returns the list of the entries in the directory. + /** + \param nameFilters The list of file patterns to list, uses the same + syntax as QDir. + \param filters The entry type filters, only Files and Dirs are + accepted. + \param sort Sorting mode. + */ + QList entryInfoList(const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entries in the directory. + /** + \overload + + The same as entryInfoList(QStringList(), filters, sort). + */ + QList entryInfoList(QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entries in the directory with zip64 support. + /** + \param nameFilters The list of file patterns to list, uses the same + syntax as QDir. + \param filters The entry type filters, only Files and Dirs are + accepted. + \param sort Sorting mode. + */ + QList entryInfoList64(const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entries in the directory with zip64 support. + /** + \overload + + The same as entryInfoList64(QStringList(), filters, sort). + */ + QList entryInfoList64(QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entry names in the directory. + /** + The same as entryInfoList(nameFilters, filters, sort), but only + returns entry names. + */ + QStringList entryList(const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns the list of the entry names in the directory. + /** + \overload + + The same as entryList(QStringList(), filters, sort). + */ + QStringList entryList(QDir::Filters filters = QDir::NoFilter, + QDir::SortFlags sort = QDir::NoSort) const; + /// Returns \c true if the entry with the specified name exists. + /** + The ".." is considered to exist if the current directory + is not root. The "." and "/" are considered to + always exist. Paths starting with "/" are relative to + the archive root, other paths are relative to the current dir. + */ + bool exists(const QString &fileName) const; + /// Return \c true if the directory pointed by this QuaZipDir exists. + bool exists() const; + /// Returns the full path to the specified file. + /** + Doesn't check if the file actually exists. + */ + QString filePath(const QString &fileName) const; + /// Returns the default filter. + QDir::Filters filter(); + /// Returns if the QuaZipDir points to the root of the archive. + /** + Not that the root path is the empty string, not '/'. + */ + bool isRoot() const; + /// Return the default name filter. + QStringList nameFilters() const; + /// Returns the path to the current dir. + /** + The path never starts with '/', and the root path is an empty + string. + */ + QString path() const; + /// Returns the path to the specified file relative to the current dir. + /** + * This function is mostly useless, provided only for the sake of + * completeness. + * + * @param fileName The path to the file, should start with "/" + * if relative to the archive root. + * @return Path relative to the current dir. + */ + QString relativeFilePath(const QString &fileName) const; + /// Sets the default case sensitivity mode. + void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); + /// Sets the default filter. + void setFilter(QDir::Filters filters); + /// Sets the default name filter. + void setNameFilters(const QStringList &nameFilters); + /// Goes to the specified path. + /** + The difference from cd() is that this function never checks if the + path actually exists and doesn't use relative paths, so it's + possible to go to the root directory with setPath(""). + + Note that this function still chops the trailing and/or leading + '/' and treats a single '/' as the root path (path() will still + return an empty string). + */ + void setPath(const QString &path); + /// Sets the default sorting mode. + void setSorting(QDir::SortFlags sort); + /// Returns the default sorting mode. + QDir::SortFlags sorting() const; +}; + +#endif // QUAZIP_QUAZIPDIR_H diff --git a/libs/zip_libs/include/quazipfile.h b/libs/zip_libs/include/quazipfile.h new file mode 100644 index 0000000..e27b7a4 --- /dev/null +++ b/libs/zip_libs/include/quazipfile.h @@ -0,0 +1,456 @@ +#ifndef QUA_ZIPFILE_H +#define QUA_ZIPFILE_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include + +#include "quazip_global.h" +#include "quazip.h" +#include "quazipnewinfo.h" + +class QuaZipFilePrivate; + +/// A file inside ZIP archive. +/** \class QuaZipFile quazipfile.h + * This is the most interesting class. Not only it provides C++ + * interface to the ZIP/UNZIP package, but also integrates it with Qt by + * subclassing QIODevice. This makes possible to access files inside ZIP + * archive using QTextStream or QDataStream, for example. Actually, this + * is the main purpose of the whole QuaZIP library. + * + * You can either use existing QuaZip instance to create instance of + * this class or pass ZIP archive file name to this class, in which case + * it will create internal QuaZip object. See constructors' descriptions + * for details. Writing is only possible with the existing instance. + * + * Note that due to the underlying library's limitation it is not + * possible to use multiple QuaZipFile instances to open several files + * in the same archive at the same time. If you need to write to + * multiple files in parallel, then you should write to temporary files + * first, then pack them all at once when you have finished writing. If + * you need to read multiple files inside the same archive in parallel, + * you should extract them all into a temporary directory first. + * + * \section quazipfile-sequential Sequential or random-access? + * + * At the first thought, QuaZipFile has fixed size, the start and the + * end and should be therefore considered random-access device. But + * there is one major obstacle to making it random-access: ZIP/UNZIP API + * does not support seek() operation and the only way to implement it is + * through reopening the file and re-reading to the required position, + * but this is prohibitively slow. + * + * Therefore, QuaZipFile is considered to be a sequential device. This + * has advantage of availability of the ungetChar() operation (QIODevice + * does not implement it properly for non-sequential devices unless they + * support seek()). Disadvantage is a somewhat strange behaviour of the + * size() and pos() functions. This should be kept in mind while using + * this class. + * + **/ +class QUAZIP_EXPORT QuaZipFile: public QIODevice { + friend class QuaZipFilePrivate; + Q_OBJECT + private: + QuaZipFilePrivate *p; + // these are not supported nor implemented + QuaZipFile(const QuaZipFile& that); + QuaZipFile& operator=(const QuaZipFile& that); + protected: + /// Implementation of the QIODevice::readData(). + qint64 readData(char *data, qint64 maxSize); + /// Implementation of the QIODevice::writeData(). + qint64 writeData(const char *data, qint64 maxSize); + public: + /// Constructs a QuaZipFile instance. + /** You should use setZipName() and setFileName() or setZip() before + * trying to call open() on the constructed object. + **/ + QuaZipFile(); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object. + * + * You should use setZipName() and setFileName() or setZip() before + * trying to call open() on the constructed object. + **/ + QuaZipFile(QObject *parent); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object and \a + * zipName specifies ZIP archive file name. + * + * You should use setFileName() before trying to call open() on the + * constructed object. + * + * QuaZipFile constructed by this constructor can be used for read + * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. + **/ + QuaZipFile(const QString& zipName, QObject *parent =NULL); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object, \a + * zipName specifies ZIP archive file name and \a fileName and \a cs + * specify a name of the file to open inside archive. + * + * QuaZipFile constructed by this constructor can be used for read + * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. + * + * \sa QuaZip::setCurrentFile() + **/ + QuaZipFile(const QString& zipName, const QString& fileName, + QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); + /// Constructs a QuaZipFile instance. + /** \a parent argument specifies this object's parent object. + * + * \a zip is the pointer to the existing QuaZip object. This + * QuaZipFile object then can be used to read current file in the + * \a zip or to write to the file inside it. + * + * \warning Using this constructor for reading current file can be + * tricky. Let's take the following example: + * \code + * QuaZip zip("archive.zip"); + * zip.open(QuaZip::mdUnzip); + * zip.setCurrentFile("file-in-archive"); + * QuaZipFile file(&zip); + * file.open(QIODevice::ReadOnly); + * // ok, now we can read from the file + * file.read(somewhere, some); + * zip.setCurrentFile("another-file-in-archive"); // oops... + * QuaZipFile anotherFile(&zip); + * anotherFile.open(QIODevice::ReadOnly); + * anotherFile.read(somewhere, some); // this is still ok... + * file.read(somewhere, some); // and this is NOT + * \endcode + * So, what exactly happens here? When we change current file in the + * \c zip archive, \c file that references it becomes invalid + * (actually, as far as I understand ZIP/UNZIP sources, it becomes + * closed, but QuaZipFile has no means to detect it). + * + * Summary: do not close \c zip object or change its current file as + * long as QuaZipFile is open. Even better - use another constructors + * which create internal QuaZip instances, one per object, and + * therefore do not cause unnecessary trouble. This constructor may + * be useful, though, if you already have a QuaZip instance and do + * not want to access several files at once. Good example: + * \code + * QuaZip zip("archive.zip"); + * zip.open(QuaZip::mdUnzip); + * // first, we need some information about archive itself + * QByteArray comment=zip.getComment(); + * // and now we are going to access files inside it + * QuaZipFile file(&zip); + * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { + * file.open(QIODevice::ReadOnly); + * // do something cool with file here + * file.close(); // do not forget to close! + * } + * zip.close(); + * \endcode + **/ + QuaZipFile(QuaZip *zip, QObject *parent =NULL); + /// Destroys a QuaZipFile instance. + /** Closes file if open, destructs internal QuaZip object (if it + * exists and \em is internal, of course). + **/ + virtual ~QuaZipFile(); + /// Returns the ZIP archive file name. + /** If this object was created by passing QuaZip pointer to the + * constructor, this function will return that QuaZip's file name + * (or null string if that object does not have file name yet). + * + * Otherwise, returns associated ZIP archive file name or null + * string if there are no name set yet. + * + * \sa setZipName() getFileName() + **/ + QString getZipName()const; + /// Returns a pointer to the associated QuaZip object. + /** Returns \c NULL if there is no associated QuaZip or it is + * internal (so you will not mess with it). + **/ + QuaZip* getZip()const; + /// Returns file name. + /** This function returns file name you passed to this object either + * by using + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) + * or by calling setFileName(). Real name of the file may differ in + * case if you used case-insensitivity. + * + * Returns null string if there is no file name set yet. This is the + * case when this QuaZipFile operates on the existing QuaZip object + * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). + * + * \sa getActualFileName + **/ + QString getFileName() const; + /// Returns case sensitivity of the file name. + /** This function returns case sensitivity argument you passed to + * this object either by using + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) + * or by calling setFileName(). + * + * Returns unpredictable value if getFileName() returns null string + * (this is the case when you did not used setFileName() or + * constructor above). + * + * \sa getFileName + **/ + QuaZip::CaseSensitivity getCaseSensitivity() const; + /// Returns the actual file name in the archive. + /** This is \em not a ZIP archive file name, but a name of file inside + * archive. It is not necessary the same name that you have passed + * to the + * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), + * setFileName() or QuaZip::setCurrentFile() - this is the real file + * name inside archive, so it may differ in case if the file name + * search was case-insensitive. + * + * Equivalent to calling getCurrentFileName() on the associated + * QuaZip object. Returns null string if there is no associated + * QuaZip object or if it does not have a current file yet. And this + * is the case if you called setFileName() but did not open the + * file yet. So this is perfectly fine: + * \code + * QuaZipFile file("somezip.zip"); + * file.setFileName("somefile"); + * QString name=file.getName(); // name=="somefile" + * QString actual=file.getActualFileName(); // actual is null string + * file.open(QIODevice::ReadOnly); + * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows + * \endcode + * + * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity + **/ + QString getActualFileName()const; + /// Sets the ZIP archive file name. + /** Automatically creates internal QuaZip object and destroys + * previously created internal QuaZip object, if any. + * + * Will do nothing if this file is already open. You must close() it + * first. + **/ + void setZipName(const QString& zipName); + /// Returns \c true if the file was opened in raw mode. + /** If the file is not open, the returned value is undefined. + * + * \sa open(OpenMode,int*,int*,bool,const char*) + **/ + bool isRaw() const; + /// Binds to the existing QuaZip instance. + /** This function destroys internal QuaZip object, if any, and makes + * this QuaZipFile to use current file in the \a zip object for any + * further operations. See QuaZipFile(QuaZip*,QObject*) for the + * possible pitfalls. + * + * Will do nothing if the file is currently open. You must close() + * it first. + **/ + void setZip(QuaZip *zip); + /// Sets the file name. + /** Will do nothing if at least one of the following conditions is + * met: + * - ZIP name has not been set yet (getZipName() returns null + * string). + * - This QuaZipFile is associated with external QuaZip. In this + * case you should call that QuaZip's setCurrentFile() function + * instead! + * - File is already open so setting the name is meaningless. + * + * \sa QuaZip::setCurrentFile + **/ + void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); + /// Opens a file for reading. + /** Returns \c true on success, \c false otherwise. + * Call getZipError() to get error code. + * + * \note Since ZIP/UNZIP API provides buffered reading only, + * QuaZipFile does not support unbuffered reading. So do not pass + * QIODevice::Unbuffered flag in \a mode, or open will fail. + **/ + virtual bool open(OpenMode mode); + /// Opens a file for reading. + /** \overload + * Argument \a password specifies a password to decrypt the file. If + * it is NULL then this function behaves just like open(OpenMode). + **/ + inline bool open(OpenMode mode, const char *password) + {return open(mode, NULL, NULL, false, password);} + /// Opens a file for reading. + /** \overload + * Argument \a password specifies a password to decrypt the file. + * + * An integers pointed by \a method and \a level will receive codes + * of the compression method and level used. See unzip.h. + * + * If raw is \c true then no decompression is performed. + * + * \a method should not be \c NULL. \a level can be \c NULL if you + * don't want to know the compression level. + **/ + bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); + /// Opens a file for writing. + /** \a info argument specifies information about file. It should at + * least specify a correct file name. Also, it is a good idea to + * specify correct timestamp (by default, current time will be + * used). See QuaZipNewInfo. + * + * The \a password argument specifies the password for crypting. Pass NULL + * if you don't need any crypting. The \a crc argument was supposed + * to be used for crypting too, but then it turned out that it's + * false information, so you need to set it to 0 unless you want to + * use the raw mode (see below). + * + * Arguments \a method and \a level specify compression method and + * level. The only method supported is Z_DEFLATED, but you may also + * specify 0 for no compression. If all of the files in the archive + * use both method 0 and either level 0 is explicitly specified or + * data descriptor writing is disabled with + * QuaZip::setDataDescriptorWritingEnabled(), then the + * resulting archive is supposed to be compatible with the 1.0 ZIP + * format version, should you need that. Except for this, \a level + * has no other effects with method 0. + * + * If \a raw is \c true, no compression is performed. In this case, + * \a crc and uncompressedSize field of the \a info are required. + * + * Arguments \a windowBits, \a memLevel, \a strategy provide zlib + * algorithms tuning. See deflateInit2() in zlib. + **/ + bool open(OpenMode mode, const QuaZipNewInfo& info, + const char *password =NULL, quint32 crc =0, + int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, + int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); + /// Returns \c true, but \ref quazipfile-sequential "beware"! + virtual bool isSequential()const; + /// Returns current position in the file. + /** Implementation of the QIODevice::pos(). When reading, this + * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is + * unable to keep track of the ungetChar() calls (which is + * non-virtual and therefore is dangerous to reimplement). So if you + * are using ungetChar() feature of the QIODevice, this function + * reports incorrect value until you get back characters which you + * ungot. + * + * When writing, pos() returns number of bytes already written + * (uncompressed unless you use raw mode). + * + * \note Although + * \ref quazipfile-sequential "QuaZipFile is a sequential device" + * and therefore pos() should always return zero, it does not, + * because it would be misguiding. Keep this in mind. + * + * This function returns -1 if the file or archive is not open. + * + * Error code returned by getZipError() is not affected by this + * function call. + **/ + virtual qint64 pos()const; + /// Returns \c true if the end of file was reached. + /** This function returns \c false in the case of error. This means + * that you called this function on either not open file, or a file + * in the not open archive or even on a QuaZipFile instance that + * does not even have QuaZip instance associated. Do not do that + * because there is no means to determine whether \c false is + * returned because of error or because end of file was reached. + * Well, on the other side you may interpret \c false return value + * as "there is no file open to check for end of file and there is + * no end of file therefore". + * + * When writing, this function always returns \c true (because you + * are always writing to the end of file). + * + * Error code returned by getZipError() is not affected by this + * function call. + **/ + virtual bool atEnd()const; + /// Returns file size. + /** This function returns csize() if the file is open for reading in + * raw mode, usize() if it is open for reading in normal mode and + * pos() if it is open for writing. + * + * Returns -1 on error, call getZipError() to get error code. + * + * \note This function returns file size despite that + * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", + * for which size() should return bytesAvailable() instead. But its + * name would be very misguiding otherwise, so just keep in mind + * this inconsistence. + **/ + virtual qint64 size()const; + /// Returns compressed file size. + /** Equivalent to calling getFileInfo() and then getting + * compressedSize field, but more convenient and faster. + * + * File must be open for reading before calling this function. + * + * Returns -1 on error, call getZipError() to get error code. + **/ + qint64 csize()const; + /// Returns uncompressed file size. + /** Equivalent to calling getFileInfo() and then getting + * uncompressedSize field, but more convenient and faster. See + * getFileInfo() for a warning. + * + * File must be open for reading before calling this function. + * + * Returns -1 on error, call getZipError() to get error code. + **/ + qint64 usize()const; + /// Gets information about current file. + /** This function does the same thing as calling + * QuaZip::getCurrentFileInfo() on the associated QuaZip object, + * but you can not call getCurrentFileInfo() if the associated + * QuaZip is internal (because you do not have access to it), while + * you still can call this function in that case. + * + * File must be open for reading before calling this function. + * + * \return \c false in the case of an error. + * + * This function doesn't support zip64, but will still work fine on zip64 + * archives if file sizes are below 4 GB, otherwise the values will be set + * as if converted using QuaZipFileInfo64::toQuaZipFileInfo(). + * + * \sa getFileInfo(QuaZipFileInfo64*) + **/ + bool getFileInfo(QuaZipFileInfo *info); + /// Gets information about current file with zip64 support. + /** + * @overload + * + * \sa getFileInfo(QuaZipFileInfo*) + */ + bool getFileInfo(QuaZipFileInfo64 *info); + /// Closes the file. + /** Call getZipError() to determine if the close was successful. + **/ + virtual void close(); + /// Returns the error code returned by the last ZIP/UNZIP API call. + int getZipError() const; + /// Returns the number of bytes available for reading. + virtual qint64 bytesAvailable() const; +}; + +#endif diff --git a/libs/zip_libs/include/quazipfileinfo.h b/libs/zip_libs/include/quazipfileinfo.h new file mode 100644 index 0000000..4e142a4 --- /dev/null +++ b/libs/zip_libs/include/quazipfileinfo.h @@ -0,0 +1,178 @@ +#ifndef QUA_ZIPFILEINFO_H +#define QUA_ZIPFILEINFO_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant and contributors, +see quazip/(un)zip.h files for details. Basically it's the zlib license. +*/ + +#include +#include +#include + +#include "quazip_global.h" + +/// Information about a file inside archive. +/** + * \deprecated Use QuaZipFileInfo64 instead. Not only it supports large files, + * but also more convenience methods as well. + * + * Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to + * fill this structure. */ +struct QUAZIP_EXPORT QuaZipFileInfo { + /// File name. + QString name; + /// Version created by. + quint16 versionCreated; + /// Version needed to extract. + quint16 versionNeeded; + /// General purpose flags. + quint16 flags; + /// Compression method. + quint16 method; + /// Last modification date and time. + QDateTime dateTime; + /// CRC. + quint32 crc; + /// Compressed file size. + quint32 compressedSize; + /// Uncompressed file size. + quint32 uncompressedSize; + /// Disk number start. + quint16 diskNumberStart; + /// Internal file attributes. + quint16 internalAttr; + /// External file attributes. + quint32 externalAttr; + /// Comment. + QString comment; + /// Extra field. + QByteArray extra; + /// Get the file permissions. + /** + Returns the high 16 bits of external attributes converted to + QFile::Permissions. + */ + QFile::Permissions getPermissions() const; +}; + +/// Information about a file inside archive (with zip64 support). +/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to + * fill this structure. */ +struct QUAZIP_EXPORT QuaZipFileInfo64 { + /// File name. + QString name; + /// Version created by. + quint16 versionCreated; + /// Version needed to extract. + quint16 versionNeeded; + /// General purpose flags. + quint16 flags; + /// Compression method. + quint16 method; + /// Last modification date and time. + /** + * This is the time stored in the standard ZIP header. This format only allows + * to store time with 2-second precision, so the seconds will always be even + * and the milliseconds will always be zero. If you need more precise + * date and time, you can try to call the getNTFSmTime() function or + * its siblings, provided that the archive itself contains these NTFS times. + */ + QDateTime dateTime; + /// CRC. + quint32 crc; + /// Compressed file size. + quint64 compressedSize; + /// Uncompressed file size. + quint64 uncompressedSize; + /// Disk number start. + quint16 diskNumberStart; + /// Internal file attributes. + quint16 internalAttr; + /// External file attributes. + quint32 externalAttr; + /// Comment. + QString comment; + /// Extra field. + QByteArray extra; + /// Get the file permissions. + /** + Returns the high 16 bits of external attributes converted to + QFile::Permissions. + */ + QFile::Permissions getPermissions() const; + /// Converts to QuaZipFileInfo + /** + If any of the fields are greater than 0xFFFFFFFFu, they are set to + 0xFFFFFFFFu exactly, not just truncated. This function should be mainly used + for compatibility with the old code expecting QuaZipFileInfo, in the cases + when it's impossible or otherwise unadvisable (due to ABI compatibility + reasons, for example) to modify that old code to use QuaZipFileInfo64. + + \return \c true if all fields converted correctly, \c false if an overflow + occured. + */ + bool toQuaZipFileInfo(QuaZipFileInfo &info) const; + /// Returns the NTFS modification time + /** + * The getNTFS*Time() functions only work if there is an NTFS extra field + * present. Otherwise, they all return invalid null timestamps. + * @param fineTicks If not NULL, the fractional part of milliseconds returned + * there, measured in 100-nanosecond ticks. Will be set to + * zero if there is no NTFS extra field. + * @sa dateTime + * @sa getNTFSaTime() + * @sa getNTFScTime() + * @return The NTFS modification time, UTC + */ + QDateTime getNTFSmTime(int *fineTicks = NULL) const; + /// Returns the NTFS access time + /** + * The getNTFS*Time() functions only work if there is an NTFS extra field + * present. Otherwise, they all return invalid null timestamps. + * @param fineTicks If not NULL, the fractional part of milliseconds returned + * there, measured in 100-nanosecond ticks. Will be set to + * zero if there is no NTFS extra field. + * @sa dateTime + * @sa getNTFSmTime() + * @sa getNTFScTime() + * @return The NTFS access time, UTC + */ + QDateTime getNTFSaTime(int *fineTicks = NULL) const; + /// Returns the NTFS creation time + /** + * The getNTFS*Time() functions only work if there is an NTFS extra field + * present. Otherwise, they all return invalid null timestamps. + * @param fineTicks If not NULL, the fractional part of milliseconds returned + * there, measured in 100-nanosecond ticks. Will be set to + * zero if there is no NTFS extra field. + * @sa dateTime + * @sa getNTFSmTime() + * @sa getNTFSaTime() + * @return The NTFS creation time, UTC + */ + QDateTime getNTFScTime(int *fineTicks = NULL) const; + /// Checks whether the file is encrypted. + bool isEncrypted() const {return (flags & 1) != 0;} +}; + +#endif diff --git a/libs/zip_libs/include/quazipnewinfo.h b/libs/zip_libs/include/quazipnewinfo.h new file mode 100644 index 0000000..bfd4986 --- /dev/null +++ b/libs/zip_libs/include/quazipnewinfo.h @@ -0,0 +1,207 @@ +#ifndef QUA_ZIPNEWINFO_H +#define QUA_ZIPNEWINFO_H + +/* +Copyright (C) 2005-2014 Sergey A. Tachenov + +This file is part of QuaZIP. + +QuaZIP is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +QuaZIP is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with QuaZIP. If not, see . + +See COPYING file for the full LGPL text. + +Original ZIP package is copyrighted by Gilles Vollant, see +quazip/(un)zip.h files for details, basically it's zlib license. + **/ + +#include +#include +#include + +#include "quazip_global.h" + +#include "quazipfileinfo.h" + +/// Information about a file to be created. +/** This structure holds information about a file to be created inside + * ZIP archive. At least name should be set to something correct before + * passing this structure to + * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). + * + * Zip64 support of this structure is slightly limited: in the raw mode (when + * a pre-compressed file is written into a ZIP file as-is), it is necessary + * to specify the uncompressed file size and the appropriate field is 32 bit. + * Since the raw mode is used extremely rare, there is no real need to have + * a separate QuaZipNewInfo64 structure like QuaZipFileInfo64. It may be added + * in the future though, if there is a demand for the raw mode with zip64 + * archives. + **/ +struct QUAZIP_EXPORT QuaZipNewInfo { + /// File name. + /** This field holds file name inside archive, including path relative + * to archive root. + **/ + QString name; + /// File timestamp. + /** This is the last file modification date and time. Will be stored + * in the archive central directory. It is a good practice to set it + * to the source file timestamp instead of archive creating time. Use + * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). + **/ + QDateTime dateTime; + /// File internal attributes. + quint16 internalAttr; + /// File external attributes. + /** + The highest 16 bits contain Unix file permissions and type (dir or + file). The constructor QuaZipNewInfo(const QString&, const QString&) + takes permissions from the provided file. + */ + quint32 externalAttr; + /// File comment. + /** Will be encoded using QuaZip::getCommentCodec(). + **/ + QString comment; + /// File local extra field. + QByteArray extraLocal; + /// File global extra field. + QByteArray extraGlobal; + /// Uncompressed file size. + /** This is only needed if you are using raw file zipping mode, i. e. + * adding precompressed file in the zip archive. + **/ + ulong uncompressedSize; + /// Constructs QuaZipNewInfo instance. + /** Initializes name with \a name, dateTime with current date and + * time. Attributes are initialized with zeros, comment and extra + * field with null values. + **/ + QuaZipNewInfo(const QString& name); + /// Constructs QuaZipNewInfo instance. + /** Initializes name with \a name. Timestamp and permissions are taken + * from the specified file. If the \a file does not exists or its timestamp + * is inaccessible (e. g. you do not have read permission for the + * directory file in), uses current time and zero permissions. Other attributes are + * initialized with zeros, comment and extra field with null values. + * + * \sa setFileDateTime() + **/ + QuaZipNewInfo(const QString& name, const QString& file); + /// Initializes the new instance from existing file info. + /** Mainly used when copying files between archives. + * + * Both extra fields are initialized to existing.extra. + * @brief QuaZipNewInfo + * @param existing + */ + QuaZipNewInfo(const QuaZipFileInfo &existing); + /// Initializes the new instance from existing file info. + /** Mainly used when copying files between archives. + * + * Both extra fields are initialized to existing.extra. + * @brief QuaZipNewInfo + * @param existing + */ + QuaZipNewInfo(const QuaZipFileInfo64 &existing); + /// Sets the file timestamp from the existing file. + /** Use this function to set the file timestamp from the existing + * file. Use it like this: + * \code + * QuaZipFile zipFile(&zip); + * QFile file("file-to-add"); + * file.open(QIODevice::ReadOnly); + * QuaZipNewInfo info("file-name-in-archive"); + * info.setFileDateTime("file-to-add"); // take the timestamp from file + * zipFile.open(QIODevice::WriteOnly, info); + * \endcode + * + * This function does not change dateTime if some error occured (e. g. + * file is inaccessible). + **/ + void setFileDateTime(const QString& file); + /// Sets the file permissions from the existing file. + /** + Takes permissions from the file and sets the high 16 bits of + external attributes. Uses QFileInfo to get permissions on all + platforms. + */ + void setFilePermissions(const QString &file); + /// Sets the file permissions. + /** + Modifies the highest 16 bits of external attributes. The type part + is set to dir if the name ends with a slash, and to regular file + otherwise. + */ + void setPermissions(QFile::Permissions permissions); + /// Sets the NTFS times from an existing file. + /** + * If the file doesn't exist, a warning is printed to the stderr and nothing + * is done. Otherwise, all three times, as reported by + * QFileInfo::lastModified(), QFileInfo::lastRead() and QFileInfo::created(), + * are written to the NTFS extra field record. + * + * The NTFS record is written to + * both the local and the global extra fields, updating the existing record + * if there is one, or creating a new one and appending it to the end + * of each extra field. + * + * The microseconds will be zero, as they aren't reported by QFileInfo. + * @param fileName + */ + void setFileNTFSTimes(const QString &fileName); + /// Sets the NTFS modification time. + /** + * The time is written into the NTFS record in + * both the local and the global extra fields, updating the existing record + * if there is one, or creating a new one and appending it to the end + * of each extra field. When updating an existing record, all other fields + * are left intact. + * @param mTime The new modification time. + * @param fineTicks The fractional part of milliseconds, in 100-nanosecond + * ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than + * 9999 will add milliseconds or even seconds, but this can be + * confusing and therefore is discouraged. + */ + void setFileNTFSmTime(const QDateTime &mTime, int fineTicks = 0); + /// Sets the NTFS access time. + /** + * The time is written into the NTFS record in + * both the local and the global extra fields, updating the existing record + * if there is one, or creating a new one and appending it to the end + * of each extra field. When updating an existing record, all other fields + * are left intact. + * @param aTime The new access time. + * @param fineTicks The fractional part of milliseconds, in 100-nanosecond + * ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than + * 9999 will add milliseconds or even seconds, but this can be + * confusing and therefore is discouraged. + */ + void setFileNTFSaTime(const QDateTime &aTime, int fineTicks = 0); + /// Sets the NTFS creation time. + /** + * The time is written into the NTFS record in + * both the local and the global extra fields, updating the existing record + * if there is one, or creating a new one and appending it to the end + * of each extra field. When updating an existing record, all other fields + * are left intact. + * @param cTime The new creation time. + * @param fineTicks The fractional part of milliseconds, in 100-nanosecond + * ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than + * 9999 will add milliseconds or even seconds, but this can be + * confusing and therefore is discouraged. + */ + void setFileNTFScTime(const QDateTime &cTime, int fineTicks = 0); +}; + +#endif diff --git a/libs/zip_libs/include/trees.h b/libs/zip_libs/include/trees.h new file mode 100644 index 0000000..d35639d --- /dev/null +++ b/libs/zip_libs/include/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/libs/zip_libs/include/unzip.h b/libs/zip_libs/include/unzip.h new file mode 100644 index 0000000..da7b062 --- /dev/null +++ b/libs/zip_libs/include/unzip.h @@ -0,0 +1,458 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + + --------------------------------------------------------------------------- + + As per the requirement above, this file is plainly marked as modified + by Sergey A. Tachenov. Most modifications include the I/O API redesign + to support QIODevice interface. Some improvements and small fixes were also made. +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_AUTO_CLOSE 0x01u +#define UNZ_DEFAULT_FLAGS UNZ_AUTO_CLOSE + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((voidpf file)); +extern unzFile ZEXPORT unzOpen64 OF((voidpf file)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((voidpf file, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((voidpf file, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + + +/* + * Exported by Sergey A. Tachenov to implement some QuaZIP features. This + * function MAY change signature in order to implement even more features. + * You have been warned! + * */ +extern unzFile unzOpenInternal (voidpf file, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction, unsigned flags); + + + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + +extern int ZEXPORT unzSetFlags(unzFile file, unsigned flags); +extern int ZEXPORT unzClearFlags(unzFile file, unsigned flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/libs/zip_libs/include/zconf.h b/libs/zip_libs/include/zconf.h new file mode 100644 index 0000000..5e1d68a --- /dev/null +++ b/libs/zip_libs/include/zconf.h @@ -0,0 +1,534 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/libs/zip_libs/include/zip.h b/libs/zip_libs/include/zip.h new file mode 100644 index 0000000..a6617ad --- /dev/null +++ b/libs/zip_libs/include/zip.h @@ -0,0 +1,390 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + + --------------------------------------------------------------------------- + + As per the requirement above, this file is plainly marked as modified + by Sergey A. Tachenov. Most modifications include the I/O API redesign + to support QIODevice interface. Some improvements and small fixes were also made. + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#define ZIP_WRITE_DATA_DESCRIPTOR 0x8u +#define ZIP_AUTO_CLOSE 0x1u +#define ZIP_SEQUENTIAL 0x2u +#define ZIP_DEFAULT_FLAGS (ZIP_AUTO_CLOSE | ZIP_WRITE_DATA_DESCRIPTOR) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); +extern zipFile ZEXPORT zipOpen64 OF((voidpf file, int append)); +/* + Create a zipfile. + the file argument depends on the API used, for QuaZIP it's a QIODevice + pointer. + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((voidpf file, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((voidpf file, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +/* + * Exported by Sergey A. Tachenov to suit the needs of QuaZIP. + * Note that this function MAY change signature in order to + * provide new QuaZIP features. You have been warned! + * */ +extern zipFile ZEXPORT zipOpen3 (voidpf file, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + unsigned flags); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +/* + Added by Sergey A. Tachenov to tweak zipping behaviour. +*/ +extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags); +extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/libs/zip_libs/include/zlib.h b/libs/zip_libs/include/zlib.h new file mode 100644 index 0000000..f09cdaf --- /dev/null +++ b/libs/zip_libs/include/zlib.h @@ -0,0 +1,1912 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if any input has been consumed in a previous + deflate() call, then the input available so far is compressed with the old + level and strategy using deflate(strm, Z_BLOCK). There are three approaches + for the compression levels 0, 1..3, and 4..9 respectively. The new level + and strategy will take effect at the next call of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/libs/zip_libs/include/zutil.h b/libs/zip_libs/include/zutil.h new file mode 100644 index 0000000..b079ea6 --- /dev/null +++ b/libs/zip_libs/include/zutil.h @@ -0,0 +1,271 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/main.cpp b/main.cpp index 86aafd0..a5d3bf7 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,8 @@ #include "tegrarcmgui.h" - #include #include + int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -12,8 +12,9 @@ int main(int argc, char *argv[]) //appTranslator.load(QLocale(), QLatin1String("tegrarcmgui"), QLatin1String("_"), QLatin1String(":/i18n")); appTranslator.load("tegrarcmgui_fr", "languages"); a.installTranslator(&appTranslator); + TegraRcmGUI w; - w.setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + w.setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint); w.show(); return a.exec(); } diff --git a/packagemanager.cpp b/packagemanager.cpp new file mode 100644 index 0000000..3641b35 --- /dev/null +++ b/packagemanager.cpp @@ -0,0 +1,174 @@ +#include "packagemanager.h" +#include "ui_packagemanager.h" +#include "tegrarcmgui.h" +#include +#include +#include + +PackageManager::PackageManager(Packages* pkgs, TegraRcmGUI* parent) : + QDialog(parent), + ui(new Ui::PackageManager), m_parent(parent) +{ + ui->setupUi(this); + m_pkgs = pkgs; + + // Create model & connect to view + const auto view = ui->tableView; + m_um_model = new PackageManagerModel(m_pkgs, parent); + view->setModel(m_um_model); + view->setColumnWidth(0, 120); + view->setColumnWidth(1, 60); + view->setColumnWidth(2, 80); + view->setColumnWidth(3, 60); + view->setColumnWidth(4, 230); + view->setItemDelegateForColumn(4,new PackageManagerItemDelegate(this)); + view->setAlternatingRowColors(true); + view->show(); + + // Connect signals & slots + connect(m_pkgs, &Packages::updateProgress, this, &PackageManager::downloadProgress); + connect(m_pkgs, SIGNAL(updateLatestVerFinished()), this, SLOT(pkgUpdateVerFinished())); + connect(m_pkgs, &Packages::error, [=](QResult err) { + QMessageBox::critical(this, "Error", err.errorStr()); + }); + connect(m_pkgs, &Packages::updateFinished, [=]() { + if (m_pkgs->hasPendingDevInstalls()) + m_pkgs->devInstall(); + }); + + // Stylesheet + view->setStyleSheet(GetStyleSheetFromResFile(":/res/QTableView.qss")); + + m_pkgs->updateLatestVer(); +} + +PackageManager::~PackageManager() +{ + m_pkgs->disconnect(); + delete ui; +} + +void PackageManager::on_checkForUpdateBut_clicked() +{ + // Update packages latest version + //m_pkgs->updateLatestVer(); + + if (!m_pkgs->isUpdateAvailable()) + QMessageBox::information(this, "Update", "Everything is up to date"); + else pkgUpdateVerFinished(); + +} + +void PackageManager::downloadProgress(Packages::Package* pkg, qint64 current, qint64 total) +{ + m_um_model->updateProgress(pkg); +} + +void PackageManager::pkgUpdateVerFinished() +{ + + QString updateStr; + for (auto pkg : m_pkgs->all()) if (pkg->isUpdateAvailable()) + updateStr += "- "+ pkg->name() +" "+ pkg->latest_ver() +"\n"; + + if (updateStr.length()) + { + QString message(tr("Update available for the following packages:\n")+ updateStr +tr("\n Do you want to download & update ?")); + if (QMessageBox::question(this, tr("Update available"), message , QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes) + { + auto res = m_pkgs->update(); + if (!res.success()) + QMessageBox::critical(this, "Error", res.errorStr()); + } + } +} + + +QVariant PackageManagerModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= pkgs->count() || index.row() < 0) + return QVariant(); + + auto pkg = pkgs->at(index.row()); + auto col = index.column(); + + if (col == 0) + { + if (role == Qt::DisplayRole) + return pkg->name(); + else if (role == Qt::ToolTipRole) + return pkg->description(); + } + else if (col == 1) + { + if (role == Qt::DisplayRole) + return pkg->author(); + } + else if (col == 2) + { + if (role == Qt::DisplayRole) + return pkg->type(); + } + else if (col == 3) + { + if (role == Qt::DisplayRole) + return pkg->version(); + } + return QVariant(); +} + +void PackageManagerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + auto model = reinterpret_cast(index.model()); + auto pkg = model->pkgs->at(index.row()); + QString msg; + + switch (pkg->status()) { + case UNSET: + msg.append(""); + break; + case BROKEN: + msg.append(tr("Package is broken. Update needed")); + break; + case INSTALLED: + msg.append(tr("Package installed")); + break; + case INSTALL_FAILED: + msg.append(tr("Failed to install package")); + break; + case DOWNLOADING: + msg.append(tr("Downloading package...")); + break; + case UNZIPING: + msg.append(tr("Extracting package...")); + break; + case INSTALLING: + msg.append(tr("Installing package...")); + break; + case DEV_INSTALLING: + msg.append(tr("Installing on device...")); + break; + case DEV_INSTALL_PENDING: + msg.append(tr("Connect device to finish install")); + break; + } + + if (!is_in(pkg->status(), {DOWNLOADING, UNZIPING, INSTALLING})) + { + QStyleOptionViewItem itemOption(option); + initStyleOption(&itemOption, index); + itemOption.text = msg; + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &itemOption, painter); + return; + } + + QStyleOptionProgressBar progressBarOption; + progressBarOption.rect = option.rect; + progressBarOption.minimum = 0; + progressBarOption.maximum = 100; + progressBarOption.progress = pkg->updateProgress(); + progressBarOption.text = msg + (progressBarOption.progress ? QString::number(progressBarOption.progress) + "%" : ""); + progressBarOption.textVisible = true; + progressBarOption.textAlignment = Qt::AlignCenter; + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); +} diff --git a/packagemanager.h b/packagemanager.h new file mode 100644 index 0000000..1e89a4c --- /dev/null +++ b/packagemanager.h @@ -0,0 +1,103 @@ +#ifndef PACKAGEMANAGER_H +#define PACKAGEMANAGER_H + +#include +#include +#include "packages.h" +#include "qutils.h" + +class TegraRcmGUI; + +class PackageManagerModel : public QAbstractTableModel +{ + Q_OBJECT +public: + PackageManagerModel(Packages* packages, QObject *parent = nullptr) : QAbstractTableModel(parent), pkgs(packages), m_parent(parent) { } + QVariant headerData(int section, Qt::Orientation orientation, int role) const override { + if (role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QVariant(); + + if (section == 0) + return QString("Package"); + else if (section == 1) + return QString("Author"); + else if (section == 2) + return QString("Type"); + else if (section == 3) + return QString("Version"); + else + return QString("Status"); + } + int rowCount(const QModelIndex &parent = QModelIndex()) const override { + return parent.isValid() ? 0 : int(pkgs->count()); + } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { + return parent.isValid() ? 0 : 5; + } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override { + if (!index.isValid()) + return Qt::ItemIsEnabled; + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + } + void updateProgress(Packages::Package *pkg = nullptr) { + for (int i=0; i < pkgs->count(); i++) if (pkg == nullptr || pkgs->at(i) == pkg ){ + auto ix = index(i, 4, QModelIndex()); + emit dataChanged(ix, ix, {Qt::DisplayRole}); + if (pkg->status() == INSTALLED) + { + ix = index(i, 1, QModelIndex()); + emit dataChanged(ix, ix, {Qt::DisplayRole}); + } + } + } + void updateAll() { + auto topLeft = index(0, 0, QModelIndex()); + auto bottomRight = index(rowCount()-1, columnCount()-1, QModelIndex()); + emit dataChanged(topLeft, bottomRight, {Qt::DisplayRole}); + } + Packages* pkgs; +private: + QObject* m_parent; +}; + +// Item delegate for Update progress +class PackageManagerItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + PackageManagerItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const ; +}; + + +namespace Ui { +class PackageManager; +} + +class PackageManager : public QDialog +{ + Q_OBJECT + +public: + explicit PackageManager(Packages* pkgs, TegraRcmGUI *parent); + ~PackageManager(); + + PackageManagerModel* model() { return m_um_model; } + +public slots: + void pkgUpdateVerFinished(); + void downloadProgress(Packages::Package*, qint64, qint64); + +private slots: + void on_checkForUpdateBut_clicked(); + +private: + Ui::PackageManager *ui; + Packages* m_pkgs; + PackageManagerModel *m_um_model; + TegraRcmGUI* m_parent; + +}; + +#endif // PACKAGEMANAGER_H diff --git a/packagemanager.ui b/packagemanager.ui new file mode 100644 index 0000000..5f44452 --- /dev/null +++ b/packagemanager.ui @@ -0,0 +1,54 @@ + + + PackageManager + + + + 0 + 0 + 608 + 252 + + + + Package Manager + + + + + 10 + 10 + 111 + 22 + + + + Check for updates + + + + + + 10 + 40 + 591 + 201 + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + diff --git a/packages.cpp b/packages.cpp new file mode 100644 index 0000000..d54409f --- /dev/null +++ b/packages.cpp @@ -0,0 +1,497 @@ +#include "packages.h" +#include +#include "tegrarcmgui.h" +#include "QtConcurrent/QtConcurrent" + +bool JsonArrayContains(QJsonArray &arr, const QString &name ) { for (auto it : arr) if (it.toObject().contains("name") && it.toObject()["name"].toString() == name) return true; return false; }; + + +Packages::Package::Package(Packages *parent, const QString &package_name) : m_parent(parent) +{ + m_name = package_name; + auto findPackage = [&](const QString &path) { + QFile file(path); + if (!file.exists() || !file.open(QIODevice::ReadOnly)) + return false; + + QJsonObject json = QJsonDocument::fromJson(file.readAll()).object(); + file.close(); + if (!json.contains("packages")) + return false; + + for (auto pkg : json["packages"].toArray()) + { + auto obj = pkg.toObject(); + if (obj.contains("name") && obj["name"].toString() == package_name) + { + loadFromObj(obj); + return true; + } + } + return false; + }; + + if(!findPackage("packages/packages.json")) // Load from external file + findPackage(":/res/packages.json"); // Load from built_in packages +} + +Packages::Package::Package(Packages *parent, QJsonObject package_obj) : m_parent(parent) +{ + loadFromObj(package_obj); +} + +void Packages::Package::loadFromObj(QJsonObject obj) +{ + if (!m_name.length() && obj.contains("name")) + m_name = obj["name"].toString(); + if (obj.contains("version")) + m_version = obj["version"].toString(); + if (obj.contains("author")) + m_author = obj["author"].toString(); + if (obj.contains("description")) + m_description = obj["description"].toString(); + if (obj.contains("type")) + m_type = obj["type"].toString(); + if (obj.contains("url")) + m_url = obj["url"].toString(); + if (obj.contains("payload")) + m_payload = obj["payload"].toString(); + if (obj.contains("status")) + m_status = (PkgStatus) obj["status"].toInt(); + + if (m_version.length() && (!exists() || m_status > 10)) + m_status = BROKEN; +} + +bool Packages::Package::exists() +{ + return location().length() ? QFile(location() + "/package.json").exists() : false; +} + +QResult Packages::Package::update() +{ + if (!m_update_url.isValid()) + setUpdateVer(m_latest_ver, m_latest_url); + + if (!m_update_url.isValid()) + return QResult(InvalidUrl, m_update_url.toString(), APPEND); + + QDir dir("packages/" + m_name + "/" + m_update_version); + if (!dir.exists() && !dir.mkpath(".")) + return QResult(InvalidPath, dir.path(), APPEND); + + filePtr = new QFile(dir.path() + "/" + QFileInfo(m_update_url.toString()).fileName()); + if (!filePtr->open(QIODevice::WriteOnly)) + return QResult(FileCreateFailed, filePtr->fileName(), APPEND); + + QNetworkRequest request(m_update_url); + auto reply = m_parent->m_nm.get(request); + m_networkStatus = PENDING; + m_status = DOWNLOADING; + m_parent->m_pkgs_updating.append(this); + + connect(reply, &QNetworkReply::downloadProgress, [=](qint64 bytesReceived, qint64 bytesTotal) { + m_status = DOWNLOADING; + m_updateProgress = int(bytesReceived * 100 / bytesTotal); + emit m_parent->updateProgress(this, bytesReceived, bytesTotal); + }); + connect(reply, &QNetworkReply::readyRead, [=]() { + QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (!status_code.isValid() || status_code.toInt() != 200) + return; + filePtr->write(reply->readAll()); + }); + connect(reply, &QNetworkReply::finished, [=]() { + m_networkStatus = READY; + filePtr->close(); + reply->deleteLater(); + if (reply->error() != QNetworkReply::NetworkError::NoError) + { + filePtr->remove(); + m_status = INSTALL_FAILED; + } + else + { + auto res = unzip(filePtr->fileName()); + if (!res.success() && !exists()) + { + m_status = INSTALL_FAILED; + emit m_parent->error(res); + } + else + { + // Install package + auto jObj = json(); + if (jObj.contains("payload")) + { + m_payload = location() + "/" + jObj["payload"].toString(); + if (m_parent->m_gui && jObj.contains("install")) + { + for (auto j_cmd : jObj["install"].toArray()) if (j_cmd.toObject().contains("add_to_favorites") && j_cmd.toObject()["add_to_favorites"].toBool()) + { + QFile file(m_payload); + if (file.exists()) + { + if (!m_parent->m_gui->payloadTab->addFavorite(QFileInfo(file).fileName(), m_payload)) + { + m_status = INSTALL_FAILED; + emit m_parent->error(QResult(AddFavoriteFailed)); + } + break; + } + } + } + } + if (m_status != INSTALL_FAILED) + { + m_status = getFilesForDeviceInstall() ? DEV_INSTALL_PENDING : INSTALLED; + emit m_parent->updateProgress(this, 1, 1); + m_version = m_update_version; + m_parent->save(this); + } + + m_parent->m_pkgs_updating.removeAt(m_parent->m_pkgs_updating.indexOf(this)); + if (m_parent->m_pkgs_updating.empty()) + m_parent->emit updateFinished(); + } + } + delete filePtr; + }); + + return QResult(NoError); +} + +QResult Packages::Package::unzip(const QString &file_path, QString out_dir_path) { + + QFileInfo zip_fi(file_path); + if (!out_dir_path.size()) + out_dir_path = zip_fi.path(); + + if (out_dir_path.lastIndexOf("/") != out_dir_path.size()) + out_dir_path.append("/"); + + QuaZip zip(file_path); + if (!zip.open(QuaZip::mdUnzip)) + return QResult(ArchiveOpenFailed, file_path, APPEND); + + qint64 totaUncompressed = 0, currentUncompressed = 0; + for (auto fi : zip.getFileInfoList()) + totaUncompressed += fi.uncompressedSize; + + m_status = UNZIPING; + m_updateProgress = int(currentUncompressed * 100 / totaUncompressed); + emit m_parent->updateProgress(this, currentUncompressed, totaUncompressed); + + QuaZipFile zip_file(&zip); + QuaZipFileInfo fi; + // Process directories + for (bool b = zip.goToFirstFile(); b ; b = zip.goToNextFile()) if (zip_file.getFileInfo(&fi) && fi.externalAttr != 0x10 && fi.name.endsWith("/")) + { + QDir dir(out_dir_path + fi.name); + if (!dir.exists()) + dir.mkpath("."); + } + // Process file + for (bool b = zip.goToFirstFile(); b ; b = zip.goToNextFile()) if (zip_file.getFileInfo(&fi) && fi.externalAttr == 0x20) + { + zip_file.open(QIODevice::ReadOnly); + if (!zip_file.isOpen()) + return QResult(ArchiveOpenFailed, tr("Failed to open file ")+ fi.name + tr("in archive ") + zip_fi.fileName()); + + QFile file(out_dir_path + fi.name); + file.open(QIODevice::WriteOnly); + if (!file.isOpen()) + return QResult(FileCreateFailed, file.fileName(), APPEND); + + char buffer[0x100000]; + while (qint64 bytesRead = zip_file.read(buffer, 0x100000)) + { + currentUncompressed += file.write(buffer, bytesRead); + m_updateProgress = int(currentUncompressed * 100 / totaUncompressed); + emit m_parent->updateProgress(this, currentUncompressed, totaUncompressed); + } + zip_file.close(); + file.close(); + + if (file.size() != fi.uncompressedSize) + { + file.remove(); + return QResult(UnZipFailed, tr("Failed to unzip file ")+ fi.name + tr("in archive ") + zip_fi.fileName()); + } + } + return QResult(NoError); +} + +QJsonObject Packages::Package::json() +{ + QJsonObject obj; + if (!exists()) + return obj; + + QFile file(location() + "/package.json"); + if (!file.open(QIODevice::ReadOnly)) + return obj; + + obj = QJsonDocument::fromJson(file.readAll()).object(); + file.close(); + return obj; +} + +bool Packages::Package::getFilesForDeviceInstall() +{ + auto jobj = json(); + if (!jobj.contains("install")) + return false; + + auto install_cmds = jobj["install"].toArray(); + + m_dev_install_cpys.clear(); + for (auto cmd : install_cmds) if (cmd.toObject().contains("copy")) + { + auto cp_cmd = cmd.toObject()["copy"].toObject(); + if (!cp_cmd.contains("source") || !cp_cmd.contains("destination")) + continue; + + QString source = location() + "/" + cp_cmd["source"].toString(); + + QString destination = cp_cmd["destination"].toString(); + if (!destination.startsWith("sdmmc:")) + continue; + destination = destination.right(destination.length()-6); + + QDir dir(source); + if (dir.exists()) + { + if (!source.endsWith("/")) + source.append("/"); + if (!destination.endsWith("/")) + destination.append("/"); + + dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks); + QDirIterator it(dir, QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString item = it.next(); + QString path = item.mid(source.length(), item.length()); + m_dev_install_cpys.append({ source + path, destination + path}); + } + } + else if (QFile(source).exists()) + m_dev_install_cpys.append({ source, destination}); + } + return !m_dev_install_cpys.empty(); +} + +void Packages::Package::setStatus(PkgStatus s, qint64 current, qint64 total) +{ + m_status = s; + emit m_parent->updateProgress(this, current, total); + m_parent->save(); +} + +Packages::Packages() +{ + qRegisterMetaType("QResult"); + qRegisterMetaType("Package*"); + connect(&m_nm, &QNetworkAccessManager::finished, [=](QNetworkReply* reply) { + if (reply->error() != QNetworkReply::NetworkError::NoError) + emit error(QResult(NetworkError, reply->errorString())); + }); + this->loadPackages(); + + // Test + /*auto ams = get("Atmosphere"); + if (ams) + ams->getFilesForDeviceInstall(); + */ + save(); +} + +Packages::~Packages() { + for (auto pkg : m_packages) + delete pkg; +} + +bool Packages::loadPackages() +{ + m_packages.clear(); + auto load = [&](const QString &path) { + QFile ext_file(path); + if (ext_file.exists() && ext_file.open(QIODevice::ReadOnly)) + { + QJsonObject json = QJsonDocument::fromJson(ext_file.readAll()).object(); + if (json.contains("packages")) for (auto pkg : json["packages"].toArray()) + { + if (!this->contains(pkg.toObject()["name"].toString())) + m_packages.push_back(new Packages::Package(this, pkg.toObject())); + } + ext_file.close(); + } + }; + + load("packages/packages.json");// Load from external file + load(":/res/packages.json"); // Load built_in packages + return m_packages.count(); +} + +QResult Packages::save(Package* in_pkg) +{ + QJsonArray json_pkgs; + /// LAMBDA: Update a package JsonObject + auto upd_pkg = [&json_pkgs](Package* from_pkg, int index) { + auto to_obj = json_pkgs[index].toObject(); + to_obj["name"] = from_pkg->name(); + to_obj["version"] = from_pkg->version(); + if (from_pkg->payload().length()) + to_obj["payload"] = from_pkg->payload(); + to_obj["status"] = from_pkg->status(); + if (from_pkg->author().length()) + to_obj["author"] = from_pkg->author(); + if (from_pkg->description().length()) + to_obj["description"] = from_pkg->description(); + if (from_pkg->type().length()) + to_obj["type"] = from_pkg->type(); + if (from_pkg->url().length()) + to_obj["url"] = from_pkg->url(); + json_pkgs[index] = to_obj; + }; + /// LAMBDA: Retrieve or create JsonObject in json_pkgs + auto j_arr_get = [&json_pkgs](const QString &name) { + for (int i=0; iname())); + else for (auto pkg : m_packages) + upd_pkg(pkg, j_arr_get(pkg->name())); + + if (json_pkgs.count()) + { + QFile file("packages/packages.json"); + if (!file.open(QIODevice::WriteOnly)) + return QResult(FileOpenFailed, file.fileName(), APPEND); + + QJsonObject json; + json["packages"] = json_pkgs; + file.write(QJsonDocument(json).toJson(QJsonDocument::Indented)); + file.close(); + } + + return QResult(NoError); +} + +bool Packages::contains(const QString &pkg_name) +{ + if (!m_packages.count()) + return false; + + for (auto pkg : m_packages) if (pkg->name() == pkg_name) + return true; + + return false; +} + +Packages::Package* Packages::first() +{ + if (m_packages.isEmpty()) + return nullptr; + + m_pkg_cur_ix = 0; + return m_packages[m_pkg_cur_ix]; +} + +Packages::Package* Packages::next() +{ + + if (m_packages.isEmpty() || m_packages.count() < m_pkg_cur_ix+2) + return nullptr; + + m_pkg_cur_ix++; + return m_packages[m_pkg_cur_ix]; +} + +void Packages::updateLatestVer() +{ + if (!m_packages.size()) + { + emit updateLatestVerFinished(); + return; + } + + QUrl url("https://www.eliboa.com/switch/tegrarcmgui/packages/index.php?export=json&latest"); + QNetworkRequest request(url); + auto reply = m_nm.get(request); + m_networkStatus = reply->isRunning() ? PENDING : READY; + connect(reply, &QNetworkReply::readyRead, [=]() { + QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object(); + if (!json.contains("packages")) + return; + + auto pkg_updates = json["packages"].toArray(); + for (auto pkg_update : pkg_updates) { + auto update = pkg_update.toObject(); + if (auto pkg = this->get(update["name"].toString())) + { + // Package found + pkg->setLatestVer(update["version"].toString(), update["url"].toString()); + } + + } + }); + connect(reply, &QNetworkReply::finished, [this, reply]() { + m_networkStatus = READY; + emit updateLatestVerFinished(); + reply->deleteLater(); + }); +} + +QResult Packages::update(QList pkgs) +{ + QError err = NoError; + QString errStr; + auto dl = [&err, &errStr](Package* pkg) { + auto res = pkg->update(); + if (!res.success()) + { + err = Error; + errStr += res.errorStr() + "\n"; + } + }; + if (pkgs.empty()) for (auto pkg : m_packages) + { + if (pkg->isUpdateAvailable()) + dl(pkg); + } + else for (auto pkg : pkgs) dl(pkg); + + return QResult(err, errStr); +} + +void Packages::devInstall() +{ + if (!m_gui || !m_gui->m_kourou || !m_gui->m_device.arianeIsReady()) + return; + + QList upd_pkgs; + for (auto pkg : m_packages) if (pkg->status() == DEV_INSTALL_PENDING) + upd_pkgs.append(pkg); + + if (!upd_pkgs.empty()) + QtConcurrent::run(m_gui->m_kourou, &QKourou::copyFiles, upd_pkgs); +} + diff --git a/packages.h b/packages.h new file mode 100644 index 0000000..56268a5 --- /dev/null +++ b/packages.h @@ -0,0 +1,143 @@ +#ifndef PACKAGES_H +#define PACKAGES_H +#include +#include +#include "qutils.h" +#include +#include "qerror.h" + +class QKourou; +class TegraRcmGUI; + +typedef enum _NetStatus { + PENDING, + READY +} NetStatus; + +enum PkgStatus : int { + UNSET = 0, + BROKEN = 1, + INSTALL_FAILED = 2, + INSTALLED = 3, + DEV_INSTALL_PENDING = 4, + DOWNLOADING = 10, + UNZIPING = 11, + INSTALLING = 12, + DEV_INSTALLING = 14, +}; + +class Packages : public QObject +{ + Q_OBJECT + +public: + Packages(); + ~Packages(); + + // Nested class Package + class Package + { + public: + // Constructor + Package(Packages* parent, const QString &package_name); + Package(Packages* parent, QJsonObject package_obj); + + // Public members + + + // Getters + QString name() { return m_name; } + QString version() { return m_version; } + QString url() { return m_url; } + QString author() { return m_author; } + QString description() { return m_description; } + QString type() { return m_type; } + QString location() { return m_name.length() && m_version.length() ? "packages/" + m_name + "/" + m_version : ""; } + QString payload() { return m_payload; } + QString latest_ver() { return m_latest_ver; } + QUrl latest_ver_url() { return m_latest_url; } + QString update_version() { return m_update_version; } + QUrl update_url() { return m_update_url; } + PkgStatus status() { return m_status; } + int updateProgress() { return m_updateProgress; } + Cpys devInstallCpys() {return m_dev_install_cpys; } + Packages* parent() { return m_parent; } + + // Setters + void setLatestVer(const QString &ver, const QUrl &url) { m_latest_ver = ver; m_latest_url = url; } + void setUpdateVer(const QString &ver, const QUrl &url) { m_update_version = ver; m_update_url = url; } + void setStatus(PkgStatus s, qint64 current = 1, qint64 total = 1); + void clearDevInstallCpys() { m_dev_install_cpys.clear(); } + + // Public methods + bool exists(); + bool isUpdateAvailable() { return m_status < 10 && m_latest_ver.length() && (m_latest_ver != m_version || !exists()) && m_latest_url.isValid(); } + QResult update(); + QResult unzip(const QString &file_path, QString out_dir_path = ""); + QJsonObject json(); + bool getFilesForDeviceInstall(); + + private: + Packages *m_parent; + QString m_name; + QString m_version; + QString m_author; + QString m_description; + QString m_type; + QString m_url; + QString m_payload; + QString m_latest_ver; + QUrl m_latest_url; + QString m_update_version; + QUrl m_update_url; + QPointer filePtr = nullptr; + NetStatus m_networkStatus = READY; + PkgStatus m_status = PkgStatus::UNSET; + int m_updateProgress = 0; + Cpys m_dev_install_cpys; + + // Private methods + void loadFromObj(QJsonObject obj); + }; + + // Methods + void setParent(TegraRcmGUI* parent) { m_gui = parent; } + QResult save(Package* pkg = nullptr); + bool loadPackages(); + bool contains(const QString &pkg_name); + bool isPending() { return m_networkStatus == PENDING; } + bool isUpdateAvailable() { for (auto pkg : m_packages) if (pkg->isUpdateAvailable()) return true; return false; } + void updateLatestVer(); + QResult update(QList pkgs = QList()); + bool isUpdateInProcess() { return !m_pkgs_updating.empty(); } + bool hasPendingDevInstalls() { for (auto pkg : m_packages) if (pkg->status() == DEV_INSTALL_PENDING) return true; return false; } + void devInstall(); + + // Getters + Package* get(const QString &name) { for (auto pkg : m_packages) if (pkg->name() == name) return pkg; return nullptr; } + Package* first(); + Package* next(); + Package* at(const int i) { return m_packages.at(i); } + QVector all() { return m_packages; } + int count() { return m_packages.count(); } + +signals: + void updateLatestVerFinished(); + void updateFinished(); + void updateProgress(Package*, qint64, qint64); + void error(QResult); + +private: + QVector m_packages; + int m_pkg_cur_ix = 0; + + QNetworkAccessManager m_nm; + NetStatus m_networkStatus = READY; + bool m_update_available = false; + TegraRcmGUI *m_gui = nullptr; + QList m_pkgs_updating; + + QQueue dev_cpy_queue; +}; + +#endif // PACKAGES_H diff --git a/qerror.h b/qerror.h new file mode 100644 index 0000000..019f866 --- /dev/null +++ b/qerror.h @@ -0,0 +1,84 @@ +#ifndef QERROR_H +#define QERROR_H +#include +#include + +typedef enum _QError { + NoError, + Error, + InvalidUrl, + NetworkError, + InvalidPath, + FileOpenFailed, + FileCreateFailed, + ArchiveOpenFailed, + UnZipFailed, + AddFavoriteFailed +} QError; + +typedef enum _QErrorMode { + NO_MODE, + APPEND, +} QErrorMode; + +typedef struct _strArrEntry{ const QError err; const QString str; } strArrEntry; +static strArrEntry StrArr[] = { + { Error, QT_TR_NOOP("Generic Error ") }, + { InvalidUrl, QT_TR_NOOP("Invalid URL ") }, + { NetworkError, QT_TR_NOOP("Network Error ") }, + { InvalidPath, QT_TR_NOOP("Invalid Path ") }, + { FileOpenFailed, QT_TR_NOOP("Failed to open file ") }, + { FileCreateFailed, QT_TR_NOOP("Failed to create file ") }, + { ArchiveOpenFailed, QT_TR_NOOP("Failed to open archive ") }, + { UnZipFailed, QT_TR_NOOP("Failed to open unzip archive ") }, + { AddFavoriteFailed, QT_TR_NOOP("Failed to add payload to favorites ") } +}; + +static const QString ErrorStr(QError err) { + for (auto entry : StrArr) if (entry.err == err) + return entry.str; + return ""; +} + +typedef struct _QResult { + QError err; + QString str; + + _QResult(const QError error = NoError, const QString &errStr = "", const QErrorMode mode = NO_MODE) : err(error), str(errStr) { + if (mode == APPEND) + str = ErrorStr(err) + str; + } + + const QString errorStr() { + if (str.length()) + return str; + return ErrorStr(err); + } + + bool success() const { return err == NoError; } +} QResult; + + + + +/* +class QResult +{ +public: + QResult(QError err = NoError, const QString &errStr = "") : m_error(err), m_errorStr(errStr) {} + QError error() { return m_error; } + QString errorStr() { + if (m_errorStr.length()) + return m_errorStr; + return ErrorStr(m_error); + } + bool success() { return m_error == NoError; } + +private: + QError m_error; + QString m_errorStr; + + +}; +*/ +#endif // QERROR_H diff --git a/qhekate.cpp b/qhekate.cpp new file mode 100644 index 0000000..5ee9c5e --- /dev/null +++ b/qhekate.cpp @@ -0,0 +1,304 @@ +#include "tegrarcmgui.h" +#include "qhekate.h" +#include "ui_qhekate.h" +#include "qobjects/custombutton.h" +#include "qprogress_widget.h" + +qHekate::qHekate(TegraRcmGUI *parent) : QWidget(parent), ui(new Ui::qHekate), parent(parent) +{ + ui->setupUi(this); + m_kourou = parent->m_kourou; + m_device = &parent->m_device; + + // Connect signals & slots + connect(this, SIGNAL(error(int)), parent, SLOT(error(int))); + + initHekatePayload(); + + // Styles + ui->umsFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); + ui->configFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); + ui->umsLayout->setAlignment(Qt::AlignLeft); + ui->headerLayout->setAlignment(Qt::AlignLeft); + ui->configLayout->setAlignment(Qt::AlignRight); + + ui->hconfigTableWidget->setColumnCount(2); + ui->hconfigTableWidget->setColumnWidth(0, 110); + ui->hconfigTableWidget->setColumnWidth(1, 120); + ui->hconfigTableWidget->horizontalScrollBar()->setStyleSheet("QScrollBar {height:0px;}"); + ui->hconfigTableWidget->setStyleSheet(GetStyleSheetFromResFile(":/res/QTableWidget.qss")); + ui->hconfigTableWidget->setAlternatingRowColors(true); + + // Meta types + qRegisterMetaType("nyx_ums_type"); + + // Draw boxes + drawHeader(); + drawUmsBox(); + + /* + * TODO + * - Que faire si aucun payload ? + * + */ + +} + +qHekate::~qHekate() +{ + delete ui; +} + +bool qHekate::initHekatePayload() +{ + auto hekate_pkg = parent->m_pkgs.get("Hekate"); + if (!hekate_pkg || !hekate_pkg->exists() || !hekate_pkg->payload().length()) + return false; + + QFile payload(hekate_pkg->payload()); + payload.open(QIODevice::ReadOnly); + if (!payload.isOpen()) + return false; + + m_hekate_payload = payload.readAll(); + payload.close(); + + // Check nyx bin & get version + QFile nyx_bin(hekate_pkg->location() + "/bootloader/sys/nyx.bin"); + nyx_bin.open(QIODevice::ReadOnly); + if (nyx_bin.isOpen()) + { + nyx_bin.seek(0x99); + QString magic(nyx_bin.read(3)); + if (magic == "CTC") + { + m_nyx_version.major = QString(nyx_bin.read(1)).toInt(); + m_nyx_version.minor = QString(nyx_bin.read(1)).toInt(); + m_nyx_version.micro = QString(nyx_bin.read(1)).toInt(); + } + nyx_bin.close(); + } + + return true; +} + +void qHekate::on_tabActivated() +{ + //new WarningBox("TEST", ui->fullLayout); +} + +void qHekate::on_deviceStateChange() +{ + drawHeader(); + drawUmsBox(); + drawConfigBox(); +} + +void qHekate::on_deviceInfo_received() +{ + drawHeader(); + drawUmsBox(); +} + +void qHekate::drawHeader() +{ + // Clear all items in layout + ClearLayout(ui->headerLayout); + + auto hekate_pkg = parent->m_pkgs.get("Hekate"); + // Hekate's badge + if (m_hekate_payload.size() && hekate_pkg && hekate_pkg->version().length()) + { + Badge *hekate_badge = new Badge("Hekate", hekate_pkg->version(), this); + hekate_badge->setStatusTip(tr("Hekate's payload location: ") + hekate_pkg->payload()); + ui->headerLayout->addWidget(hekate_badge); + } + + auto di = m_device->deviceInfo(); + if (!m_device->isDeviceInfoAvailable() || !di.sdmmc_initialized || !m_hekate_payload.size()) + return; + + // Nyx & AMS badges + AppVersion nyx_ver; + nyx_ver.major = QString(di.nyx_version[0]).toInt(); + nyx_ver.minor = QString(di.nyx_version[1]).toInt(); + nyx_ver.micro = QString(di.nyx_version[2]).toInt(); + Badge *nyx_badge = new Badge("Nyx", !di.cbl_nyx ? "Not found" : GetAppVersionAsQString(nyx_ver), this); + ui->headerLayout->addWidget(nyx_badge); + + AppVersion ams_ver; + ams_ver.major = di.ams_version[0]; + ams_ver.minor = di.ams_version[1]; + ams_ver.micro = di.ams_version[2]; + Badge *ams_badge = new Badge("AMS", !di.cfw_ams ? "Not found" : GetAppVersionAsQString(ams_ver), this); + ui->headerLayout->addWidget(ams_badge); + + // Header button lambda + auto createHeaderButton = [&](const QString& label, void(qHekate::* slotName)()) + { + auto *button = new CustomButton(parent, label); + button->addEnableCondition(C_ARIANE_READY); + button->setFixedHeight(22); + button->setStyleSheet("padding: 5px;"); + connect(button, &QPushButton::clicked, this, slotName); + button->setStatusTip(tr("%1 on device (i.e needed files will be copied to SD card)").arg(label)); + ui->headerLayout->addWidget(button); + }; + // Create buttons + createHeaderButton(tr("Install Hekate/Nyx"), &qHekate::on_hekate_install); + createHeaderButton(tr("Install AMS"), &qHekate::on_ams_install); +} + +void qHekate::drawConfigBox() +{ + ClearLayout(ui->configLayout); + if (!m_kourou->hekate_ini) + return; + + auto cfg_list = ui->configComboBox; + auto configs = m_kourou->hekate_ini->configs()->data(); + + cfg_list->clear(); + for (auto config : configs) + { + QVariant id = config->getValue("id"); + if (id.toString().size()) + cfg_list->addItem(config->name(), id); + } + + if (cfg_list->count()) + { + auto *button = new CustomButton(parent, "Launch config"); + button->setFixedSize(100, 22); + connect(button, &QPushButton::clicked, [=]() { + emit on_launchHekateConfig(); + }); + button->setStatusTip(tr("Launch selected config")); + button->addEnableCondition(C_READY_FOR_PAYLOAD); + ui->configLayout->addWidget(button, 0, 0); + } +} + +void qHekate::drawUmsBox() +{ + // Clear all items in layout + ClearLayout(ui->umsLayout); + + if (!m_device->arianeIsReady()) + { + QString label(tr("Ariane needs to be loaded.\n")); + label.append(m_kourou->autoLaunchAriane ? tr("Boot device to RCM") : tr("Enable Ariane autoboot first")); + new WarningBox(label, ui->umsLayout); + return; + } + + auto di = m_device->deviceInfo(); + + // We need available device infos + nyx installed on device + ariane loaded and ready + if (!m_device->isDeviceInfoAvailable() || !di.cbl_nyx) + return; + + // UMS button lambda + auto createUmsButton = [&](const QString& storage, nyx_ums_type ums_type, int row, int col) + { + auto *button = new CustomButton(parent, storage, LIGHT); + button->setFixedSize(100, 22); + connect(button, &QPushButton::clicked, [=]() { + emit on_launchHekateUms(ums_type); + }); + button->setStatusTip(tr("Mount %1 as an external hard drive").arg(storage)); + ui->umsLayout->addWidget(button, row, col); + }; + + // Create UMS buttons + if (di.sdmmc_initialized) createUmsButton(tr("SD Card"), NYX_UMS_SD_CARD, 0, 0); + createUmsButton(tr("eMMC RAWNAND"), NYX_UMS_EMMC_GPP, 0, 1); + createUmsButton(tr("eMMC BOOT0"), NYX_UMS_EMMC_BOOT0, 0, 2); + createUmsButton(tr("eMMC BOOT1"), NYX_UMS_EMMC_BOOT1, 0, 3); + + if (!di.emunand_enabled) + return; + + createUmsButton(tr("EMU RAWNAND"), NYX_UMS_EMUMMC_GPP, 1, 0); + createUmsButton(tr("EMU BOOT0"), NYX_UMS_EMUMMC_BOOT0, 1, 1); + createUmsButton(tr("EMU BOOT1"), NYX_UMS_EMUMMC_BOOT0, 1, 2); +} + +void qHekate::on_launchHekateUms(nyx_ums_type type) +{ + if (!m_hekate_payload.size()) + return; + + // Clear boot config + for (int i=0x94; i < 0x105; i++) + m_hekate_payload[i] = 0; + + // Set boot config + m_hekate_payload[0x97] = EXTRA_CFG_NYX_UMS; + m_hekate_payload[0x98] = type; + + QtConcurrent::run(m_kourou, &QKourou::hack, (u8*)m_hekate_payload.data(), (u32)m_hekate_payload.size()); +} + +void qHekate::on_launchHekateConfig() +{ + if (!m_hekate_payload.size()) + return; + + QString id = ui->configComboBox->currentData().toString(); + if (!id.size()) + { + parent->pushMessage(tr("No config selected")); + return; + } + + // Clear boot config + for (int i=0x94; i < 0x105; i++) + m_hekate_payload[i] = 0; + + // Set boot config + m_hekate_payload[0x94] = BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_ID; + m_hekate_payload.replace(0x98, id.size() < 8 ? id.size() : 8, id.toLocal8Bit().constData()); + + QtConcurrent::run(m_kourou, &QKourou::hack, (u8*)m_hekate_payload.data(), (u32)m_hekate_payload.size()); +} + + +void qHekate::on_hekate_install() +{ + QString path = QFileInfo(m_payloads.at(0).file_path).absolutePath(); + QtConcurrent::run(m_kourou, &QKourou::installSDFiles, path, false); +} + +void qHekate::on_ams_install() +{ + QtConcurrent::run(m_kourou, &QKourou::installSDFiles, QString("atmosphere"), true); +} + + +void qHekate::on_configComboBox_currentIndexChanged(int index) +{ + QString id = ui->configComboBox->currentData().toString(); + auto tw = ui->hconfigTableWidget; + tw->setRowCount(0); + + if (!m_kourou->hekate_ini) + return; + + auto config = m_kourou->hekate_ini->configs()->getConfigById(id); + if (!config) + return; + + for (auto entry : config->entries()) + { + tw->insertRow(tw->rowCount()); + auto label_i = new QTableWidgetItem(entry.name); + label_i->setTextAlignment(Qt::AlignLeft |Qt::AlignVCenter); + label_i->setFlags(label_i->flags() ^ Qt::ItemIsEditable); + auto value_i = new QTableWidgetItem(entry.value.toString()); + value_i->setTextAlignment(Qt::AlignLeft |Qt::AlignVCenter); + tw->setItem(tw->rowCount()-1, 0, label_i); + tw->setItem(tw->rowCount()-1, 1, value_i); + } + tw->resizeColumnsToContents(); +} diff --git a/qhekate.h b/qhekate.h new file mode 100644 index 0000000..b29cf7a --- /dev/null +++ b/qhekate.h @@ -0,0 +1,98 @@ +#ifndef QHEKATE_H +#define QHEKATE_H + +#include +#include "qutils.h" + + +#define BOOT_CFG_AUTOBOOT_EN (1 << 0) +#define BOOT_CFG_FROM_LAUNCH (1 << 1) +#define BOOT_CFG_FROM_ID (1 << 2) +#define BOOT_CFG_TO_EMUMMC (1 << 3) +#define BOOT_CFG_SEPT_RUN (1 << 7) + +#define EXTRA_CFG_KEYS (1 << 0) +#define EXTRA_CFG_PAYLOAD (1 << 1) +#define EXTRA_CFG_MODULE (1 << 2) + +#define EXTRA_CFG_NYX_BIS (1 << 4) +#define EXTRA_CFG_NYX_UMS (1 << 5) +#define EXTRA_CFG_NYX_RELOAD (1 << 6) +#define EXTRA_CFG_NYX_DUMP (1 << 7) + +typedef enum _nyx_ums_type +{ + NYX_UMS_SD_CARD = 0, + NYX_UMS_EMMC_BOOT0, + NYX_UMS_EMMC_BOOT1, + NYX_UMS_EMMC_GPP, + NYX_UMS_EMUMMC_BOOT0, + NYX_UMS_EMUMMC_BOOT1, + NYX_UMS_EMUMMC_GPP +} nyx_ums_type; + +struct HekatePayload +{ + QString file_path; + AppVersion version; + + bool operator<(const HekatePayload &other) const + { + // Default is desc sort + if (!(other.version == version)) + return other.version < version; + else + return other.file_path < file_path; + } +}; + +class TegraRcmGUI; +class Kourou; +class QKourou; +class qProgressWidget; + +QT_BEGIN_NAMESPACE +namespace Ui { class qHekate; } +QT_END_NAMESPACE + +class qHekate : public QWidget +{ + Q_OBJECT + +public: + explicit qHekate(TegraRcmGUI *parent = nullptr); + ~qHekate(); + + bool initHekatePayload(); + +private: + Ui::qHekate *ui; + TegraRcmGUI *parent; + QKourou *m_kourou; + Kourou *m_device; + qProgressWidget *m_progressWidget; + QVector m_payloads; + AppVersion m_nyx_version; + QByteArray m_hekate_payload; + + void drawHeader(); + void drawConfigBox(); + void drawUmsBox(); + +signals: + void error(int); + +public slots: + void on_tabActivated(); + void on_deviceStateChange(); + void on_deviceInfo_received(); + void on_launchHekateUms(nyx_ums_type type); + void on_launchHekateConfig(); + +private slots: + void on_hekate_install(); + void on_ams_install(); + void on_configComboBox_currentIndexChanged(int index); +}; + +#endif // QHEKATE_H diff --git a/qhekate.ui b/qhekate.ui new file mode 100644 index 0000000..15144f9 --- /dev/null +++ b/qhekate.ui @@ -0,0 +1,148 @@ + + + qHekate + + + + 0 + 0 + 499 + 380 + + + + Form + + + + + 10 + 240 + 461 + 101 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 311 + 16 + + + + USB Mass Storage quick launch + + + + + + 10 + 30 + 441 + 61 + + + + + + + + + 10 + 10 + 461 + 31 + + + + + + + + 10 + 50 + 461 + 181 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 101 + 22 + + + + Hekate's configs: + + + + + + 10 + 140 + 441 + 31 + + + + + + + + 110 + 10 + 211 + 22 + + + + + + + 10 + 40 + 441 + 91 + + + + QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + true + + + false + + + false + + + 18 + + + 18 + + + + + + + diff --git a/qkourou.cpp b/qkourou.cpp index 0abf5cd..da8cfa2 100644 --- a/qkourou.cpp +++ b/qkourou.cpp @@ -1,4 +1,6 @@ #include "qkourou.h" +#include "tegrarcmgui.h" +#include "qprogress_widget.h" #include #include #include @@ -11,13 +13,22 @@ QKourou::QKourou(QWidget *parent, Kourou* device, TegraRcmGUI* gui) : QWidget(pa connect(this, SIGNAL(clb_error(int)), parent, SLOT(error(int))); connect(this, SIGNAL(clb_deviceStateChange()), parent, SLOT(on_deviceStateChange())); connect(this, SIGNAL(clb_finished(int)), parent, SLOT(on_Kourou_finished(int))); - connect(this, SIGNAL(pushMessage(QString)), parent, SLOT(pushMessage(QString))); + connect(this, SIGNAL(pushMessage(const QString)), parent, SLOT(pushMessage(const QString))); + connect(this, SIGNAL(initProgressWidget(const QString, int)), gui->m_progressWidget, SLOT(init_ProgressWidget(const QString, int))); + connect(this, SIGNAL(sendStatusLbl(const QString)), gui->m_progressWidget, SLOT(setLabel(const QString))); + connect(this, SIGNAL(closeProgressWidget()), gui->m_progressWidget, SLOT(close())); +} + +QKourou::~QKourou() +{ + if (m_hekate_ini != nullptr) + delete m_hekate_ini; } void QKourou::initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo) { if (!waitUntilUnlock()) - return; + return; DWORD error = 0; bool devInfoSync = false; @@ -28,7 +39,7 @@ void QKourou::initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo) if (!m_device->initDevice(deviceInfo)) error = GetLastError(); - emit clb_deviceStateChange(); + //emit clb_deviceStateChange(); bool b_autoInject = false; if (!error) @@ -41,16 +52,18 @@ void QKourou::initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo) // Auto boot Ariane if (!error && !b_autoInject && !m_device->arianeIsReady() && autoLaunchAriane && ariane_bin.size()) { + emit initProgressWidget(tr("Loading Ariane..."), 5); arianeIsLoading = true; - error = m_device->hack((u8*)ariane_bin.data(), (u32)ariane_bin.size()); + emit clb_deviceStateChange(); + error = m_device->hack((u8*)ariane_bin.data(), (u32)ariane_bin.size()); + QThread::msleep(1000); // Wait for Ariane to be fully loaded + emit sendStatusLbl(tr("Retrieving device info...")); if (!error) - m_device->arianeIsReady_sync(); + m_device->arianeIsReady_sync(); //waitUntilArianeReady(); - arianeIsLoading = false; + arianeIsLoading = false; } - } - - setLockEnabled(false); + } if (error && !silent) emit clb_error(int(error)); @@ -59,14 +72,36 @@ void QKourou::initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo) emit clb_finished(AUTO_INJECT); // Get device info if ariane is ready - if (m_device->arianeIsReady()) + if (m_device->arianeIsReady()) devInfoSync = !(m_device->getDeviceInfo(&di)); - setLockEnabled(false); - emit clb_deviceStateChange(); + if (devInfoSync) emit clb_deviceInfo(di); - if (devInfoSync) - emit clb_deviceInfo(di); + + // Read hekate_ipl.ini from device + if (devInfoSync && di.cbl_hekate) + { + emit sendStatusLbl(tr("Retrieving hekate's config")); + Bytes ini_file; + u32 bytesRead = 0; + if(!m_device->sdmmc_readFile("bootloader/hekate_ipl.ini", &ini_file, &bytesRead)) + { + if (m_hekate_ini != nullptr) delete m_hekate_ini; + // Create new Hekate ini + m_hekate_ini = new HekateIni(QByteArray(reinterpret_cast(ini_file.data()), ini_file.size())); + // Set configs ids if needed + if (m_hekate_ini->setConfigsIds()) + { + emit sendStatusLbl(tr("Updating hekate's config")); + std::vector data(m_hekate_ini->data().constBegin(), m_hekate_ini->data().constEnd()); + m_device->sdmmc_writeFile(&data, "bootloader/hekate_ipl.ini", true); + } + } + } + + emit closeProgressWidget(); + emit clb_deviceStateChange(); + setLockEnabled(false); } DWORD QKourou::autoInject() @@ -139,10 +174,6 @@ void QKourou::hack(const char* payload_path, u8 *payload_buff, u32 buff_size) DWORD res = 0; setLockEnabled(true); - // Reboot if ariane is loaded - if (m_device->arianeIsReady() && !rebootToRcm()) - res = GetLastError(); - // Push payload if(!res) res = payload_path != nullptr ? m_device->hack(payload_path) : m_device->hack(payload_buff, buff_size); @@ -175,6 +206,7 @@ bool QKourou::rebootToRcm() if (!err) { m_device->disconnect(); + m_device->resetCurrentBuffer(); if(!waitUntilInit(3)) err = RCM_REBOOT_FAILED; } @@ -207,6 +239,17 @@ bool QKourou::waitUntilRcmReady(uint timeout_s) return true; } +bool QKourou::waitUntilArianeReady(bool skip_rcm, uint timeout_s) +{ + qint64 begin_timestamp = QDateTime::currentSecsSinceEpoch(); + while(!m_device->arianeIsReady_sync(skip_rcm)) + { + if (QDateTime::currentSecsSinceEpoch() > begin_timestamp + timeout_s) + return false; + } + return true; +} + bool QKourou::waitUntilInit(uint timeout_s) { qint64 begin_timestamp = QDateTime::currentSecsSinceEpoch(); @@ -276,3 +319,163 @@ void QKourou::noDriverDeviceLookUp() if (!found) m_APX_device_reconnect = true; } + +void QKourou::copyFiles(QList in_pkgs) +{ + QList pkgs; + // Load install cpys from Json if necessary + for (auto pkg : in_pkgs) + { + if (pkg->devInstallCpys().empty()) + pkg->getFilesForDeviceInstall(); + + if (!pkg->devInstallCpys().empty()) + pkgs.append(pkg); + } + + if (pkgs.empty()) + return; + + ///LAMBDA: Exit + auto exit = [=](int err) { + setLockEnabled(false); + if (err) + { + for (auto pkg : pkgs) + pkg->setStatus(INSTALL_FAILED); + emit clb_error(err); + } + emit closeProgressWidget(); + }; + + if (!waitUntilUnlock()) + return exit(ARIANE_NOT_READY); + + setLockEnabled(true); + + for (auto pkg : pkgs) + pkg->setStatus(DEV_INSTALLING); + + emit initProgressWidget(tr("Preparing files"), 15); + + for (auto pkg : pkgs) + { + auto cpys = pkg->devInstallCpys(); // Get copy of InstallCpys + pkg->clearDevInstallCpys(); // Clear InstallCpys in package + for (auto cpy : cpys) + { + QString dest_path = cpy.destination.mid(0, cpy.destination.lastIndexOf('/')); + if (!m_device->sdmmc_mkPath(dest_path.toLocal8Bit().constData())) + return exit(FAILED_TO_MKDIR); + + emit sendStatusLbl(tr("Copying ") + cpy.destination); + int res = m_device->sdmmc_writeFile(cpy.source.toLocal8Bit().constData(), cpy.destination.toLocal8Bit().constData(), true); + + if (res != QFile(cpy.source).size()) + return exit(SD_FILE_WRITE_FAILED); + + } + pkg->setStatus(INSTALLED); + } + + emit sendStatusLbl(tr("Installation finished")); + QThread::msleep(1500); + UC_DeviceInfo di; + if(m_device->getDeviceInfo(&di) == SUCCESS) + emit clb_deviceInfo(di); + + return exit(SUCCESS); +} + +void QKourou::installSDFiles(QString input_path, bool ignore_ini) +{ + auto exit = [&](int err) { + setLockEnabled(false); + if (err) + emit clb_error(err); + emit closeProgressWidget(); + }; + + emit initProgressWidget(tr("Preparing files"), 15); + + bool is_dir = false; + if (QDir(input_path).exists()) + is_dir = true; + else if (!QFile(input_path).exists()) + return exit(BAD_ARGUMENT); + + QStringList directories; + QStringList files; + + if (is_dir) + { + QDir dir(input_path); + dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); + QDirIterator it(dir, QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString item = it.next(); + if (QDir(item).exists()) + directories << item; + else if (QFile(item).exists()) + files << item; + } + } + else files << input_path; + + if (!waitUntilUnlock()) + return exit(ARIANE_NOT_READY); + + setLockEnabled(true); + + // Create dirs + for (auto dir : directories) + { + QString outdir = dir.mid(input_path.length() + 1, dir.length()); + if (!m_device->sdmmc_isDir(outdir.toLocal8Bit().constData())) + { + if (!m_device->sdmmc_mkDir(outdir.toLocal8Bit().constData())) + return exit(FAILED_TO_MKDIR); + } + } + + // Create files + for (auto file : files) + { + QString outfile = file.mid(input_path.length() + 1, file.length()); + if (ignore_ini && outfile.endsWith(".ini") && m_device->sdmmc_fileSize(outfile.toLocal8Bit().constData())) + continue; + + emit sendStatusLbl(tr("Copying ") + outfile); + int res = m_device->sdmmc_writeFile(file.toLocal8Bit().constData(), outfile.toLocal8Bit().constData(), true); + + if (res != QFile(file).size()) + { + return exit(res ? res : SD_FILE_WRITE_FAILED); + } + } + + emit sendStatusLbl(tr("Installation finished")); + QThread::msleep(1500); + UC_DeviceInfo di; + if(m_device->getDeviceInfo(&di) == SUCCESS) + emit clb_deviceInfo(di); + + return exit(SUCCESS); + +} + +void QKourou::getKeys() +{ + if (!waitUntilUnlock()) + return; + + if (!m_device->arianeIsReady_sync()) + return; + + UC_Header uc; + uc.command = GET_KEYS; + // Send command + m_device->write((const u8*)&uc, sizeof(uc)); + QThread::msleep(500); +} diff --git a/qkourou.h b/qkourou.h index ab4ab65..1462f00 100644 --- a/qkourou.h +++ b/qkourou.h @@ -5,7 +5,8 @@ #include #include #include "kourou/kourou.h" -#include "tegrarcmgui.h" +#include "qobjects/hekate_ini.h" +#include "packages.h" typedef enum _qKourouAction : int { @@ -16,8 +17,11 @@ typedef enum _qKourouAction : int } qKourouAction; +class Kourou; class TegraRcmGUI; - +class qProgressWidget; +class HekateIni; +class Packages; /// /// \brief The QKourou class is a Qt thread safe reimplemented class of Kourou class, for TegraRcmGUI /// @@ -27,30 +31,35 @@ class QKourou : public QWidget { public: QKourou(QWidget *parent, Kourou* device, TegraRcmGUI* gui); + ~QKourou(); bool isLocked() { return m_locked; } QByteArray ariane_bin; bool autoLaunchAriane = true; bool autoInjectPayload = false; bool arianeIsLoading = false; + HekateIni *m_hekate_ini = nullptr; + HekateIni *&hekate_ini = m_hekate_ini; + Kourou* device() { return m_device; } private: + QWidget *parent; Kourou *m_device; TegraRcmGUI *m_gui; bool m_locked = false; bool m_force_lock = false; bool m_askForDriverInstall = true; - bool m_APX_device_reconnect = true; - QWidget *parent; + bool m_APX_device_reconnect = true; std::string tmp_string; + void hack(const char* payload_path, u8 *payload_buff, u32 buff_size); void setLockEnabled(bool enable) { m_locked = enable; } bool waitUntilUnlock(uint timeout_s = 10); bool waitUntilRcmReady(uint timeout_s = 10); + bool waitUntilArianeReady(bool skip_rcm = false, uint timeout_s = 10); bool waitUntilInit(uint timeout_s = 10); bool rebootToRcm(); DWORD autoInject(); - public slots: void initDevice(bool silent, KLST_DEVINFO_HANDLE deviceInfo = nullptr); void getDeviceInfo(); @@ -59,14 +68,20 @@ public slots: void initNoDriverDeviceLookUpLoop(); void noDriverDeviceLookUp(); void setAutoRcmEnabled(bool state); + void installSDFiles(QString input_path, bool ignore_ini = false); + void copyFiles(QList pkgs); + void getKeys(); signals: void clb_deviceInfo(UC_DeviceInfo di); void clb_error(int error); void clb_deviceStateChange(); void clb_finished(int res); - void clb_driverMissing(); - void pushMessage(QString); + void clb_driverMissing(); + void pushMessage(const QString); + void initProgressWidget(const QString, int); + void sendStatusLbl(const QString); + void closeProgressWidget(); }; #endif // QKOUROU_H diff --git a/qobjects/custombutton.cpp b/qobjects/custombutton.cpp new file mode 100644 index 0000000..31db161 --- /dev/null +++ b/qobjects/custombutton.cpp @@ -0,0 +1,85 @@ +#include "custombutton.h" +#include "../qutils.h" + +CustomButton::CustomButton(TegraRcmGUI *parent, const QString &text, ButtonStyle style) : QPushButton(parent), m_gui(parent) +{ + setText(text); + + QString stylesheet_file = ":/res/QPushButton.qss"; + if (style == LIGHT) + stylesheet_file = ":/res/QPushButton_light.qss"; + + setStyleSheet(GetStyleSheetFromResFile(stylesheet_file)); + + m_enabled = getFailedCondition() == C_NONE ? true : false; + setCursor(m_enabled ? Qt::PointingHandCursor : Qt::ForbiddenCursor); +} + +void CustomButton::addEnableCondition(BtnCondition condition) +{ + for (BtnCondition m_condition : m_enable_conditions) if (m_condition == condition) + return; + + m_enable_conditions.push_back(condition); +} + +void CustomButton::paintEvent(QPaintEvent *e) +{ + if (!m_enable_conditions.size()) + { + QPushButton::paintEvent(e); + return; + } + + auto failed = getFailedCondition(); + bool b_enabled = failed == C_NONE ? true : false; + if (b_enabled != m_enabled) + { + setCursor(b_enabled ? Qt::PointingHandCursor : Qt::ForbiddenCursor); + QPushButton::setStatusTip(getStatusTip(&failed)); + m_enabled = b_enabled; + } + + QPushButton::paintEvent(e); +} + +void CustomButton::setStatusTip(const QString &statusTip) +{ + m_statusTip = statusTip; + QPushButton::setStatusTip(getStatusTip()); +} + +BtnCondition CustomButton::getFailedCondition() +{ + for (auto condition : m_enable_conditions) + { + if ((condition == C_RCM_READY && !m_gui->m_device.rcmIsReady()) + || (condition == C_ARIANE_READY && !m_gui->m_device.arianeIsReady()) + || (condition == C_READY_FOR_PAYLOAD && !m_gui->m_device.isReadyToReceivePayload())) + return condition; + } + return C_NONE; +} + +QString CustomButton::getStatusTip(BtnCondition *failed_condition) +{ + auto failed = failed_condition ? *failed_condition : getFailedCondition(); + if (failed == C_RCM_READY) + return tr("No RCM device found"); + + if (failed == C_ARIANE_READY) + return tr("Ariane is not loaded/ready"); + + if (failed == C_READY_FOR_PAYLOAD) + return tr("No device found"); + + return m_statusTip; +} + +void CustomButton::mousePressEvent(QMouseEvent *e) +{ + if (!m_enabled) + return; + + QPushButton::mousePressEvent(e); +} diff --git a/qobjects/custombutton.h b/qobjects/custombutton.h new file mode 100644 index 0000000..529942d --- /dev/null +++ b/qobjects/custombutton.h @@ -0,0 +1,46 @@ +#ifndef CUSTOMBUTTON_H +#define CUSTOMBUTTON_H + +#include +#include +#include +#include "../tegrarcmgui.h" + +class TegraRcmGUI; + +typedef enum _ButtonStyle : int { + DEFAULT, + LIGHT +} ButtonStyle; + +typedef enum _BtnCondition : int { + C_NONE, + C_RCM_READY, + C_ARIANE_READY, + C_READY_FOR_PAYLOAD, +} BtnCondition; + +class CustomButton : public QPushButton +{ + Q_OBJECT +public: + CustomButton(TegraRcmGUI *parent, const QString &text, ButtonStyle style = DEFAULT); + void addEnableCondition(BtnCondition condition); + void setStatusTip(const QString &statusTip); + +private: + TegraRcmGUI *m_gui; + bool m_enabled = true; + QVector m_enable_conditions; + QString m_statusTip; + + QString getStatusTip(BtnCondition *failed_condition = nullptr); + BtnCondition getFailedCondition(); + +protected: + void paintEvent(QPaintEvent*) override; + void mousePressEvent(QMouseEvent *e); +}; + + +#endif // CUSTOMBUTTON_H diff --git a/qobjects/hekate_ini.cpp b/qobjects/hekate_ini.cpp new file mode 100644 index 0000000..764e36c --- /dev/null +++ b/qobjects/hekate_ini.cpp @@ -0,0 +1,292 @@ +#include "hekate_ini.h" + +HekateIni::HekateIni(QByteArray hekate_ini) +{ + if (!hekate_ini.size()) + return; + + m_hekate_ini = hekate_ini; + parseIni(); +} + +bool HekateIni::parseIni(HConfigs *in_configs) +{ + QTextStream ts(m_hekate_ini); + QString line; + HConfig *cur_cfg = nullptr; + HConfigs *configs = in_configs != nullptr ? in_configs : &m_configs; + + configs->clear(); + + while (ts.readLineInto(&line)) if (line.size()) + { + if (line.at(0) == "[" ) + { + auto cfg_name = QString(line.begin()+1, line.lastIndexOf("]")-1); + if (cfg_name != "config") + { + configs->addConfig(cfg_name); + cur_cfg = configs->last(); + } + else cur_cfg = configs->mainConfig(); + + } + else if (line.at(0) != "{" && line.contains("=") && cur_cfg) + { + int pos = line.indexOf("="); + cur_cfg->addEntry(line.left(pos), QVariant(line.right(line.size() - pos - 1))); + } + } + + return configs->size(); +} + +bool HekateIni::setConfigsIds() +{ + if (!m_configs.size()) + return false; + + bool result = false; + for (auto cfg : m_configs.data()) if (!cfg->exists("id")) + { + // Create new id + QString id_str; + QString cf_name_tr = cfg->name().trimmed().replace(" ", "_"); + for (int i(0); i < 10; i++) if (!m_configs.getConfigById(QString(cf_name_tr.begin(), 6).append(QString::number(i)))) + { + id_str = QString(cf_name_tr.begin(), 6).append(QString::number(i)); + break; + } + + if (id_str.size()) + { + cfg->setValue("id", id_str); + result = true; + } + } + + if (result) + rewriteIniData(); + + return result; +} + +bool HekateIni::rewriteIniData() +{ + QString out_str, line; + QTextStream ts(m_hekate_ini), out_ts(&out_str); + HConfig *cur_cfg = nullptr, *new_cfg = nullptr; + bool out_appened = false, first = true; + HConfigs old_cfgs, new_cfgs; + + // Look for new configs by inspecting old configs + if (m_hekate_ini.size() && parseIni(&old_cfgs)) + { + // Add new entries from main config + for (auto entry : m_configs.mainConfig()->entries()) if (!old_cfgs.mainConfig()->exists(entry.name)) + new_cfgs.mainConfig()->addEntry(entry.name, entry.value); + + // Loop inside current configs + for (auto cur_cfg : m_configs.data()) + { + auto old_cfg = old_cfgs.getConfig(cur_cfg->name()); + if (!old_cfg) // Current config not found in old configs + { + new_cfgs.addConfig(cur_cfg); + continue; + } + + HConfig *new_cfg = new HConfig(cur_cfg->name()); + // Add new entries (not found in old entries) + for (auto entry : cur_cfg->entries()) if (!old_cfg->exists(entry.name)) + new_cfg->addEntry(entry.name, entry.value); + + if (new_cfg->size()) + new_cfgs.addConfig(new_cfg); + } + } + else new_cfgs = m_configs; // Add all configs + + // Rewrite ini from old data + while (ts.readLineInto(&line)) + { + if (!line.size() && (cur_cfg || first)) + { + out_ts << "\n"; + continue; + } + + // Old config entry + if (line.at(0) == "[") + { + first = false; + cur_cfg = nullptr; + new_cfg = nullptr; + auto cfg_name = QString(line.begin()+1, line.lastIndexOf("]")-1); + + cur_cfg = cfg_name == "config" ? m_configs.mainConfig() : m_configs.getConfig(cfg_name); + if (cur_cfg) + { + new_cfg = cfg_name == "config" ? new_cfgs.mainConfig() : new_cfgs.getConfig(cur_cfg->name()); + + // Write config + out_ts << line << "\n"; + + // Write new entries + if (new_cfg) for (auto entry : new_cfg->entries()) + { + out_ts << entry.name << "=" << entry.value.toString() << "\n"; + out_appened = true; + } + } + continue; + } + + if (!cur_cfg || !first) + continue; // Do not write old lines if current config was deleted + + if (line.at(0) == "{" || !line.contains("=")) + { + out_ts << line << "\n"; + continue; + } + + // (re)write existing entries + int pos = line.indexOf("="); + auto entry_name = line.left(pos); + auto entry_old_value = QVariant(line.right(line.size() - pos - 1)); + auto entry_new_value = cur_cfg->getValue(entry_name); + if (!entry_new_value.isNull() && !entry_old_value.isNull() && entry_old_value != entry_new_value) + { + out_ts << entry_name << "=" << entry_new_value.toString() << "\n"; + out_appened = true; + } + else + out_ts << line << "\n"; + } + + // Append main config if absent + if (auto main_cfg = old_cfgs.getConfig("config")) + { + out_ts << "\n[config]\n"; + for (auto entry : main_cfg->entries()) + out_ts << entry.name << "=" << entry.value.toString(); + + out_appened = true; + } + // Append new configs to ini data + for (auto cfg : new_cfgs.data()) if (!old_cfgs.getConfig(cfg->name())) + { + out_ts << "\n" << "[" << cfg->name() << "]\n"; + for (auto entry : cfg->entries()) + out_ts << entry.name << "=" << entry.value.toString(); + + out_appened = true; + } + + if (out_appened) + { + // Replace ini's data + m_hekate_ini.clear(); + m_hekate_ini.append(out_str); + return true; + } + + return false; +} + + +HConfig::HConfig(const QString &cfg_name) +{ + m_name = cfg_name; +} + +bool HConfig::addEntry(const QString &entry_name, const QVariant &entry_value) +{ + if (!entry_name.size() || entry_value.isNull()) + return false; + + H_Entry entry; + entry.name = entry_name; + entry.value = entry_value; + m_entries.push_back(entry); + + return true; +} + +H_Entry* HConfig::getEntry(const QString &entry_name) +{ + for (int i(0); i < m_entries.size(); i++) if (!m_entries[i].name.compare(entry_name, Qt::CaseInsensitive)) + return &m_entries[i]; + + return nullptr; +} + +QVariant HConfig::getValue(const QString &entry_name) +{ + for (auto entry : m_entries) if (!entry.name.compare(entry_name, Qt::CaseInsensitive)) + return entry.value; + + return QVariant(); +} + +bool HConfig::setValue(const QString &entry_name, const QVariant &entry_value) +{ + if (!entry_name.size() || entry_value.isNull()) + return false; + + if (auto old_entry = getEntry(entry_name)) + { + old_entry->value = entry_value; + return true; + } + else return addEntry(entry_name, entry_value); +} + +bool HConfig::exists(const QString &entry_name) +{ + for (auto entry : m_entries) if (!entry.name.compare(entry_name, Qt::CaseInsensitive)) + return true; + + return false; +} + +HConfigs::~HConfigs() { + delete m_main_config; + for (auto cfg : m_configs) + delete cfg; +} + +bool HConfigs::addConfig(const QString &cfg_name) +{ + if (!cfg_name.size() || getConfig(cfg_name)) + return false; + + m_configs.push_back(new HConfig(cfg_name)); + return true; +} + +bool HConfigs::addConfig(HConfig *cfg) { + + if (getConfig(cfg->name())) + return false; + + m_configs.push_back(cfg); + return true; +} + +HConfig* HConfigs::getConfig(const QString &cfg_name) +{ + for (int i(0); i < m_configs.size(); i++) if (!m_configs[i]->name().compare(cfg_name, Qt::CaseInsensitive)) + return m_configs[i]; + + return nullptr; +} + +HConfig* HConfigs::getConfigById(const QString &id) +{ + for (int i(0); i < m_configs.size(); i++) if (!m_configs[i]->getValue("id").toString().compare(id, Qt::CaseInsensitive)) + return m_configs[i]; + + return nullptr; +} diff --git a/qobjects/hekate_ini.h b/qobjects/hekate_ini.h new file mode 100644 index 0000000..e0741c3 --- /dev/null +++ b/qobjects/hekate_ini.h @@ -0,0 +1,87 @@ +#ifndef HEKATEINI_H +#define HEKATEINI_H + +#include +#include +#include + +struct ini_entry_t { + QString name; + QVariant value; +}; + +struct ini_cfg_enty_t { + QString name; + QVector entries; +}; + +using H_Config = ini_cfg_enty_t; +using H_Configs = QVector; +using H_Entry = ini_entry_t; +using H_Entries = QVector; + +class HConfig +{ +public: + HConfig(const QString &cfg_name); + + QVariant getValue(const QString &entry_name); + bool setValue(const QString &entry_name, const QVariant &entry_value); + bool exists(const QString &entry_name); + QString name(){ return m_name; } + bool addEntry(const QString &entry_name, const QVariant &entry_value); + H_Entry* findEntry(const QString &entry_name); + H_Entries entries() { return m_entries; } + int size() { return m_entries.size(); } + +private: + QString m_name; + H_Entries m_entries; + + H_Entry* getEntry(const QString &entry_name); +}; + +class HConfigs +{ +public: + HConfigs() {} + ~HConfigs(); + bool addConfig(const QString &cfg_name); + bool addConfig(HConfig *cfg); + + HConfig* mainConfig() { return m_main_config; } + HConfig* getConfig(const QString &cfg_name); + HConfig* getConfigById(const QString &id); + QVector data() { return m_configs; } + void clear() { m_configs.clear(); } + int size() { return m_configs.size(); } + HConfig* last() { return !m_configs.size() ? nullptr : m_configs[m_configs.size()-1]; } + +private: + HConfig *m_main_config = new HConfig("config"); + QVector m_configs; +}; + + +class HekateIni +{ +public: + HekateIni(QByteArray hekate_ini); + + HConfigs* configs() { return &m_configs; } + HConfig* config(const QString &cfg) { return m_configs.getConfig(cfg); } + QByteArray data() { return m_hekate_ini; } + + bool setConfigsIds(); + bool rewriteIniData(); + +private: + QByteArray m_hekate_ini; + HConfigs m_configs; + + bool parseIni(HConfigs *configs = nullptr); + +}; + + +#endif // HEKATEINI_H diff --git a/qpayload.cpp b/qpayload.cpp index e4b210c..f0be6f2 100644 --- a/qpayload.cpp +++ b/qpayload.cpp @@ -1,12 +1,9 @@ + #include #include "qpayload.h" #include "ui_qpayload.h" #include "qutils.h" - -///////////////////////////////////////////////////////////// -/// \brief QPayloadWidget::QPayloadWidget -/// \param parent -///////////////////////////////////////////////////////////// +#include "qobjects/custombutton.h" QPayloadWidget::QPayloadWidget(TegraRcmGUI *parent) : QWidget(parent) , ui(new Ui::QPayloadWidget), parent(parent) @@ -38,52 +35,38 @@ QPayloadWidget::QPayloadWidget(TegraRcmGUI *parent) : QWidget(parent) item.at(i)->setStatusTip("test"); } - - // Timers - QTimer *payloadBtnStatus_timer = new QTimer(this); - connect(payloadBtnStatus_timer, SIGNAL(timeout()), this, SLOT(payloadBtnStatusTimer())); - payloadBtnStatus_timer->start(1000); // Every second - - - - /// Stylesheets - // Apply stylesheet to all buttons - QString btnSs = GetStyleSheetFromResFile(":/res/QPushButton.qss"); - auto buttons = this->findChildren(); - for (int i = 0; i < buttons.count(); i++) - { - buttons.at(i)->setStyleSheet(btnSs); - buttons.at(i)->setCursor(Qt::PointingHandCursor); - - } + // Stylesheets this->setStyleSheet(GetStyleSheetFromResFile(":/res/QMainWindow.qss")); ui->payload_tableView->setStyleSheet(GetStyleSheetFromResFile(":/res/QTableView.qss")); ui->payloadFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); + ui->payloadPathLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title02.qss")); + ui->favoritesLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title02.qss")); // Buttons Switch *_switch = new Switch(parent->userSettings->value("autoInject").toBool() ? true : false, 50); ui->horizontalLayout->addWidget(_switch); connect(_switch, SIGNAL(clicked()), this, SLOT(on_autoInject_toggled())); - //ui->injectPayloadBtn->setCursor(Qt::PointingHandCursor); - //ui->browsePayloadBtn->setCursor(Qt::PointingHandCursor); - // ToolTip + auto *browseB = new CustomButton(parent, tr("Browse"), LIGHT); + browseB->setStatusTip(tr("Browse payload file from local file systems")); + browseB->setFixedSize(60, 20); + connect(browseB, &QPushButton::clicked, this, &QPayloadWidget::on_browsePayloadBtn_clicked); + ui->browsePayloadLayout->addWidget(browseB); + + auto *injectB = new CustomButton(parent, tr("INJECT PAYLOAD")); + injectB->setStatusTip(tr("Inject current payload to device")); + injectB->addEnableCondition(C_READY_FOR_PAYLOAD); + injectB->setFixedSize(100, 30); + connect(injectB, &QPushButton::clicked, this, &QPayloadWidget::on_injectPayloadBtn_clicked); + ui->injectPayloadLayout->addWidget(injectB); + + // Tool tips ui->addFavoriteBtn->setStatusTip(tr("Add current payload selection to favorites")); ui->deleteFavoriteBtn->setStatusTip(tr("Remove selected item from favorites (payload file will not be deleted)")); - QString ppath = parent->userSettings->value("autoInjectPath").toString(); - ui->payload_path->setText(ppath); + ui->payload_path->setText(parent->userSettings->value("autoInjectPath").toString()); +} -} -void QPayloadWidget::payloadBtnStatusTimer() -{ - qint64 time = QDateTime::currentSecsSinceEpoch(); - if (payloadBtnStatusLbl_time && (time + 5 > payloadBtnStatusLbl_time)) - { - ui->payloadBtnStatusLbl->setText(""); - payloadBtnStatusLbl_time = 0; - } -} void QPayloadWidget::on_browsePayloadBtn_clicked() { QString path = FileDialog(this, open_file).toLocal8Bit(); @@ -91,21 +74,18 @@ void QPayloadWidget::on_browsePayloadBtn_clicked() ui->payload_path->setText(path); } +void QPayloadWidget::on_injectPayload(QString payload_path) +{ + ui->payload_path->setText(payload_path); + on_injectPayloadBtn_clicked(); +} + void QPayloadWidget::on_injectPayloadBtn_clicked() { - if (!m_device->rcmIsReady() && !m_device->arianeIsReady()) - return; - - if (payloadBtnLock) - { - ui->payloadBtnStatusLbl->setText(tr("Work in progress")); - payloadBtnStatusLbl_time = QDateTime::currentSecsSinceEpoch(); - return; - } - QFile file(ui->payload_path->text().toLocal8Bit().constData()); if (!file.open(QIODevice::ReadOnly)) return parent->error(0x005); + if (file.size() > PAYLOAD_MAX_SIZE) { file.close(); @@ -113,9 +93,7 @@ void QPayloadWidget::on_injectPayloadBtn_clicked() } file.close(); - tmp_string.clear(); - tmp_string.append(ui->payload_path->text().toStdString()); - payloadBtnLock = true; + tmp_string = ui->payload_path->text().toStdString(); QtConcurrent::run(m_kourou, &QKourou::hack, tmp_string.c_str()); } @@ -123,21 +101,11 @@ void QPayloadWidget::on_deviceStateChange() { if ((m_device->rcmIsReady() && !m_kourou->autoLaunchAriane) || m_device->arianeIsReady()) { - payloadBtnLock = false; - ui->injectPayloadBtn->setCursor(Qt::PointingHandCursor); - ui->injectPayloadBtn->setStatusTip("Inject current payload to device"); if (m_payloadModel->rowCount()) ui->payload_tableView->setStatusTip(tr("Double-click to inject payload")); } else { - payloadBtnLock = true; - QString tip = m_device->getStatus() == CONNECTED ? tr("RCM device is not ready. Reboot to RCM") : tr("RCM device undetected!"); - if (m_kourou->arianeIsLoading) - tip = tr("Wait for Ariane to be fully loaded"); - //ui->injectPayloadBtn->setToolTip(tip); - ui->injectPayloadBtn->setStatusTip(tip); - ui->injectPayloadBtn->setCursor(Qt::ForbiddenCursor); if (m_payloadModel->rowCount()) ui->payload_tableView->setStatusTip(tr("Double-click to push favorite into current selection")); } @@ -145,19 +113,23 @@ void QPayloadWidget::on_deviceStateChange() bool QPayloadWidget::addFavorite(QString name, QString path) { - QFile file(path); + if (m_payloadModel->getPayloads().contains({ path, name })) + return true; // Already in favorites, return true + + QFile file(path); if (!file.exists()) return false; if (!m_payloadModel->getPayloads().contains({ name, path })) { m_payloadModel->insertRows(0, 1, QModelIndex()); - QModelIndex index = m_payloadModel->index(0, 0, QModelIndex()); + auto index = m_payloadModel->index(0, 0, QModelIndex()); m_payloadModel->setData(index, name, Qt::EditRole); index = m_payloadModel->index(0, 1, QModelIndex()); m_payloadModel->setData(index, path, Qt::EditRole); - return true; + + return writeFavoritesToFile(); } return false; } @@ -186,8 +158,6 @@ void QPayloadWidget::on_addFavoriteBtn_clicked() return; } - if(addFavorite(name, path)) - writeFavoritesToFile(); } void QPayloadWidget::on_deleteFavoriteBtn_clicked() @@ -237,10 +207,9 @@ bool QPayloadWidget::readFavoritesFromFile() pFile.close(); QJsonDocument loadDoc(QJsonDocument::fromJson(pData)); - QJsonObject json = loadDoc.object(); - QJsonArray pArray = json["favorites"].toArray(); + int i(0); for (i = 0; i < pArray.size(); i++) { @@ -262,8 +231,8 @@ bool QPayloadWidget::writeFavoritesToFile() return false; QJsonArray pArray; - QVector payloads = m_payloadModel->getPayloads(); - for (payload_t paylaod : payloads) + auto payloads = m_payloadModel->getPayloads(); + for (auto paylaod : payloads) { QJsonObject payloadEntry; payloadEntry["name"] = paylaod.name; @@ -272,11 +241,8 @@ bool QPayloadWidget::writeFavoritesToFile() } QJsonObject json; json["favorites"] = pArray; - QJsonDocument saveDoc(json); - pFile.write(saveDoc.toJson()); - + pFile.write(QJsonDocument(json).toJson()); pFile.close(); - return true; } @@ -361,7 +327,6 @@ bool PayloadModel::setData(const QModelIndex &index, const QVariant &value, int return true; } - return false; } @@ -381,7 +346,7 @@ const QVector &PayloadModel::getPayloads() const void QPayloadWidget::on_payload_tableView_doubleClicked(const QModelIndex &index) { - QString path = m_payloadModel->getPayloads().at(index.row()).path; - ui->payload_path->setText(path); - on_injectPayloadBtn_clicked(); + ui->payload_path->setText(m_payloadModel->getPayloads().at(index.row()).path); + if (m_device->isReadyToReceivePayload()) + on_injectPayloadBtn_clicked(); } diff --git a/qpayload.h b/qpayload.h index 8776892..5ba225a 100644 --- a/qpayload.h +++ b/qpayload.h @@ -63,6 +63,8 @@ public: std::string tmp_string; const QVector &getPayloads() const { return m_payloadModel->getPayloads(); } + bool addFavorite(QString name, QString path); + private: Ui::QPayloadWidget *ui; PayloadModel *m_payloadModel; @@ -70,10 +72,8 @@ private: TegraRcmGUI *parent; QKourou *m_kourou; Kourou *m_device; - qint64 payloadBtnStatusLbl_time = 0; - bool payloadBtnLock = false; - bool addFavorite(QString name, QString path); + bool readFavoritesFromFile(); bool writeFavoritesToFile(); @@ -81,6 +81,7 @@ signals: public slots: void on_deviceStateChange(); + void on_injectPayload(QString payload_path); private slots: void on_browsePayloadBtn_clicked(); @@ -88,8 +89,6 @@ private slots: void on_addFavoriteBtn_clicked(); void on_deleteFavoriteBtn_clicked(); void on_autoInject_toggled(); - void payloadBtnStatusTimer(); - void on_payload_path_textChanged(const QString &arg1); void on_payload_tableView_doubleClicked(const QModelIndex &index); diff --git a/qpayload.ui b/qpayload.ui index f4b2e55..05edc73 100644 --- a/qpayload.ui +++ b/qpayload.ui @@ -60,8 +60,7 @@ - - + QFrame::StyledPanel @@ -69,22 +68,6 @@ QFrame::Raised - - - - 340 - 10 - 71 - 20 - - - - - - - Browse - - @@ -94,10 +77,6 @@ 20 - - font: 10pt "Calibri"; -color: rgb(255, 255, 255); - Path: @@ -114,10 +93,6 @@ color: rgb(255, 255, 255); 16 - - font: 10pt "Calibri"; -color: rgb(255, 255, 255); - Auto inject: @@ -136,22 +111,6 @@ color: rgb(255, 255, 255); - - - - 10 - 40 - 101 - 30 - - - - - - - INJECT PAYLOAD - - @@ -171,24 +130,27 @@ color: rgb(255, 255, 255); Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + - 120 - 45 - 131 + 10 + 40 + 111 + 31 + + + + + + + + 340 + 10 + 71 21 - - font: 10pt "Calibri"; - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + @@ -201,8 +163,7 @@ color: rgb(255, 255, 255); - font: 11pt "Calibri"; - + Payload selection: @@ -261,8 +222,7 @@ color: rgb(255, 255, 255); - font: 11pt "Calibri"; - + Favorites: diff --git a/qprogress_widget.cpp b/qprogress_widget.cpp new file mode 100644 index 0000000..1cfcb6f --- /dev/null +++ b/qprogress_widget.cpp @@ -0,0 +1,77 @@ +#include "qprogress_widget.h" +#include "ui_qprogress_widget.h" +#include "qutils.h" +#include + +qProgressWidget::qProgressWidget(const QString init_message, QWidget *parent) : + QDialog(parent), + ui(new Ui::qProgressWidget) +{ + ui->setupUi(this); + + this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + this->setAttribute(Qt::WA_TranslucentBackground); + this->setStyleSheet(GetStyleSheetFromResFile(":/res/ProgressWidget.qss")); + + QMovie *movie = new QMovie(":/res/loader_bg646464.gif"); + ui->loadingLbl->setMovie(movie); + ui->loadingLbl->show(); + movie->start(); + + if (init_message.size()) + setLabel(init_message); + + m_latest_activity = QDateTime::currentSecsSinceEpoch(); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(checkActivity())); + timer->start(1000); // Every second +} + +void qProgressWidget::init_ProgressWidget(const QString init_message, int timeout_s) +{ + if (timeout_s) + setTimeOut(timeout_s); + + if (init_message.size()) + setLabel(init_message); + else + { + setLastActivity(); + show(); + } +} + +qProgressWidget::~qProgressWidget() +{ + delete ui; +} + +void qProgressWidget::checkActivity() +{ + if (!isVisible()) + return; + + qint64 now = QDateTime::currentSecsSinceEpoch(); + if (now > m_latest_activity + m_timeout_s) + hide(); +} + +void qProgressWidget::setLastActivity() +{ + m_latest_activity = QDateTime::currentSecsSinceEpoch(); +} + +void qProgressWidget::setLabel(const QString label) +{ + QString s_label = label.size() > 40 ? "..." + label.mid(label.size() - 37, 37) : label; + ui->label->setText(s_label); + setLastActivity(); + if (!isVisible()) + show(); +} + +void qProgressWidget::closeEvent(QCloseEvent *e) +{ + hide(); + QDialog::closeEvent(e); +} diff --git a/qprogress_widget.h b/qprogress_widget.h new file mode 100644 index 0000000..c309e17 --- /dev/null +++ b/qprogress_widget.h @@ -0,0 +1,39 @@ +#ifndef QPROGRESS_WIDGET_H +#define QPROGRESS_WIDGET_H + +#include + +namespace Ui { +class qProgressWidget; +} + +class qProgressWidget : public QDialog +{ + Q_OBJECT + +public: + explicit qProgressWidget(const QString init_message = "", QWidget *parent = nullptr); + ~qProgressWidget(); + +public: + void setTimeOut(unsigned int seconds) { if (seconds) m_timeout_s = seconds; } + +public slots: + void init_ProgressWidget(const QString init_message = "", int timeout_s = 0); + void setLabel(const QString label); + void setLastActivity(); + void closeEvent(QCloseEvent *e) override; + +private: + Ui::qProgressWidget *ui; + qint64 m_latest_activity; + unsigned int m_timeout_s = 5; + +private slots: + void checkActivity(); + + + +}; + +#endif // QPROGRESS_WIDGET_H diff --git a/qprogress_widget.ui b/qprogress_widget.ui new file mode 100644 index 0000000..d16ea18 --- /dev/null +++ b/qprogress_widget.ui @@ -0,0 +1,85 @@ + + + qProgressWidget + + + Qt::ApplicationModal + + + + 0 + 0 + 301 + 82 + + + + + + + border-radius: 10px; + + + + + 0 + 0 + 301 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 6 + 55 + 291 + 20 + + + + + 0 + 0 + + + + Work in progress + + + true + + + Qt::AlignCenter + + + true + + + 0 + + + + + + 125 + 3 + 54 + 55 + + + + + + + + + + + diff --git a/qresources.qrc b/qresources.qrc index d6408f3..1fe679d 100644 --- a/qresources.qrc +++ b/qresources.qrc @@ -15,5 +15,12 @@ res/add.ico res/QLabel_warning.qss res/QLabel_title02.qss + res/ProgressWidget.qss + res/loader_bg646464.gif + res/Badge_label.qss + res/Badge_value.qss + res/QPushButton_light.qss + res/QTableWidget.qss + res/packages.json diff --git a/qsettings.cpp b/qsettings.cpp index 368cf6e..2d049b4 100644 --- a/qsettings.cpp +++ b/qsettings.cpp @@ -12,13 +12,24 @@ qSettings::qSettings(TegraRcmGUI *parent) : QWidget(parent), /// Stylesheets // Apply stylesheet to all buttons - QString btnSs = GetStyleSheetFromResFile(":/res/QPushButton.qss"); + auto btnSs = GetStyleSheetFromResFile(":/res/QPushButton.qss"); auto buttons = this->findChildren(); for (int i = 0; i < buttons.count(); i++) { buttons.at(i)->setStyleSheet(btnSs); buttons.at(i)->setCursor(Qt::PointingHandCursor); } + + for (auto it : {ui->minTrayFrame, ui->driverFrame, ui->PkgmFrame}) + it->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); + + for (auto it : { ui->minTrayLbl, ui->driverLbl, ui->PkgmLbl}) + it->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title02.qss")); + + // Switch + minTraySwitch = new Switch(parent->userSettings->contains("minToTray") && parent->userSettings->value("minToTray").toBool() ? true : false, 50); + ui->minTrayLayout->addWidget(minTraySwitch); + connect(minTraySwitch, SIGNAL(clicked()), this, SLOT(on_minToTraySwitch_toggled())); } qSettings::~qSettings() @@ -41,7 +52,10 @@ void qSettings::on_installDriverButton_clicked() QFile file(q_path); if (!file.exists()) + { + QMessageBox::critical(this, "Error", tr("InstallDriver.exe not found!\nExpected location: ") + q_path); return; + } std::wstring w_path = q_path.toStdWString(); LPCWSTR path = (const wchar_t*) w_path.c_str(); @@ -60,3 +74,16 @@ void qSettings::on_installDriverButton_clicked() CloseHandle(shExInfo.hProcess); } } + +void qSettings::on_minToTraySwitch_toggled() +{ + parent->userSettings->setValue("minToTray", minTraySwitch->getState()); +} + +void qSettings::on_packagesButton_clicked() +{ + auto dialog = new PackageManager(&parent->m_pkgs, parent); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->exec(); + //delete dialog; +} diff --git a/qsettings.h b/qsettings.h index 6978464..abfd318 100644 --- a/qsettings.h +++ b/qsettings.h @@ -3,10 +3,12 @@ #include #include "tegrarcmgui.h" +#include "qutils.h" class TegraRcmGUI; class Kourou; class QKourou; +class Switch; QT_BEGIN_NAMESPACE namespace Ui { @@ -24,14 +26,19 @@ public: public slots: void on_driverMissing(); + private slots: void on_installDriverButton_clicked(); + void on_minToTraySwitch_toggled(); + + void on_packagesButton_clicked(); private: Ui::qSettings *ui; TegraRcmGUI *parent; QKourou *m_kourou; Kourou *m_device; + Switch *minTraySwitch; }; diff --git a/qsettings.ui b/qsettings.ui index 8a11e8d..50864b5 100644 --- a/qsettings.ui +++ b/qsettings.ui @@ -6,25 +6,214 @@ 0 0 - 400 + 491 300 Form - + - 10 - 10 - 80 - 22 + 20 + 20 + 211 + 121 - - Install driver + + QFrame::StyledPanel + + QFrame::Raised + + + + + 10 + 10 + 191 + 16 + + + + Minimize to tray + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 150 + 80 + 51 + 31 + + + + + + + + 10 + 30 + 191 + 51 + + + + font: 7.5pt "Rubik"; +color: rgb(168, 168, 168); + + + When enabled the application will be minimized to system tray instead of taskBar. Use tray's icon context menu to show or control application + + + Qt::AlignJustify|Qt::AlignTop + + + true + + + + + + + 240 + 20 + 211 + 121 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 191 + 16 + + + + Driver + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 10 + 30 + 191 + 51 + + + + font: 7.5pt "Rubik"; +color: rgb(168, 168, 168); + + + LibusbK driver is required to communicate with the Nintendo Switch (RCM). + + + Qt::AlignJustify|Qt::AlignTop + + + true + + + + + + 120 + 80 + 80 + 31 + + + + Install driver + + + + + + + 20 + 150 + 211 + 121 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 191 + 16 + + + + Packages Manager + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 10 + 30 + 191 + 51 + + + + font: 7.5pt "Rubik"; +color: rgb(168, 168, 168); + + + Update & manage your packages (Hekate, AMS, payloads, tools, ...) + + + Qt::AlignJustify|Qt::AlignTop + + + true + + + + + + 120 + 80 + 80 + 31 + + + + Packages + + diff --git a/qtools.cpp b/qtools.cpp index a0d0f4c..8c08c25 100644 --- a/qtools.cpp +++ b/qtools.cpp @@ -20,18 +20,14 @@ qTools::qTools(TegraRcmGUI *parent) : QWidget(parent), } ui->autoRcmFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); - ui->genricToolFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box02.qss")); ui->autoRcm_warningFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_warning.qss")); - ui->autoRcmTitleLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title02.qss")); + ui->autoRcmTitleLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title02.qss")); // Buttons autoRCM_switch = new Switch(false, 50); ui->autoRcmLayout->addWidget(autoRCM_switch); connect(autoRCM_switch, SIGNAL(clicked()), this, SLOT(on_autoRcmSwitchToggled())); - Switch *_switch2 = new Switch(false, 50); - ui->genricToolLayout->addWidget(_switch2); - //connect(_switch, SIGNAL(clicked()), this, SLOT(on_autoInject_toggled())); } qTools::~qTools() @@ -43,7 +39,7 @@ void qTools::on_deviceStateChange() { //autoRcm_arianeLbl - if (!m_device->arianeIsReady() || !parent->isDeviceInfoAvailable()) + if (!m_device->arianeIsReady() || !m_device->isDeviceInfoAvailable()) { QString label; if (m_device->arianeIsReady()) diff --git a/qtools.ui b/qtools.ui index ba58725..4dd7a15 100644 --- a/qtools.ui +++ b/qtools.ui @@ -60,21 +60,23 @@ 10 30 - 201 + 191 51 - font: italic 9pt "Calibri"; + font: 7.5pt "Rubik"; +color: rgb(168, 168, 168); - autoRCM is a controlled brick of BOOT0 -partition. Enabling autoRCM will force -your Switch to boot straight to RCM + Controlled brick of BOOT0 partition. Enabling autoRCM will force your Switch to boot straight to RCM. Qt::AlignJustify|Qt::AlignTop + + true + @@ -115,84 +117,6 @@ your Switch to boot straight to RCM - - - - 240 - 20 - 211 - 121 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 150 - 80 - 51 - 31 - - - - - - - - 10 - 10 - 241 - 16 - - - - font: 75 11pt "Calibri"; - - - Another Tool: - - - - - - 10 - 30 - 201 - 51 - - - - font: italic 9pt "Calibri"; - - - blabababla - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - 6 - 79 - 141 - 31 - - - - Tool state: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - diff --git a/qutils.cpp b/qutils.cpp index d7d3d94..3b76788 100644 --- a/qutils.cpp +++ b/qutils.cpp @@ -1,5 +1,62 @@ #include "qutils.h" +QString GetAppVersionAsQString(AppVersion version) +{ + QString s_ver = QString::number(version.major); + s_ver.append("."); + s_ver.append(QString::number(version.minor)); + s_ver.append("."); + s_ver.append(QString::number(version.micro)); + return s_ver; +} + +Badge::Badge(QString label, QString value, QWidget* parent) +{ + m_hbl = new QHBoxLayout(this); + m_hbl->setMargin(0); + m_hbl->setSpacing(0); + + m_hbl->setAlignment(Qt::AlignLeft); + m_l_label = new QLabel(label, this); + m_l_label->setFixedHeight(22); + m_l_label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + m_l_label->setAlignment(Qt::AlignVCenter | Qt::AlignRight); + m_l_label->setStyleSheet(GetStyleSheetFromResFile(":/res/Badge_label.qss")); + + m_v_label = new QLabel(value, this); + m_v_label->setFixedHeight(22); + m_v_label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + m_v_label->setAlignment(Qt::AlignCenter); + m_v_label->setStyleSheet(GetStyleSheetFromResFile(":/res/Badge_value.qss")); + + m_hbl->addWidget(m_l_label); + m_hbl->addWidget(m_v_label); +} + +Badge::~Badge() +{ + delete m_hbl; + delete m_l_label; + delete m_v_label; +} + +WarningBox::WarningBox(QString message, QLayout *layout) +{ + // Clear all items in layout + ClearLayout(layout); + + layout->setAlignment(Qt::AlignLeft | Qt::AlignTop); + m_label = new QLabel(message, this); + m_label->setAlignment(Qt::AlignCenter); + m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_label->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_warning.qss")); + layout->addWidget(m_label); +} + +WarningBox::~WarningBox() +{ + delete m_label; +} QString FileDialog(QWidget *parent, fdMode mode, const QString& defaultName) { @@ -152,6 +209,21 @@ void MoveWindowWidget::mouseMoveEvent(QMouseEvent *event) QPoint delta = event->pos() - startPos; QWidget * w = window(); if(w) + { w->move(w->pos() + delta); + w->adjustSize(); + } QWidget::mouseMoveEvent(event); } + +void ClearLayout(QLayout *layout) +{ + QLayoutItem* item; + while ((item = layout->takeAt(0)) != nullptr) + { + delete item->widget(); + delete item; + } +} + + diff --git a/qutils.h b/qutils.h index 0e41e5a..e30600c 100644 --- a/qutils.h +++ b/qutils.h @@ -7,7 +7,45 @@ #include #include #include +#include "qerror.h" +//class TegraRcmGUI; + +template +bool is_in(const T& v, std::initializer_list lst) +{ + return std::find(std::begin(lst), std::end(lst), v) != std::end(lst); +} + +typedef struct _Cpy { + QString source; + QString destination; + _Cpy(const QString src, const QString dst) : source(src), destination(dst) {} +} Cpy; +typedef QList Cpys; + +struct AppVersion { + int major = 0; + int minor = 0; + int micro = 0; + + bool operator==(const AppVersion &other) const + { + return other.major == major && other.minor == minor && other.micro == micro; + } + + bool operator<(const AppVersion &other) const + { + if (other.major != major) + return other.major > major; + else if (other.minor != minor) + return other.minor > minor; + else + return other.micro > micro; + } +}; + +QString GetAppVersionAsQString(AppVersion version); enum fdMode { open_file, save_as }; @@ -15,6 +53,30 @@ QString FileDialog(QWidget *parent, fdMode mode, const QString& defaultName = "" QString GetReadableSize(qint64 bytes); QString GetStyleSheetFromResFile(QString qss_file); +class Badge : public QWidget { + Q_OBJECT + +public: + Badge(QString label, QString value, QWidget* parent = nullptr); + ~Badge(); + +private: + QHBoxLayout *m_hbl; + QLabel *m_l_label; + QLabel *m_v_label; +}; + +class WarningBox : public QWidget { + Q_OBJECT + +public: + WarningBox(QString message, QLayout *layout); + ~WarningBox(); + +private: + QLabel *m_label; +}; + class Switch : public QAbstractButton { Q_OBJECT Q_PROPERTY(int offset READ offset WRITE setOffset) @@ -59,7 +121,6 @@ private: QPropertyAnimation *_anim = nullptr; }; - class AnimatedLabel : public QLabel { @@ -84,8 +145,6 @@ public: } }; - - class MoveWindowWidget : public QWidget { Q_OBJECT @@ -99,4 +158,6 @@ private: QPoint startPos; }; +void ClearLayout(QLayout *layout); + #endif // QUTILS_H diff --git a/res/Badge_label.qss b/res/Badge_label.qss new file mode 100644 index 0000000..2b9bf16 --- /dev/null +++ b/res/Badge_label.qss @@ -0,0 +1,11 @@ +QLabel +{ + font: 75 8pt "Rubik"; + padding: 5px; + color: rgb(255, 255, 255); + background-color: rgb(41, 41, 41); + border-top-left-radius: 10px; + border-top-right-radius: 0px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 0px; +} diff --git a/res/Badge_value.qss b/res/Badge_value.qss new file mode 100644 index 0000000..e9ab32f --- /dev/null +++ b/res/Badge_value.qss @@ -0,0 +1,11 @@ +QLabel +{ + font: 75 8pt "Rubik"; + padding: 5px; + color: rgb(0, 0, 0); + background-color: rgb(213, 213, 213); + border-top-left-radius: 0px; + border-top-right-radius: 10px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 10px; +} diff --git a/res/ProgressWidget.qss b/res/ProgressWidget.qss new file mode 100644 index 0000000..eb49072 --- /dev/null +++ b/res/ProgressWidget.qss @@ -0,0 +1,18 @@ +QDialog +{ + background-color: transparent; + color: rgb(255, 255, 255); +} + +QFrame +{ + background-color: rgb(100, 100, 100); + border-radius: 10px; + border-color: rgb(0, 0, 0); +} + +QLabel +{ + font: 8pt "Rubik"; + color: rgb(255, 255, 255); +} diff --git a/res/QFrame_box01.qss b/res/QFrame_box01.qss index f1aec7a..31fee99 100644 --- a/res/QFrame_box01.qss +++ b/res/QFrame_box01.qss @@ -1,12 +1,12 @@ QFrame { - background-color: rgb(60, 60, 60); - border-radius: 10px; - border-color: rgb(0, 0, 0); + background-color: rgb(60, 60, 60); + border-radius: 10px; + border-color: rgb(0, 0, 0); } QLabel -{ +{ border-radius: 0px; - font: 10pt "Calibri"; - color: rgb(255, 255, 255); + font: 8pt "Rubik"; + color: rgb(255, 255, 255); } diff --git a/res/QFrame_box02.qss b/res/QFrame_box02.qss index ca71113..d08583b 100644 --- a/res/QFrame_box02.qss +++ b/res/QFrame_box02.qss @@ -8,7 +8,7 @@ QFrame QLabel { border-radius: 0px; - font: 10pt "Calibri"; + font: 8pt "Rubik"; background-color: rgb(41, 41, 41); color: rgb(255, 255, 255); } @@ -16,7 +16,7 @@ QLineEdit { border-color: rgb(0, 0, 0); background-color: rgb(60, 60, 60); - font: 9pt "Calibri"; + font: 8pt "Rubik"; border-radius: 2px; color: rgb(255, 255, 255); } diff --git a/res/QLabel_title01.qss b/res/QLabel_title01.qss index b492dad..7598e9d 100644 --- a/res/QLabel_title01.qss +++ b/res/QLabel_title01.qss @@ -6,7 +6,7 @@ QFrame } QLabel { - font: 75 9pt "Calibri"; + font: 75 8pt "Rubik"; color: rgb(255, 255, 255); border-radius: 10px; background-color: rgb(0, 150, 136); diff --git a/res/QLabel_warning.qss b/res/QLabel_warning.qss index a9600c1..be64263 100644 --- a/res/QLabel_warning.qss +++ b/res/QLabel_warning.qss @@ -6,6 +6,6 @@ QFrame QLabel { - font: 75 9pt "Calibri"; + font: 8pt "Rubik"; color: rgb(150, 35, 0); } diff --git a/res/QMainWindow.qss b/res/QMainWindow.qss index 7f084b6..1c33acd 100644 --- a/res/QMainWindow.qss +++ b/res/QMainWindow.qss @@ -4,14 +4,25 @@ QMainWindow border-radius: 10px; color: rgb(255, 255, 255); } + +QDialog +{ + background-color: rgb(30, 30, 30); + border-radius: 10px; + color: rgb(255, 255, 255); +} + QStatusBar { color: rgb(255, 255, 255); } + QToolTip { - background-color: rgb(30, 30, 30); - color: rgb(255, 255, 255); + color: #fff; + background-color: #000; + border: none; + font: 75 8pt "Rubik"; } QMessageBox QLabel { @@ -21,3 +32,68 @@ QLabel { color: rgb(255, 255, 255); } +QScrollBar:vertical +{ + border: none; + background: rgb(60, 60, 60); + width:10px; + margin: 0px 0px 0px 0px; +} +QScrollBar::handle:vertical +{ + border: none; + background: rgb(51, 51, 51); + min-height: 5px; + border-radius: 8px; +} +QScrollBar::add-line:vertical +{ + border: none; + background: rgb(60, 60, 60); + height: 5px; + subcontrol-position: bottom; + subcontrol-origin: margin; + } + +QScrollBar::sub-line:vertical +{ + border: none; + background: rgb(60, 60, 60); + height: 5px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QPushButton +{ + background-color: rgb(0, 150, 136); + color: rgb(255, 255, 255); + border-radius: 10px; + font: 75 8pt "Rubik"; + padding : 5px; +} +QPushButton:pressed +{ + color: rgb(0, 0, 0); + background-color: rgb(255, 255, 255); +} +QPushButton:hover +{ + color: rgb(255, 255, 255); + background-color: rgb(150, 35, 0); +} +QFrame +{ + background-color: rgb(60, 60, 60); + border-radius: 10px; + border-color: rgb(0, 0, 0); +} +QMessageBox +{ + background-color: rgb(60, 60, 60); + color: rgb(255, 255, 255); +} +QMessageBox QLabel +{ + color: rgb(255, 255, 255); +} diff --git a/res/QPushButton.qss b/res/QPushButton.qss index 7acba29..3b59efd 100644 --- a/res/QPushButton.qss +++ b/res/QPushButton.qss @@ -3,6 +3,7 @@ QPushButton background-color: rgb(0, 150, 136); color: rgb(255, 255, 255); border-radius: 10px; + font: 75 8pt "Rubik"; } QPushButton:pressed { diff --git a/res/QPushButton_light.qss b/res/QPushButton_light.qss new file mode 100644 index 0000000..fd39929 --- /dev/null +++ b/res/QPushButton_light.qss @@ -0,0 +1,20 @@ +QPushButton +{ + background-color: rgba(255, 255, 255, 0); + color: rgb(160, 160, 160); + border-radius: 10px; + border: 1px solid rgb(160, 160, 160); + font: 75 8pt "Rubik"; +} +QPushButton:pressed +{ + color: rgb(160, 160, 160); + background-color: rgba(255, 255, 255, 0); +} +QPushButton:hover +{ + color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 25); + border: 1px solid rgb(255, 255, 255); +} + diff --git a/res/QTabWidget.qss b/res/QTabWidget.qss index fafac29..64d8fe2 100644 --- a/res/QTabWidget.qss +++ b/res/QTabWidget.qss @@ -10,9 +10,8 @@ QTabWidget::tab-bar QTabBar::tab { color: rgb(255, 255, 255); - border: 0px; - min-width: 10ex; + min-width: 6em; padding: 6px; /* Padding inside each tab */ font: 75 10pt "MS Shell Dlg 2"; color: rgb(255, 255, 255); @@ -24,6 +23,7 @@ QTabBar::tab:selected { QLabel { color: rgb(255, 255, 255); + font: 9pt "Rubik"; } QToolTip { diff --git a/res/QTableView.qss b/res/QTableView.qss index 6b25d32..4cf357f 100644 --- a/res/QTableView.qss +++ b/res/QTableView.qss @@ -5,4 +5,12 @@ QTableView alternate-background-color: rgb(80, 80, 80); background: rgb(41, 41, 41); selection-background-color: rgb(30, 105, 98); + font: 8pt "Rubik"; +} + +QHeaderView::section { + border-radius: 0px; + background: rgb(60, 60, 60); + font: 8pt "Rubik"; + color: rgb(255, 255, 255); } diff --git a/res/QTableWidget.qss b/res/QTableWidget.qss new file mode 100644 index 0000000..755bff4 --- /dev/null +++ b/res/QTableWidget.qss @@ -0,0 +1,21 @@ +QTableView +{ + gridline-color : rgb(120, 120, 120); + color: rgb(255, 255, 255); + alternate-background-color: rgb(255, 255, 255, 30); + background: rgb(255, 255, 255); + selection-background-color: rgb(30, 105, 98); + font: 8pt "Rubik"; +} + +QTableWidgetItem +{ + border: 0px; + height: 15px; +} + +QFrame +{ + background-color: rgb(255, 255, 255, 0); + border-radius: 0px; +} diff --git a/res/loader_bg000000.gif b/res/loader_bg000000.gif new file mode 100644 index 0000000000000000000000000000000000000000..be6865fca7a07554c30b3a9de5b47dca038fc009 GIT binary patch literal 1924 zcmcK5Sx{3~00!U)H>-dOk_1Le7Lq^(r9z?%!2k(cD=vVAK?Oq5KtK?LYCsl|C2YaO zEMN>^WDi6M5TT%DNsuL=Xb}aJVi6ha47Ij1?MrP)OUu;hIMa^j;XK?qbI<+$f9^TH z{yuwMnH10-&>PU|h>nhSad8O^4Gj+uH#0Ny^71k@HANzkzP`SWj*f;Ue^1!otm(-o zm?`Y_mAfqU4{jGeYSJCnXwC~G4<3wdHu#1 zA(0*9pLIZo<{SCcwK;Ayp7uyT3~ogBMPks$Qz4hL9}$rO^G`g4nqu!nmn6a&=Tr=o z<6sOWvEyx_iICDmVo7<$73o!3<+ic{@ipr_2f1$@(6F@#NEa(_qEwO&bW^i?S8d!^ z^qQ*v0gZO>?vS*PcgMCTIR$@<@DMZkAPaXdcLG0}JT_c8r=8JG4J`F9zL`n@qYqinvf7rbY2+p;w!UO2emqGNglolZ9dJ#gs&9*w2iIqo6qs zP2kjo$@870DVsaQr?`8%-qFhWyK{pxnq~RY;Nrq-(i+j|Jw#=*lZnw$1S3GB+WS~@ z=@oTu6QgZD-v(t;u>;M{H}dD$T7Id%;1b+?#QWe!eIVTxjXF8N&ufbDRBEro4@5*v zZ0O$S97QVk4)m&^Ag~w^X@chBC;;tp%Fk; z(d02Tt>-GFGJ!BkEU+jo>+W6caM+^UPIsDG&A5+mCQY*IiBrcO5>@!|XPqP5d99wP zUG6myiEBjT^~AAvTl{z8u#0`!I7&DqEh-|%u~-)3PVz3;tQ%iDybMpry9ce*oj-76 zX62WjrpN{>gmn@P%*sZ^huLRP0SKB!FQJrq@&y2zOE0GKDgynWENGeqv=~xTt7vXf zk_<64BLoP14jv`}I)Z%&DhV8W$@UKUu4s4!d&O2G7`$IixGm}B+$!nv>$Yrdo1sl8 zhL*+@FTbC<@xzWaA+TOJ`XPkWeY}N;$6+65Te1A|&;_(Y6p%N&+N$)qJA)42e=n2ju>&{!xDS>lP}arv(C zVFhJH@<6K#Ik|cHybPtPt-a%qa@)YHp2MHvx^f@~E@MQ*a_mTi46C6IIuF_CL2-?E zs0K2v-d>`*-mX(EDHq!pp0E6M%s~GWFq6x0yl}rWlAfIt62x$YHMO{=Z>N3gi2dZd z47aGGu`G+s2OX(STOSGhwbNG8#pk#2LBXGggfjQ%6&4kjl!h2O;32{BWMd)yV7diA z7;^O_I+kAUUK>?^231X!(>Qz3&<11ZVVO0w8qy`|`{SzE-fcI6YpZ0`c$^~L!cP*X iu;Zi|ypA|GR5;)NRP$tD>BWRr4xvk!ThVeT+vlZ(A literal 0 HcmV?d00001 diff --git a/res/loader_bg646464.gif b/res/loader_bg646464.gif new file mode 100644 index 0000000000000000000000000000000000000000..adc3721d001c2066fd793160e8254b765b8db02c GIT binary patch literal 1924 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 literal 0 HcmV?d00001 diff --git a/res/logo-v-2.blz b/res/logo-v-2.blz new file mode 100644 index 0000000000000000000000000000000000000000..7b53ec4fd37472743b6560197be47d95efd59a33 GIT binary patch literal 17420 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

%I9JLd4+Fori%_ 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 literal 0 HcmV?d00001 diff --git a/res/logo-v-2.rgb b/res/logo-v-2.rgb new file mode 100644 index 0000000000000000000000000000000000000000..de6bc45ae2c119b56531d7152a04d26374f99ca7 GIT binary patch literal 120960 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 literal 0 HcmV?d00001 diff --git a/res/logo-v-3.bmp b/res/logo-v-3.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9c3678c5de9fda93d2a2e049b4476939e04ff697 GIT binary patch literal 46456 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 literal 0 HcmV?d00001 diff --git a/res/logo-v.blz b/res/logo-v.blz new file mode 100644 index 0000000000000000000000000000000000000000..ca6f9202cecb1906d3a2a3c89903554199a303cd GIT binary patch literal 22004 zcmbt+4}28Wwf~)rNoJeyb~b6s`tra`1Ex!hWQjnxqLKB-L&BqyptZ(QLsPZ)U++ z)Z}jL?H3#mQ3ea*m0>u#qn1#-mJ!rW++wg-X$++!Uy*!VaQ1N;dY?!glSZdt+WC>^ z8Xxi%t5v;{EW1;GZBjY$l`VDDrj`&#?d%fwzRW(!S>h-WP z`_IwlF>?2)RYZ)st(v>iqb^c4lV&0%I`NtCEPOV6AWS|!_o~kDxTeAt0~wNL_8p1#drQSV4;oOip7Iv`6I{1yAUVU2VhXAGN_E z*1+IGB?xg|8svC^LGcvjHPjz3Wd>BKe>Ww64Ue3A%IftMV5?NAo*9S93sSUiKtv=@ z8SsYG6xv@GHTI%Lr^%mzr(@{iqhl+z?H67)V(ECDoVW$swEnHu7U_sQ`C%q5(|b=m z7OvDKy*-VmSg8g3+r!rxZDBk`0oaQ|w{UM=v1JOZN0aU%v%nt4|o4ye&7VLxjOTn4()%*hp=A>clmqw+;urOd! zt8>yH2ep5U)_g=l7Lf+aES$P85{R;}n-f0*j;8ur^oXHw;tv4r7aG}U(*jtswKNEk zym7@~%+;1_V4raat!<@TD1GU>g3S(IUw(6x0~qIjZ-yx~sP9(Je;A4XnMH zuCSO&B~1g?iGtl+h^}Y!rWgaNV{Fh(RkfQ(pBue#l-y|O$P9?b!cAktkcFZeH@~$7 zlg6=4kYrvRSu#c-Vs8qQA0Fi_2B-@Z4n59`Ef`C*9MFj59pLW_7G6NdlVD}@CjQ$( zutd8FjLj#xBRQB{!j0oAdW~-Gk?<>cXV@aui3{L(6x%^UjbLyvypbFjQk|F%FrgRYRrPWhwM2AXT4V1*^g{E3(gVqY zh=_cxocNc{JaQ}}cnk&hWS0e$_H5fkDcXO&LA@G!yd!ej?pIK61t9y2>Ff=4tt7}> zFjY%hfsp&5OAj?~dR@5FDa!48vTN>X=|;cHc=QtIH`1tAz;(gi{N}M}r>KV^y?N~N zBMp>tJ-p19RqcENL8aBAT+@XbrDLc(pepX>!BE}1&Br+)yMr@UVVZeu|10`1sXeA6 zti|e1(y_QBQr#$`DQUeV4+UB}deqhJwC|j-Ljf-xzO zs+zL#uuDA?dM`$r6R%_)vw4Y$Y}D2g@EcKGtuQWEDROmF^VH_C!2Rm#r*hQIamcrT zO{avXF9QEdk;;qDgd^I3-hd%jqA@fSZdYCOVZ<5+D3C6(4v3y!)_x%qGCAVLf4W=< z?TB8F!V5A~7)n>Q*+|_?5um_SfIX3AK-N5V>bO`REifs-sb{3hj)S2W2RkCDBhs!4 zzmKECN*$TMut-=AFAyShtd`UUrhvuQOwc!|CqrRR^ENKns0=60g{jPT2f0PwexcK` z{TbO={>LP>D!wCTfg#&{OZ7lzQ6lOHCY}B}&P*qMlDev2P`!|XgfsA0&t;v)e)ipj-%+sq#JicwqMO5b&9vO=C^*RJs1gv z#oVUK0fkQJI%cYxC`0Pf$}Qk5pv8Q^2<`58zaygH_Au$RBp~3yGeq(nBOD&jLA4>18J#D^XPaptV0yEc}lduK!a(|2D#ditBY zgwf*~PuM{QZOUTqfG{L<^n`AyuN39_Ueux%s#?wJ_EA@GuulBFh|pX+uC81jq+x@Q z@p;kqtM^Ft@2=f<>!qg1@P(~fPx#|dxbDIRJXP}*LH;}@iKubpb7>ymj8GVr)hqIc zNI@0r8bb$uyQI2BM0H|=YoIKswwWeI!`4czZIm|As5{K}P_Rf-UByz%7-|v;YRS*? z`dbpe|H#{_w>&7d6BHCiGSO8Dsv>vSs;tZF4G_*K+^G(PHuFs zIkDrzj1M2zez_Vlp$&NdN4}yY2)I%(Z%_*MB9GsXHnzN177*pYF-0z48k`|ZZ?8Kb zrXi{NYfVz)NGFn-Mr5h1z8eM8ncl`soBq5Hq(Kj(m**_EOBekxPAd^}r)POZ)VjFO z?LbP2g41qxi&-s-7b(62phv?|+bSL9C#8T`A9_)38_-cL-IXRi{YeBN|3k7{%vJE| ztCW)PbnE~mgbtwNh^`_=?dG~bK`|h%U%UGJGMx7=U4H=)t8gE{7Tt~5M0A>=)Xon zM2Cs$RJF~fAfRs3?#aL}kAcpQYngb(*bl%9 zBg#l62RoZRI9fGSb-MnZX%D9O@)2SR88*_Ndgh^O{lJ=uyQ~B5TKxL5#@*9W!C@n* zD+ZHt#ViQzABailgLmes3PJ;}+iznd$d6)Nb(m;-sFO{&emiHN<~B7K4FvR<2s)-RApit^GKRM(0tC~ zN=5~P_|jjd{ySKjRFZu2iR`g8%L6G=eQyW`tRbPl{g#TRx}j(b9WsIGa)zE(bS!q_ zKSMC;fVNW=CeK5wx~GlN`7!Jq)U8={P0RNlJ0-lHQShJTd!Mon-%-D^@ptLN|96yJ zxBrDhbfWM~zY|u}qM^}`yTf&kj>PY+>Z#cZeXBn7nNXzy>gx4T zGod^EMWd^se4rveJpJau^cK>cUbAiLws!HPt2B@|XD=x4#FlnLf5K{JDBO#XN3ELm zy9f3;w?uYCQunPJdnmGP?5FR46IejXLR|Nfuc*$~U4Co+ps)CQ51J|&^$M9D4KZ=j zQ%YQj8^*$UYn(mljg{Sb$C?sP3U!WNRQFP!X4D=B1%VWb`kGy~>Rb$dB6S{zT<6)9 z(OBmxs+faNcR8nZVv9z9#DiFM!O(g0=od$Gpl77+d+iyp=r5}oxgYP16qMyVPxL|v{I{5;YD_3|rSMJVv$Kl;9wQ63y}1#cVa7Jro4ICdbt zwB}k#lIoUnJlmK~Z3M*v>N;L)PHcGMPW)CRW%d8uKpYR%{L$02E2GYLspQmg!yz0| zS0xYh;tT$I0e?$_K6z_FaW&*3yQg+_r@!=zDUHq3lF(ZfjKq+~Ibfxmr5R34mtHb3 z>C*lqMBjcLKYsaAx{yGmik2a8)cf-eiN}TWk4-@+l=q`d1Ass9JK2J_U!Y!l7RIRE zV|RxLT~MUg8vIgbYjWCrBBCVJoj07W)GfW|Mk8=8%r_wT1GR^$N5<|oi|CVX^;#@{ zu|W9hb#sp{7=b8$T|)OQPkR3Q%f3e)wJa2WJ5%wYYi{?+9e0@Qh6{3{Yp^jM+(0YI zSF{XLx9P~6aA+YqDdcClTo)6rmp%S`sk(g>wpFQs19|5|>4PEB+>kJ^efp#qRw7Ng z>`5Oq3T8lJbydP*aKpvD^SZo8(u*o`P$)gMcF?g=%zfK+P^cdaih;x<=Bi7So!&NK z;ftXIq3{v7$WiU7u_MtQP6s67Es~qatqAshQQyBRL#`XMJW@rI>e>|Om8w%WIw5=f z$=5JKyJxftQfc6MS1A0}I4yIjZ(s_O11l_<`1OdzjHm{V>cZwSu{Rq0efOlQ#j3=0R%pnfKF{#WWQ?}6yZu7|NR zSE^LJl8}Z@6}nFf+oghXspeRojL^QapeS=OK3$dAlk<{h_19g%S&Xb zo5c#cmXTIVgt-~J{aKJW%kJbMh0fp)YHo@St&+pAdxf5PR)xady0$IgatmA`o}UZb zv|K9@t*@kP77F@P@BbZlSQDEVig7GP0iBb2)Sc2j`^S<>UVWr_?73)cm?VNeP%dDR zXOb-30W@(YUHt;;ILM2lyN~>*p=F$cJAu1KZD^(IFdQrOsXy{UoMpen-V(`J0eEkG3Y6dswLelW{J5k zd?BeM1|X``tq`cCUH7_6ojX#|@*Dew(Y2|x^rN<3PNglWwBC=Hw*EAOS&GG7PltYi31sU6w_HEcuXH`NV8dVEt5`nm8PVMOw@9bTwO6XH z<~>#!hUvvP2_0WB69!quFBMhD6{xA>j%r7L!+>|=lG4CU%a`8|xt@7N8EIz@?WV;B z5~H~flb&bB5*Ow|Fh(;_$GrYCWXHX|TenGDVY*E(Tf3x*1nCHRtj>#$VfW!7&E=9k z`Q73(P6z6*>KZ8Q_a63+^zKP7s{Y~Z4W538mN6R;pbzbI9ZhD4GZZYr&t1GEN|nVm zsWAGzlNfQq0`eOO^%wT`7q$mdelI%EKLTY;Oa8CHO$X}_a>v;V1-HX8T1KuYS3JL5 z6%ZQPm6#yZI$yk@zwrJWD2xGN!JG{|Kl?Wn3d_nIUd-?0>tMl=r4>zIuIbu3?dibC zabZ`6zf5wcdUxG>0>VDOEVb-}VG=xvw%cYBI>GJm0uE21nq&F$@#Fy^(A(mW3a+h? z6kif*J6wNyqT^Y!@Vj%}9$78?g|&95aNVMOoPmZNN0a41{@}pW;+mII9P-J#RAF>a z>8KGh3~Ht`4Qe%&f0nweh|&7K9VVcEPx(tS7RjJE>~rP@e){pEgWd>Kay$>Ryo}@6 zC~n2GRuFksmiv{vruh4Xw!{|4M}30i8P1cofVEC+bCRwiZHLvcI0eG!Woh!I_;keA zN8B#qa$*L0C*_0mn%A!0`_8<*iNBmOoGnGXT@a^YhH717S|Lw-!0=*BSccDtnk%_?F&YaX8!m(!5POLY$4?b^9nH>vS=Abgo0PzWZhh1QfZfQFPak zm8ajAhsCnsSN@#Xjoz^2B^FQp5%A#nL80WR&BV9EF$Et?RxVG+sjn{jJUa$h0>;C- z-08*M0=cyQb8{a*HMP2Hcx6ix>JtXVA((q6zAYr6cca6y1)FYkL4$Ozg z2)g8OxO1tmcvwu!>b?K0IJ&vtRWs-gj3kG|4qGN4RhcTw^t9QagE{dse0&Th3&W)m z;n><92p%C(R)xS|DDP>y&||%TeLnu%d37gZ;X7W-pp)B(7Y*OyE1e^kLM~Z-%v~*Y zb;7cMTvXG7)Hc|svR{NY&2?i;}D5@)mbZFL)J_Xmm(qV3vgs zy88&#V@0GiHsfbO2Zze<%$59Qhmc&H9cV#+6Py^yl(dUsvVV0jeb3A+wM8cypNKPe zR6#um0*@&FRC1f7#su0-dTg3d%4oq1IMCSBXDMJP`jVgBLk5c}Cq5`0A^FN`dFwhb^9sB>iz%j=~fR>;CMB3x%L#cp>SIQ-9(QOO%k;n96c;tU(wvPx(%^;oUM#oeW6b^py>MSmCe|!Wq|i#MtBf8&m*FFVa|KD;=*!y{Jk#bGNF{QjqDQ`hZvI1-3X*elMNdoB8W z7?PzK(XCIZQclQXZy4OisOQ)0H~Tm0EEawe?}?ju!U5C@_uTm06~rBexum&g^ZKR z;&8dT?)ak9)|ZopFjKTivoJY4b(*xIrh2-uRwqvygLZv(7;(}pT&$kos*9}M^HX5Z zmR->iX;nBJyBpn`7srF7!;V`$!wimD>H4IKrb{ZsZ9Sqs=~QSTUF$tV57Iz3#r5O& zNfi83!|ao=81UJ|`t;>{vvo{DQ*IPbq9$gU0ml(lh-%|0%-n#XStxRG2@$i1bokEM zH|O9PWWOFBY*oJyue~(UlH@`-V|a3bh%O=W>*VjumQt>tjbGNDbbK@AB9gu`jVo_t z>vTOCVnMpP+MB#xWg@cysXHd+$ym%~J~ki*8Ka$H*gB=7wG^0U->?dA`f``>eI_w283twPGncB zn`5^Bbnpqo-2)i=oQRyr>&ZLibt6<12=9Knsb3fs1k^O|SBXPHclO71|8>|qw3@rm z(3Z{0Y4ncK7B&}x7y1?`vOkDW%2jfiuZ*CDxm%On1tYF{VXmiarw6TFdPeMCInWeaU9h_h^1xH;~fwhPmxeKZlXXEVoxhL}G=bl_5^@`Q^WM%~;Ubny8 zfd-U=dl&DRSD!957BT=E4sC0soX-Imfzh<@!x_1=P~!DuItZze(Z3++#UJmyoUI)8 zM!ZVf9Ro_!gPyYXAE$JpSB3wE;XWq20EgHeZg^-dEK3cGzrU-o@{)LNUe%E5`apCd zF)LU(R0zI0F38@}chJvvd&k*K3n(aahv6k!`~ZNGR9GTVe9cQBZ7t3_FI4!37L|2v z&-M)o+v*R+L1P`i8`ury7?pljYiPCF28(Ms_058(bWV%gU$Oay*Tl26@mBYIn0>>+ zg&4X~Bslj8sYR)XhLqqbVY_3fA^rgz8gESSvBU1=f zTXq{0YopNjs%b7`>R>o_6&=1e)A@-f$JvJd}xULt?I&JD4rKJ5%mi@d^Vq{{;o9U!gmTFe;66JakhyT@0_P-un_L zSoqw`%P%-2cT$NbDR=fgo;4?O|KoKNENYE@=m(rYU)UT#PgepSSh?tJLClKIK|*;= zp>h+%u!j!t6vPIhW5Ukhy2c@;5q6OCIwJp2+x82Njg8OL?Gb;Jh#o=awgja%Qs=g` zj>I_M$b&^eRY-6x#{Vl9jVN!xa#=LRuUDoQ)ei{}Q)$-mrl~S} z(sTSciE0(zKb9ja{(N@YM|CX%Pqzu4%3=k1iklex-yp6wdWsvpr9wM&C0LW&Nm1cH z^I~%zp-F9H$FJxc!&~(5D;&10bo)e(Q!G|-C)k=Xg z;P#dx3AUD{23-ypqC1O*)l#-LJw9Kbj%oU`5Y}v|SCVqcHcQl}FnV=S2<{47{mrK9 za(-BkOx?%4y50$cubX|fZPS9qveNj|bo!a_jNJU%`8X-p37Wvi+r539-Oz%y?Kln5 zLSZu5^qdbzIwne6CSWl@t?8i+)SxgCY|WbmTo7x0Z=+x@;(=13+~bpEVPJZ1EsS?? z!>&axk`yNX*BU+6{nz@3ZY zcYP$cBG~wEgE0)jm!_ziCEtvqQ7j0vM%T2Vt%B`%^1HIb$p@1^mms16Z~x|9>q${l zQ2g05Tq_Hto>J_wAy6v4U={2QKXLU1QSs%MUlayh{X0AJ4hx;xdHEj~9YCQv4rhd6 zwr@y}0E`D*1IKPQt^IO>toU-!FVeDtouxbG4JZLmXZmx87wt-vb}b$#WQex)6S@#b zRHa|wzBAOL4{PwI9q4PQRo>~?VJ$EA#t>P{|)M#%seS z8)f|a9$RWyiWhu`w5;h@idvIB1)FZ`7Y@S-ht(TAyJn)!Y^n3T9j4*z3Giu5^wUoX zXo(H(0lJvgFxx*R!GT^~^7_m}FBUx3zq-a*N+Flctn z>&fm;Cs422PVw*lSEI6GOoXll-^Ec0{49k)Cg&M7EAd4`vX*x1e#_-em=QmmN($(O>wwtr9KTQAg2y&eV+J z=>!z#e`huhxc-rGy7>1FC+ZA$2}~s;HRl=vgP9E*2=syO{C*+9Q|Yh&Xx@~$ukARs zL^@pc#_5=Cy{JZX)MZ|>s7O&tF!>;i(7)|+|7CUZcd+Pw#8cWQv}8*!KiKtMCsw&0 z{0{8YGDY2a3AkgLz$)B!ku=}xA;c&1{l);qjAta^h6CVhCc)% zxxLp!T>hHBEsj(T2|cCCfB7m7h-VSqEvJ_yUa&|8huPzTmB8}p@JiosU8~0***skS zcJeQ#?0o!8*akom;amkkRMC$n*kyD7ow)fj8D3d5{Nm_l|0&md8Qupgo=fS8PVXs$ z(H>|cP*kPW-kc2k?}RPq*;$>AVUd)1(pEUosOxN=uSa~NzR&Ac3fjI1P5w7r2Y%Oc zy*S;Ez5hDwG?NE!ax25PjCwtz$_eqWs^BYVgs;;m!BLJv?=(`wGM23`8>&-+#jv$Z zhJ@j~R1^_LT)rCkn=&r~lBGbBE21C!{6WPFtL{B3Ew#aDLHYz; zl4Aiy4(wG+svx_4Qz3Ijs3$t$T4vD9#CXPWoLM*mlOb|KhA;YfnI&7MI~(+X(v=`! z6&;~glbJmM2VH8VA9^)EO^dDsVX&AebkmEdn_=-$(;EYQ6AjQN(ZrZE&X#t}YYlEU zhHA=YYcaGSK7!t*c82;VrZ9Dg!JsZDMQUM@x=3PweQ4N9`^ktjLH%s0E!!vL-8a5v zR$VL4doyHY6t` zU@t5jmV#OM^kObIK7|$5M)A)Y`x8!w_|{%@F$HlM3{3 z$g3v?l>M9-gA1LQf+NIG=$+3lG=^eg)lH$3W?@=Iy%GhZi$kIB5*L_%5yvvdaGr@wp;8Mz>q!sFOvj*lw%9d(orX*2 z_ZTg7z3nY3hGL>R;58J-856N^9q8KWXBz^j(0YGSy{c{EVEjG_wb{(tw006K9G%8C ze{nuL)4&Tq$xceA%dmEXPa%{|6kxbC1+u3}6~G*P{1uFDuFr6}j7cm23wD32wo z?8T%p*t&G6R9!~`l6>6dsAT|_`NtGDJy+mHlK{l09BuL>O}I^ZEj5CDZp!hb8sd`22MEg9Mpy5@fRPkkWz zb0OUGFyeZWXf^POi{IY2;d95_Bd6$wKIO)1$<$_4^Y>b_!EgZwX1cM=5{6y870IAvlHX+#WKmfZIdq~x;_xqo(kIv~< zOQY_VbdF5VDXCANzNq_m{@41bMW_<^!f{W{Rh4NhMIED2-O@XPs>Md zaKuYA(A(bctsCEZ%eJhfBCu}!!SB8G_}bN%$G%$e)rw1gL7nGR?UHB;q zZQ(uf{=?gcw^GYhEqYJk*4BH9UXxqZQH8e;ZiS_z^|ho^lxNkm|h{N%KId4*&tbm`1wB@uz3E;E*CbfmK!t!FH|#qu)8 zo<#aia}3wZwwW%w*OP+fiml@u$1@vGLsn-wTFY2=hvl|gve=V`I` zj-=1B=CjOfJXH=ObeXYC#Zc-wV<}0bpJpu6Gn9MCSV|J2N`=9Dc>f5_@ zm?eFWA}a|AWGuU_aU=u$b>c?!7|~VRR4TiYhbzE_m>-ZY$Ict zkO2IpWVt}b!q&V z;wpREnWXP^P8vV%Fv~%^?wKZv9kbdDvm7LUIY|_8Pv!8?dm}4Wzc&J= zaW&n|^#_wBt8v2F?LI&J)r#fy74;RX|8vB&oky@V+P6#Vgw;6hK#ikBae4jH*d_Yy zuNSOiX}7-wM_gU}tFK1lNWVUZUsb!q3LD=|xw;?6J$rv|16DmjvE`qJ-W|D2R=vD_ znbe4Kc?@%xRy;9`eE_0jt8MxGe5K?MPp z7GC#2kJFU#NHvbuSdE|vHNG(N0Odlg+1@Fxvpq+|9&2<7MecFm9r0@5HY$80X_4j- zalRaRau{kfZP|)*fF=1$n_>_2_JI4lk>&Lb9IwfyDf_99*4`yGavU=2Ar(i|!Ys|- z9|t2v2y-*;6GI?+2QmF>#mV6<)Z>Wf!80*G7iMW%m(vtuBr7HgnjrVU&VsnV=G2V15hj%zGU>k=&QAZuP;`)cI* z;XN)?DWl7zX8X4A(~m>3d}(~U1-be-T^p{a=z?gyK}745f~ZaLTIZ+N!E%StC9||a zmm7$sM}>ISHW1O#+Iy6ZZ=w8$HEOGs`z+}@N=s8(&XW4x&P#4Wfs|^^LN6 zT@~i*U^(YKV+~8voEVQBt-))q7c5z$>jhD-_UkJqSayUy3n}aX}RNFzrW~<*5csd#)yM1&NGu+Br1z?(k@B12JWrhYwvx z^Uy3^PYypIwQN|OK1<;*p-bED_ei3+j{IVT2-Y`{EoQ~6jo!#uc7tN3%kELkSazQ!#?{$h z{*1>j&F4h&Kc_}z6j;XNFX3s_+I?-aFOK6WA}-CDw^}CGQPbwNyREyW_NTM7MVFFK zGaZZ-MVCp#*F4}H!LqM*5$2G`j1%p4e`b%r zbaOP8w!g+@56!8O>1n#^etziZ_5HOSO=Yh3^ZJby8^$&kEMiH|ZP0VdqL40wqx|E} zN#eY{w%!YuZQfk%3oFLeEn-PN=dinjc+rbkV*E!Ij9*BW+dWq9oUh>hq{|U6XZZeZ zjz<3mg=LOedfOt(eyeo(^6CW(@=KvhZ@b63BpYv(hAzGBwRPTZ$}{n#Cf>=X^1IVbaN6ia(_IY+u=mO+0hS5o6-DfG5tV=q2qt}qIalw*!hGS2VrJj4XJH!4hvy0~f!*WKjT&V3M>)+>{ z9CECqX)nt;wsB2)(B(pHjL!s-Q zob%hEBgAsMp!q5(^Z^&o8U)YC+?;(Z_qd2WbKXJ?cC5%ul1<-OIYO}qWgFS~k=l{k zJ45`Wfm+X8%{G?ExM9QFiRIdgmVuK3XGpONHBeljHE<=l-+QIDmac&uE24UsrQtYE z{%^v$y|O?o;S-@uJdwdyIU}S>Xm*=dtq@gW%ARwMB9VA*!?5RMmLJfw26p7?Gvp)5 zD-x%Dq`LjypN8nln=Jj1d%GaH%{xs|CnqweS412l1$#%l8!P6oguwD;&mxv0mcWYP z6-k@KbZccR)mVr7Nv(&8H!OZ_<&~OL=c|IS+3U(MOVc(E4PyNKRiXsX2%BD@g4`Vz z{RbLb%Zc$I@cix2Y4Vs@>xef(YRy=NBQGL$wE~);gxnkjTKxmXBjFhl-|23ULr)6s z^RVUuS-I(Z6uK^7CZA(EzhthsLVRavfi!nSsB*!B{!Z7bq&+%9S?HS+$S-dsTmMKb zvqzUN(@2&bEb)DDXs%k>R)LknXI3kRDEHAw`b1&tC&?$Q;|xl2HZWyfekkI&O)N1E z1P$VM4tCS1IY!l6`9p9&?EZ;6li_`qX~iuNvg^ghEzl+T?A`8Z-(Q}#C?~RkP26J$ zu(T#uk9!tYtS|g!LzfxLm>x3Nhf0@MR%bRIWD|Ezu&f}zB$k;j)9W&0nTny*Z@|Vg zU8Z81*|=0y`f0{8Jwv&N5KGG4?RgGD9^;@)Lo6xZ%vdJvJFq;L#qm@zN3zdYN)qX( z#L~%hnVuu|pzHD+=a*g4dzz!0PH+TCwn=l0QQI=hD|8Kcb+ymZ@KZUs6PDz!`3_~& z`S!9cf@K0#bngf!DHi@JK{@FjrhAoU)oB|`$9dcRv-gpA&O2W@j~Cuicuv)V?UkEH zAF|^9__<2J#*ONdS)TV!S58;X(Tj>+7ju5QScB{5yqib&+Q5?HxJ@iiy61_~%Q4G0 z-qwB8XQqcrGwR(5y_R?)J%iX2VhYbJz zrO@Shi)>szM}%jI;uW*c5+ReJI4=EV-Hu!xPqUz4%5~&AsLMHSm&?_(dzo3XJ^49N zopSa1c}uQ)lAVe1t)z`-ESo%c?7qoZrf1mL18kgPPo~QTk=S}{Y?-l4&Mv&AVtLc5 zEcS%y#GB7p#^cp)?TlqRI`Ni)<)Vl^nT^LI*St2fyh?FAW7$k6UQ5O@9ns;5 z_fziPZtZMYI|4zL;yZj9&4dJkEVpF3Ovn*>WtKOsLhM=0#)(pp%viSbe{q*xFS^7S zeB5*I_WFwD*nrwNz8j5S-#A3io0$E6>0qCf_@PKYMdgDiGZ#v3fZso2R3Ih_=bwN5x^-KR;7yTGvwHC`o8xta7> zuijNUNJnkM?_k1*H?dsu47(jqTI~-?JK^41c!_)?^tVV9;T>VstIDTJpV9B_0Jd2_ zDUUwL(yno$X(#Xe%Dq~8toj&f5F8gv_3~z_UoG8LIxK#J%Tbb{0f zj*|gJm}MwG9W3irT=#5TRj-=YWsaU#e~FX_Z-b1SnaN)u14kPvGELi9I?iYAW7S>d ztEC4^XT|Rbf+!RUz1qtW#}{OYd8t@4Q#|`WRh}wuF7K+&QucFO;gE<(Ep80{+j3vibJsWNK-EWfk$!)RFM#N*k}2 z7bzb{4m4HXMWs&JB*$-u;*y=(4BEK)*fT-DAo^fou{2wrC5mH26os-%L3FIVS6nUH z8OZ}I%e#&HOU{V4&ql=|6(&lDr*-Z9-7v)B{y0j~*3zo`X8n5*k%Rr^Gya(Q%8223eZ-m&#l7Smh**Ro+>+Qi6@omRB{1f+xJ_Q;p2Y z{55%yrG3vDNTO$j7u{8Ulo-~1KPuzWRmz-#|1VbcNIz@La*VHg%J#8jn@2uG){)A7%6!%*%8`Ck`IpsGG_G#e&Y9&# zUzhf=46|jT;{GFLPP@wU6xU(%v*o=73+_?4bSyecjDqtBIM)nk?_rvFq5#nw|DWq^ z_o)Ihr(Na8%1>FsGN4PzQt`BoCirqx8W)+imh2;SPuVJW&#XRRJvz&& zvQ1-dHY+gt*nE~N-+CPW(vRc1GF2Ss7_Ms(b@>YPQ1oXdX+eRnx0() zM?6_{YhkK*Q}I;cRN;fR<)-3YR*YYA9B;5}#Y8fcQ+>UtHhp==b;lVlY$`uTG$-iJ zJw1Kp-c>kLzE(a?2Q*G(_Bt|#E|oqd8Kq05*_2fAtieU%HcVu4&K9EM zP}X*(a2)q0ikr%!6gR0_8TBdJ!j3UF_LocQQWEUx)S(fdSyJKg@~Og%7^B4dgmY(M zzIcpyQYnfTzx#9Z#WS?N1-f)PwDF!Ylri3MK6U5IJBzbKXR3IXY<-+Q7h}IC+%ak; z6-Jb);=ItMaT^b_OlhT(O0ua#PXZq!Rcmi7M;D4iw$!?q)g*eO zhb)O4aV{fubBquNt6T@uUKxq6tPoLBsGo{}Qg zipc=#oOV7aTq9LZk+mNu-}zJlxu{*b++4m7u_wqfc;0;Wk_$Mrr=hPIO)UXWsPp@U zV@1vWnGvz*oMLo%!IJ2R4GF>POh`c(ZRYq1z$JQI;)w7xM%%$uAv1rydNM>xs%>$T$rZFIxiIep2k1S#v!H4ohxTs=~DSb zXiv>?t+^$t|=NU-y~Y|OBCh^mY{inv}wov9@ZsT-cM06iKpn^Hn`uz z$~!=WS{I!)eCNgDi^lI!Aiq>BcavxD9+xD0!gour5gClPbzUwO*L>%Sah5?FZ+m}S zS}xO;b5YawR^M#n%G%v=8V7!=@YBMNVwDFAFBU3vH)GPM5`rvS#GWW#$=lkpY@ZW} zl&HlUk8CEfg>G#VWO=`F8%M^CXZYh5)0#wogjgc>u;PqbOShEL-~EJGTA<7Ro_{w# zO~mmc#x^?2FOz%8=q;7+)N5QHILi>alq`#hV~-*s^KX4Ra8#11l~_8nlI7CZJ<;k) z*NT2ny;X?@uC>p;4_oaBsj(SbfQmY5ZsoDNN!Qn;J(BA7%-N&Q`*SY!{;Iy%4v_z z4d1!t5*&@hQ*L>Bg`a1WPrrrRduh$l`wr@|W0tJ39?%3o`Glo@2WOh{4LoCch^BZN zlg|dVJrV8E=i2L5usk4gB8olT^_O7_$N4KeZ_y7J3qC4F)Q=WVG_Jy+)nDg6p;6yY zitlUVL3vW?%HkU|&iRQ216#vU{*w46=bT{Yy+?wwk z%dc6svWV~cu*P8V_Z8PHyFf21#xFHp-cSACWC>DB&7PE%CflPp1+}SkDQiuiM!Iy~ z%pWVhkw2DyE}+X7a~JcE&?xcOIW;B(mN(@u=AR|{r|2f7WZZNPO`p??H7F-)usop0 zaYaTE<0DcrNm1_Fu`v61D&QkU(% z57{9NKR<0=n|;L+9s;_&KrHcUY2)4;?`#;`7JVX52re01yy zDol^eSQ4D)xfH#@EZ=Oe%fVoY*yH;mGy1%KSSB7<4{A5X9AeJ}%7}b_>F)`-I%3aJ z&WYR!-yU*Q+emG8_{*S;+rsifGfQ{SSVoMw_1WUt#(kEJNQmokutZLdTs@dyLYHfn zna|aOy7ZsTk~Rw8DOt9w@%o53`dW!1kYf2sC?|SRN3Xm_ z3M1@a=YEmDkM#QMoat|+faSAdEI4H2Y?U}m*|+k%!fjYnuBF%HcFMlhQnf5pqdScB z9}8#PEqHI-Z)_YxXl>Ds_2lPAE$>@fOO`nAGzDkCXNbLUT~6Dc9pX&X{qa^j?YTd` zB+F(Bk_av>IQ`K+n@5@)WLVE^$FrpT;h zi%yoeVa7}iYxSI;{t020dgKh8pMI{rt;_QV34Sq^zO&IebyDv+OR1e^GLl(%Dtk(j ziy^oACa7Hs3KzK2{t@=Tv%j)SalL|Lb(jvRMheZ;}0mPeNT5OZzCy z(rB(OS;^^uv+QB)(Um1>@wD}l;Ch|Rh57To`=aEqE<0iwb-ePJ`|R)g?-g5rBD4Gj zJ-2amCGyLTSVAAnj>*Y+8JT#hmZ=)+gXg(N^lf;oi78BUGJTs*cKJuO)ach6ov_vUa)of-dnZ}!{9>BS= zdStDKXWK-(tDluxm#juk5T;{Nmm>Cb*c7BxfX+FDWFSt9&p?^v>}F~8?FUIv>6z&!^gOJ~*J%7w1^GgFOc>h^L%^hLv>yDnWgG~T?^J(Zs+s|T$idpEYRlwvFywfBwtJU5NRhd zZ6sqUu71!1U1a(3XrKKhD~Mx=vQ?=G3v9M?PswX4T^eE;-zF7h#XY7q#--HR`j)V4 z)+Jk=;x+&^OIXHNXZ$VLAEHlq+h8rYG`y^%p8S@uWZmmp?}1nN7O`Y{lBd#USf{K( z$y!c3P-Zhr{BnqqqRs)w&*#kV9h^sJ(V>@X;s2D%>+z3AKh96nI8j!70yLH@ikfnb zn9(1W@f3CbBMqprjZdBDoD*3|NZ>i=Gs&{LX4(JdvyzU$nq^0;Z#{m`cYj=cc=X@1 Tl7hg)qd%_R^WC=|cbxwR7mwjY literal 0 HcmV?d00001 diff --git a/res/logo-v.rgb b/res/logo-v.rgb new file mode 100644 index 0000000000000000000000000000000000000000..5307d5ba8941b56b16c37585ebac07cdc665143c GIT binary patch literal 158400 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 literal 0 HcmV?d00001 diff --git a/res/logo.blz b/res/logo.blz new file mode 100644 index 0000000000000000000000000000000000000000..655cf563540655b28214054aac49853808a89f45 GIT binary patch literal 5304 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 EAA+|kNdN!< literal 0 HcmV?d00001 diff --git a/res/logo.bmp.c b/res/logo.bmp.c new file mode 100644 index 0000000..456b0c8 --- /dev/null +++ b/res/logo.bmp.c @@ -0,0 +1,233 @@ +/* C:\Users\elibo\OneDrive\Documents\Switch\TegraRcmGUI\TegraRcmGUI\res\logo.bmp.lzma (23/07/2020 16:32:20) + DébutPosition(h): 00000000, FinPosition(h): 00000AAA, Longueur(h): 00000AAB */ + +unsigned char rawData[2731] = { + 0x5D, 0x00, 0x00, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x21, 0x13, 0x52, 0x17, 0x16, 0x06, 0x6B, 0xB5, 0x99, 0x2E, + 0x64, 0x70, 0xBF, 0x9A, 0x6C, 0xE3, 0x3D, 0xBB, 0xEE, 0x15, 0x3C, 0x2E, + 0x7E, 0xFF, 0x37, 0xE7, 0x3D, 0x50, 0x20, 0x6C, 0x2F, 0x8B, 0xE2, 0xC8, + 0x0C, 0x63, 0x74, 0x69, 0x5C, 0xBE, 0x5D, 0xDA, 0xEB, 0x94, 0x71, 0xCF, + 0xA9, 0x47, 0x54, 0xF5, 0x3C, 0x67, 0x43, 0xA1, 0x7E, 0xAD, 0x40, 0x4A, + 0x7C, 0xFC, 0x35, 0x6E, 0x07, 0xD1, 0x82, 0x73, 0x97, 0xC7, 0x55, 0x58, + 0x1A, 0xF7, 0x8E, 0x31, 0xBA, 0x42, 0xBF, 0x93, 0xC9, 0x63, 0x59, 0x57, + 0x27, 0xBA, 0x19, 0xD3, 0x74, 0x07, 0xE5, 0xEC, 0x3F, 0x94, 0xF6, 0xDB, + 0x07, 0xB6, 0xED, 0x5C, 0x63, 0x85, 0x2F, 0x6B, 0xA3, 0x85, 0x6E, 0x39, + 0xF5, 0x44, 0x44, 0x39, 0x1F, 0x7C, 0x11, 0x72, 0x61, 0x11, 0xC3, 0xE3, + 0xBE, 0x80, 0xFA, 0x53, 0x00, 0xD5, 0x02, 0x53, 0xE8, 0xCD, 0x7D, 0x4F, + 0x39, 0xF4, 0x89, 0xB8, 0xB0, 0x71, 0xB2, 0xD5, 0x2F, 0x46, 0xA9, 0x0C, + 0x10, 0xBE, 0x8D, 0xED, 0x7E, 0xA5, 0xE7, 0xD1, 0x9F, 0x73, 0xE2, 0x13, + 0x83, 0xBD, 0x97, 0x6C, 0xCF, 0xF8, 0x64, 0x5E, 0x6D, 0x26, 0x23, 0x65, + 0x7A, 0xAB, 0x30, 0x10, 0xE1, 0x72, 0x18, 0x04, 0x83, 0xD3, 0xFC, 0xFD, + 0x0D, 0x11, 0x98, 0x02, 0xA5, 0xC2, 0xDD, 0x9B, 0xE5, 0x94, 0x56, 0x72, + 0x27, 0x4D, 0x0B, 0x1C, 0xF0, 0x78, 0x4B, 0x69, 0x8C, 0x90, 0xB7, 0xD4, + 0x87, 0x8B, 0xC2, 0x46, 0xEC, 0x1F, 0xC6, 0x89, 0x4E, 0x3A, 0x18, 0xB4, + 0x10, 0x5F, 0x75, 0xA8, 0x1E, 0x0B, 0xC2, 0x67, 0x7F, 0x06, 0x2E, 0x98, + 0x39, 0xF0, 0xCE, 0x5A, 0x6F, 0x7F, 0x63, 0xE2, 0x8F, 0xD2, 0x0B, 0xD1, + 0x9A, 0xAE, 0x54, 0xCA, 0xCA, 0x07, 0x2A, 0x56, 0x66, 0x0E, 0x09, 0xB0, + 0x61, 0xE7, 0x16, 0x1B, 0x6D, 0xE8, 0xEB, 0xFD, 0x48, 0x16, 0xE5, 0x1B, + 0x52, 0x0F, 0x21, 0x19, 0xFA, 0x5B, 0x95, 0x3D, 0xCB, 0x75, 0x22, 0x1B, + 0xDC, 0x28, 0x68, 0x8A, 0x56, 0xC7, 0x7A, 0xCA, 0x73, 0x84, 0xB6, 0x7A, + 0x5C, 0x3A, 0x1F, 0x52, 0x32, 0x87, 0x4D, 0xA1, 0xC8, 0x50, 0xE9, 0xC4, + 0x27, 0x6F, 0x15, 0xF3, 0xAA, 0x37, 0x59, 0x99, 0x75, 0x80, 0x81, 0xC6, + 0x25, 0x72, 0xDB, 0xCB, 0x6C, 0x74, 0x7E, 0xEA, 0xEF, 0xC7, 0x3A, 0xA5, + 0xE3, 0xE0, 0xEA, 0xCE, 0x68, 0x90, 0x0C, 0x53, 0xB9, 0xDA, 0xFD, 0x2B, + 0x55, 0xED, 0x9E, 0x1B, 0xFD, 0xF4, 0x30, 0xC2, 0xCF, 0x70, 0x4E, 0x96, + 0x4E, 0x06, 0x53, 0x56, 0xCC, 0xB7, 0xB2, 0x6E, 0x4A, 0x0E, 0x85, 0xF9, + 0xAC, 0x37, 0x08, 0xAC, 0xC7, 0xC0, 0x12, 0xED, 0x16, 0x8D, 0x8B, 0x65, + 0x15, 0xED, 0x17, 0xA3, 0x21, 0xA1, 0x51, 0x4B, 0xF1, 0x2F, 0xC5, 0x05, + 0xE5, 0xC5, 0x22, 0x9C, 0xD0, 0xB8, 0x03, 0xF6, 0xDF, 0x72, 0x02, 0x97, + 0x22, 0xAF, 0x05, 0x54, 0x00, 0xF5, 0x38, 0xDA, 0x18, 0x7F, 0x84, 0x5A, + 0xD6, 0xD5, 0x28, 0x6A, 0x61, 0x57, 0x72, 0xAC, 0x0A, 0xE6, 0x73, 0x73, + 0xD1, 0x27, 0xB1, 0xA1, 0x26, 0x04, 0xBA, 0x0B, 0x87, 0x33, 0x9B, 0xD4, + 0xB8, 0x45, 0xC9, 0x63, 0x85, 0x44, 0x45, 0x63, 0x03, 0xD6, 0x61, 0x6D, + 0x47, 0x2C, 0x69, 0xCA, 0x64, 0x22, 0x48, 0x2F, 0xE8, 0x4F, 0xC1, 0x73, + 0xE4, 0xAE, 0x35, 0xFC, 0x77, 0xDF, 0x5A, 0xF6, 0xBE, 0x3D, 0x6F, 0xEF, + 0x76, 0x04, 0x36, 0x7C, 0x5D, 0x26, 0x24, 0x81, 0x06, 0xD8, 0xD5, 0x67, + 0x1A, 0x01, 0x29, 0xD7, 0x64, 0x0A, 0xEA, 0xF1, 0xB2, 0xB3, 0x02, 0x56, + 0x2C, 0x46, 0xEF, 0x6C, 0xDC, 0x0F, 0xB2, 0x05, 0xEE, 0xEA, 0xEE, 0x2A, + 0xED, 0x1F, 0xE9, 0xFA, 0xD7, 0xC0, 0x45, 0xCC, 0xF6, 0x32, 0x0D, 0x73, + 0x4B, 0x4E, 0x31, 0x3D, 0x9B, 0xCC, 0xF6, 0x21, 0xFA, 0x5C, 0x0E, 0x13, + 0x0D, 0x94, 0xA8, 0x59, 0xDD, 0xD0, 0x1B, 0xD6, 0x25, 0xE8, 0xAB, 0x38, + 0x65, 0xF8, 0xF2, 0x83, 0xCE, 0x06, 0x45, 0xCF, 0xE0, 0xB5, 0x49, 0x6C, + 0x1A, 0xEF, 0xA4, 0xF8, 0x6A, 0xD3, 0xB7, 0xA5, 0x76, 0x1C, 0x0A, 0xB9, + 0xD3, 0x47, 0x37, 0x9C, 0x47, 0x93, 0xB3, 0x11, 0xF6, 0xE5, 0x4B, 0x31, + 0xC9, 0xDA, 0x86, 0xFA, 0xEB, 0xE5, 0x67, 0x04, 0x38, 0x35, 0x3F, 0x37, + 0x3A, 0x34, 0xEC, 0x3E, 0xA0, 0x44, 0xE1, 0xA7, 0x77, 0x93, 0x90, 0x78, + 0xC9, 0x8C, 0x51, 0x3F, 0xE2, 0x25, 0xE7, 0xDD, 0xCB, 0xA8, 0x54, 0x99, + 0xB1, 0xE2, 0x88, 0xD1, 0xEE, 0xBD, 0x57, 0xB1, 0x12, 0xC9, 0xB6, 0xC2, + 0xC2, 0x13, 0x17, 0x0F, 0x98, 0xF7, 0xF7, 0xB1, 0x42, 0xA0, 0x4F, 0x21, + 0xFA, 0xF9, 0x00, 0x0A, 0xF8, 0x0D, 0xC1, 0xE6, 0x95, 0x7F, 0x52, 0xFE, + 0x95, 0xCA, 0xE5, 0x7B, 0x02, 0x79, 0x45, 0x04, 0x31, 0x8F, 0xE0, 0x9F, + 0x43, 0xF7, 0x26, 0x0B, 0xC1, 0x0C, 0x68, 0xB3, 0x05, 0x22, 0xEC, 0xFA, + 0x4E, 0xAF, 0x6C, 0xA7, 0x90, 0x41, 0xC8, 0x61, 0x34, 0x25, 0xBB, 0xA7, + 0xF0, 0x36, 0x09, 0x33, 0xD5, 0xF6, 0x44, 0xFB, 0xEA, 0xEC, 0xE5, 0xD9, + 0x48, 0x63, 0x28, 0xA4, 0xDD, 0x7A, 0xAD, 0xC0, 0x31, 0xA0, 0xCD, 0xDC, + 0xC5, 0x09, 0x29, 0xCB, 0xFD, 0xC8, 0x9E, 0xE6, 0x40, 0xD9, 0x5A, 0x5B, + 0x9B, 0x46, 0x10, 0x1F, 0xD3, 0x9C, 0xE0, 0xE9, 0x24, 0x92, 0x29, 0x77, + 0xAB, 0x5E, 0xE7, 0x7C, 0x70, 0xAF, 0x2D, 0xB9, 0xEA, 0xFD, 0x5A, 0x9A, + 0x4B, 0x53, 0x72, 0x22, 0x48, 0xB3, 0x6C, 0x3F, 0xA8, 0x9B, 0xAB, 0x34, + 0xE2, 0x3F, 0x13, 0x62, 0xC5, 0x5D, 0x5F, 0xBF, 0x82, 0x94, 0xB6, 0x03, + 0xB5, 0xD8, 0xD6, 0x2E, 0x84, 0x00, 0x08, 0x25, 0x36, 0xC8, 0xB5, 0x00, + 0xE9, 0xB5, 0xAD, 0x75, 0x73, 0xEA, 0xB3, 0xE2, 0x7B, 0x21, 0x1B, 0x22, + 0x3C, 0x5C, 0x1F, 0x73, 0xBD, 0x96, 0xC4, 0xE1, 0x2D, 0x62, 0xA6, 0xEA, + 0x1C, 0xDE, 0x31, 0x7F, 0xA1, 0x82, 0x69, 0x1A, 0xE8, 0xB0, 0x6E, 0x03, + 0x65, 0x8F, 0x13, 0x67, 0xBA, 0x52, 0xA7, 0xAD, 0x12, 0xE3, 0x81, 0x8A, + 0x99, 0x7F, 0x2D, 0x68, 0x42, 0xFC, 0x83, 0xFB, 0x35, 0xE6, 0x7D, 0xAA, + 0x4F, 0xD2, 0x78, 0x21, 0x70, 0x95, 0x1C, 0xBF, 0x56, 0x0C, 0xB6, 0xB6, + 0x8C, 0x0C, 0x14, 0xAB, 0xF2, 0x63, 0x33, 0xEB, 0xEA, 0xD0, 0xCB, 0x4C, + 0xBF, 0x4E, 0xA9, 0xF1, 0x32, 0x49, 0x41, 0xA7, 0x53, 0xDD, 0x4F, 0xA3, + 0x0D, 0x6A, 0xC0, 0x87, 0xF2, 0x34, 0x3B, 0xA1, 0x8C, 0xF2, 0x00, 0x35, + 0x3E, 0xC2, 0xCF, 0x3E, 0x2E, 0xE1, 0xD0, 0x92, 0xE7, 0xBE, 0xD5, 0x87, + 0xC2, 0xB2, 0x8D, 0x0E, 0xBD, 0xD8, 0xFF, 0x49, 0xBA, 0x22, 0x3C, 0x36, + 0x83, 0x64, 0xB0, 0x0B, 0xED, 0x2A, 0x28, 0x9C, 0x77, 0x8C, 0x45, 0xBC, + 0x71, 0xF7, 0x24, 0x53, 0xCF, 0xFD, 0x27, 0x7A, 0x5F, 0xF2, 0x76, 0xC7, + 0x02, 0x05, 0x75, 0x02, 0x80, 0x3B, 0x33, 0xDC, 0x1B, 0x2C, 0x2D, 0x9A, + 0xD2, 0xE1, 0x90, 0xCD, 0xDE, 0x85, 0xF3, 0x73, 0xB6, 0x10, 0xF8, 0x56, + 0xB4, 0xBE, 0x80, 0x2F, 0xC0, 0x00, 0x91, 0x41, 0xB6, 0xEB, 0x3B, 0x9D, + 0x9A, 0x81, 0x30, 0x00, 0x07, 0xC9, 0x9C, 0xB6, 0x96, 0xFC, 0x87, 0x9F, + 0x43, 0xDD, 0xD2, 0xB7, 0x53, 0x67, 0x81, 0x33, 0xCF, 0x15, 0x9B, 0x9F, + 0x08, 0x5A, 0x07, 0x5B, 0xE4, 0x35, 0x95, 0xC1, 0xF1, 0x57, 0x49, 0x87, + 0x5B, 0x44, 0x9D, 0xC9, 0x91, 0x41, 0xB5, 0xC2, 0x74, 0x41, 0x6F, 0xAE, + 0x25, 0xCE, 0xA7, 0x89, 0x39, 0xE9, 0x6E, 0x6E, 0xC4, 0x8E, 0xE2, 0x77, + 0x83, 0x7A, 0x7B, 0x48, 0x36, 0x84, 0xDA, 0x99, 0x19, 0x76, 0xDC, 0xF7, + 0x6A, 0x7A, 0xFB, 0x0F, 0x6B, 0xBF, 0xB4, 0x0C, 0xF5, 0xFD, 0xED, 0x1B, + 0x92, 0x3B, 0xB4, 0x50, 0x83, 0xAC, 0xFA, 0x28, 0xD4, 0x4B, 0x91, 0x16, + 0x39, 0x0B, 0x5F, 0xBE, 0x59, 0x80, 0x0E, 0x28, 0x5E, 0x63, 0x50, 0xAE, + 0x89, 0x63, 0xD8, 0x10, 0xA6, 0x4A, 0xA8, 0x10, 0x14, 0x42, 0x95, 0x11, + 0x6C, 0xDD, 0x67, 0x9D, 0xE7, 0x50, 0xF7, 0x84, 0x04, 0x7D, 0x5A, 0xE4, + 0x06, 0x8A, 0x57, 0xAB, 0xFD, 0xFA, 0x5C, 0xA4, 0xA9, 0x09, 0xC8, 0x66, + 0xC7, 0xD8, 0xD3, 0x0C, 0xEA, 0x49, 0x19, 0x40, 0x00, 0xAD, 0xA2, 0x03, + 0xC8, 0x2B, 0x20, 0xD4, 0x6E, 0xBE, 0xCC, 0xED, 0x08, 0x61, 0xC0, 0x27, + 0xC3, 0x82, 0xB0, 0x57, 0xFE, 0x79, 0x8E, 0xD4, 0x1B, 0x16, 0xEB, 0xCA, + 0xEA, 0xA7, 0x81, 0x0D, 0xD6, 0x03, 0x0E, 0x2A, 0xEF, 0x88, 0xA3, 0xEA, + 0x8D, 0x03, 0x82, 0x0D, 0xB6, 0xAC, 0x4A, 0xA5, 0xBC, 0x7E, 0x85, 0xD9, + 0xF7, 0x89, 0x9A, 0xAE, 0x7B, 0xE6, 0x54, 0x88, 0x78, 0xCE, 0x9B, 0x73, + 0xA1, 0x7F, 0xA9, 0xB2, 0x70, 0xA4, 0x0C, 0x38, 0xCD, 0xE1, 0xD8, 0x02, + 0x65, 0x58, 0x42, 0x12, 0x56, 0x62, 0x5E, 0x02, 0xEA, 0xC1, 0x1B, 0x65, + 0x78, 0x0C, 0x0C, 0xAF, 0x53, 0x5A, 0xEF, 0x22, 0x24, 0x12, 0x74, 0x53, + 0x11, 0x60, 0x83, 0x0E, 0xA4, 0x6F, 0xC1, 0x6E, 0x4B, 0xF3, 0x8E, 0x6B, + 0xEA, 0x88, 0xCD, 0xAF, 0xAD, 0x29, 0xFC, 0x6F, 0xCD, 0x2D, 0xAF, 0x5E, + 0xB7, 0x25, 0x9D, 0x4E, 0x20, 0x73, 0xA5, 0x53, 0x8B, 0xF2, 0xAB, 0x7A, + 0x68, 0xE9, 0xDF, 0x4F, 0x9C, 0x6E, 0xC1, 0xDD, 0xB3, 0x21, 0x5B, 0xFE, + 0x48, 0x55, 0x25, 0xFF, 0x18, 0x22, 0x7C, 0xDC, 0x36, 0x84, 0x0E, 0xD7, + 0xD5, 0xEF, 0xC9, 0x41, 0xFA, 0x2A, 0xBD, 0xEF, 0x0A, 0x8A, 0xEB, 0x8A, + 0x92, 0x8E, 0xD4, 0x0A, 0x83, 0x68, 0xFC, 0x60, 0x63, 0xF1, 0x9F, 0xD0, + 0x61, 0xD2, 0xEB, 0x30, 0xCC, 0xE4, 0x14, 0x50, 0x95, 0xA8, 0x8F, 0x91, + 0xB4, 0x4E, 0x6A, 0xBE, 0x71, 0xD0, 0x3E, 0x72, 0x7F, 0x1D, 0x6E, 0xAE, + 0x8F, 0x04, 0x62, 0xD0, 0x7D, 0x4D, 0x52, 0x12, 0x8B, 0x8E, 0x15, 0x67, + 0x51, 0xD8, 0x4F, 0x9E, 0x80, 0xBF, 0x3B, 0x48, 0x2E, 0xB3, 0x4E, 0x1D, + 0x28, 0x30, 0x4B, 0x6C, 0x5C, 0x0B, 0x68, 0xEC, 0x91, 0xCD, 0xB8, 0x6C, + 0x1F, 0x73, 0x5A, 0xB7, 0xA3, 0x97, 0x6F, 0x1D, 0x76, 0x0E, 0xBD, 0xB8, + 0xF7, 0xA9, 0xDC, 0xC2, 0x54, 0x62, 0x2A, 0x56, 0x58, 0xCE, 0x53, 0x9A, + 0xB4, 0xD0, 0xB9, 0xEA, 0x1D, 0xB6, 0xF7, 0x11, 0x21, 0x40, 0x95, 0x14, + 0x41, 0x20, 0x64, 0xEC, 0x09, 0xC9, 0x46, 0x97, 0xFA, 0x58, 0xE6, 0xC0, + 0x0A, 0x51, 0x10, 0xBB, 0x5B, 0x14, 0x3E, 0x3C, 0x42, 0x2A, 0x6A, 0xEE, + 0x69, 0xF7, 0x53, 0x6A, 0x97, 0x4C, 0x97, 0xA7, 0x53, 0xAF, 0x07, 0x0C, + 0x13, 0x4C, 0x07, 0xB2, 0x7B, 0x87, 0x9F, 0x1E, 0xF7, 0xE3, 0x27, 0x94, + 0x45, 0xBA, 0x26, 0xF4, 0x32, 0x4D, 0x90, 0x8B, 0xF5, 0x1D, 0xE8, 0x5C, + 0x46, 0xF6, 0xDB, 0x36, 0xED, 0x12, 0x1F, 0x7E, 0xC7, 0xF5, 0xBF, 0x59, + 0x75, 0x0B, 0x15, 0xFA, 0x56, 0x62, 0x2B, 0xDD, 0x48, 0x25, 0x0A, 0x4D, + 0x81, 0xDD, 0x67, 0x18, 0x4D, 0x73, 0xC4, 0x3A, 0x10, 0x4C, 0x72, 0xDE, + 0xFE, 0xC0, 0xE0, 0x96, 0x24, 0x89, 0x4E, 0xF5, 0x1B, 0x82, 0x4D, 0xD2, + 0x7A, 0xEA, 0x92, 0x83, 0x7E, 0x83, 0x3B, 0xF4, 0xCF, 0xFD, 0x0D, 0xB2, + 0xD6, 0xDD, 0x9C, 0xC8, 0xCF, 0x42, 0x95, 0xE9, 0x0B, 0x54, 0xDE, 0xEE, + 0x8B, 0xA0, 0x3F, 0x5A, 0xEC, 0x48, 0x28, 0x75, 0x06, 0xC9, 0xBC, 0x7B, + 0xCA, 0x9A, 0x35, 0x11, 0x28, 0xB9, 0xCF, 0xD7, 0x00, 0x84, 0x6B, 0xBC, + 0x92, 0x64, 0x78, 0x8C, 0x2B, 0x2B, 0x69, 0x34, 0x60, 0xEF, 0x25, 0xCC, + 0x79, 0xF1, 0x63, 0x50, 0xA1, 0xAB, 0xED, 0x07, 0xD5, 0x51, 0x40, 0x26, + 0x6C, 0x9B, 0x67, 0x2E, 0x8F, 0x38, 0x6D, 0x19, 0xB0, 0x0E, 0x97, 0x41, + 0xDE, 0xA6, 0x5A, 0x19, 0x35, 0x38, 0x03, 0x99, 0x60, 0xA2, 0xEB, 0xCE, + 0xF4, 0xB3, 0xCB, 0x5C, 0x32, 0x9B, 0xA3, 0xBE, 0xCE, 0xB5, 0x7F, 0xD9, + 0x5D, 0x35, 0x5F, 0x0B, 0x17, 0xEF, 0xF4, 0x59, 0xBE, 0xC6, 0x31, 0x60, + 0xBE, 0xC4, 0xAB, 0x2C, 0xA9, 0x02, 0x26, 0xFA, 0x79, 0x30, 0x3A, 0x5D, + 0x81, 0xFE, 0x8C, 0x8A, 0xAE, 0x8F, 0x79, 0x43, 0x61, 0xA9, 0x91, 0xF4, + 0x96, 0x52, 0x47, 0x87, 0x26, 0x7B, 0x8E, 0x04, 0xDF, 0x22, 0x33, 0x1A, + 0xA3, 0x68, 0x17, 0x20, 0x4C, 0x33, 0xAD, 0x11, 0x16, 0xEA, 0x89, 0x2E, + 0x5F, 0x52, 0x46, 0xC0, 0xAD, 0x96, 0xDE, 0xD0, 0x27, 0xB3, 0x05, 0x46, + 0xA8, 0x1A, 0xDA, 0x38, 0xF1, 0x8B, 0xF3, 0x16, 0x9C, 0x94, 0x69, 0x86, + 0xE4, 0xC3, 0xED, 0x4F, 0xB0, 0xC4, 0x02, 0x4D, 0xBD, 0x2F, 0x4F, 0x55, + 0x6A, 0x39, 0xE3, 0xDF, 0xBD, 0x87, 0x88, 0xB8, 0xCE, 0x8F, 0xB5, 0xB3, + 0x4B, 0x82, 0x36, 0x86, 0xEC, 0x65, 0xAB, 0xE6, 0x87, 0xA6, 0x86, 0x5B, + 0x09, 0xE6, 0x2B, 0x08, 0x4F, 0x35, 0x95, 0xDE, 0xC9, 0x9B, 0x69, 0xF3, + 0x33, 0xF6, 0x93, 0x0E, 0xB3, 0xF4, 0xDC, 0x4E, 0x71, 0x99, 0x22, 0xF9, + 0x09, 0x0C, 0x6D, 0x4C, 0x02, 0x7D, 0x3D, 0x45, 0xC2, 0x02, 0x78, 0xE1, + 0x0A, 0xBA, 0xA3, 0xA7, 0x80, 0xA9, 0x71, 0xA0, 0xA4, 0x3E, 0xDD, 0x0F, + 0x09, 0x61, 0xDE, 0xDF, 0xFD, 0x3D, 0x1A, 0xD8, 0x32, 0x4B, 0x46, 0x33, + 0xB4, 0xBB, 0x5E, 0xCE, 0x77, 0x26, 0x27, 0xDF, 0x51, 0x24, 0x91, 0x36, + 0x6C, 0x39, 0x37, 0x6E, 0x5A, 0x0B, 0x07, 0x26, 0xE6, 0x15, 0x11, 0xB8, + 0x64, 0xD6, 0x75, 0x57, 0x32, 0xE9, 0xA8, 0x87, 0x55, 0xE5, 0x9B, 0xA3, + 0x46, 0x3D, 0x69, 0xBE, 0xEE, 0x13, 0xA6, 0xC8, 0x94, 0x06, 0x34, 0x56, + 0x8C, 0x16, 0x71, 0x8B, 0x9B, 0x78, 0xDF, 0x91, 0x52, 0x8B, 0x4D, 0x2D, + 0xE5, 0x32, 0xC8, 0x93, 0x72, 0xF8, 0x8D, 0xBF, 0x59, 0x86, 0xE8, 0x9B, + 0xE6, 0x39, 0x60, 0xA8, 0x12, 0x6C, 0x91, 0x3E, 0x97, 0x71, 0x04, 0x6C, + 0x95, 0x1C, 0xC1, 0x16, 0x5B, 0xB1, 0x36, 0x8B, 0x9D, 0x18, 0x52, 0xE6, + 0x9B, 0xAD, 0x18, 0x9E, 0xE2, 0x13, 0x4B, 0xB7, 0x78, 0x67, 0x11, 0x2B, + 0x76, 0x2B, 0xF3, 0xFA, 0x5B, 0x06, 0x48, 0xA6, 0xA4, 0xFC, 0x5A, 0xCE, + 0xAC, 0x27, 0xE8, 0xFD, 0x08, 0x97, 0xA6, 0x01, 0xC7, 0xA8, 0xF8, 0x23, + 0xB1, 0x5A, 0xCC, 0xC5, 0x65, 0x91, 0x7A, 0x16, 0x1F, 0x99, 0xCF, 0x9B, + 0x1C, 0xF4, 0xCA, 0x4D, 0xB2, 0xAF, 0x9F, 0x37, 0xEB, 0x97, 0xD4, 0xE7, + 0xC9, 0x01, 0x7D, 0x60, 0xE0, 0x85, 0x27, 0xC0, 0x25, 0x21, 0xB9, 0x1F, + 0x6B, 0xE6, 0x4D, 0x59, 0x79, 0x91, 0x0D, 0x1E, 0x84, 0x53, 0x1C, 0x11, + 0x61, 0xFC, 0x9E, 0x25, 0xA9, 0x25, 0x90, 0x7B, 0x34, 0xB4, 0x27, 0x19, + 0xA2, 0xD7, 0x9D, 0x2C, 0x96, 0xF5, 0x90, 0x7C, 0x47, 0x28, 0x33, 0x84, + 0x3D, 0xF8, 0x42, 0x1C, 0xEA, 0x52, 0x5A, 0x18, 0x1B, 0xAA, 0xB1, 0x23, + 0xC7, 0xA1, 0xEE, 0x40, 0x63, 0x93, 0x15, 0xC9, 0xFA, 0x87, 0x7C, 0x1C, + 0xF5, 0xC9, 0x8B, 0xF4, 0xD9, 0x06, 0x5B, 0x2D, 0x35, 0xEB, 0x19, 0xC5, + 0x43, 0xDA, 0x28, 0x38, 0x4D, 0x70, 0xC5, 0x65, 0x99, 0x9E, 0xFC, 0x7A, + 0x68, 0x72, 0x04, 0x30, 0x4D, 0x65, 0x02, 0x6B, 0xF8, 0x89, 0xA5, 0xA3, + 0x8D, 0xE4, 0xD7, 0x38, 0x88, 0x3A, 0x40, 0x6C, 0x49, 0xA1, 0xF9, 0x7B, + 0xEB, 0xB2, 0x48, 0x16, 0x08, 0x14, 0x45, 0x13, 0x78, 0x30, 0x41, 0xAB, + 0x14, 0x03, 0xEA, 0x77, 0xD9, 0x1C, 0x9D, 0x94, 0x36, 0xEA, 0xF6, 0x07, + 0xDB, 0x3D, 0x7F, 0xDB, 0x59, 0xE3, 0x7B, 0xAD, 0x49, 0xEC, 0x22, 0x38, + 0x98, 0x92, 0xF5, 0x44, 0x8D, 0xAD, 0x27, 0x5B, 0xE8, 0x72, 0x3F, 0x2B, + 0x0C, 0x1B, 0x5E, 0xCD, 0x1F, 0x51, 0x9B, 0xE1, 0xF8, 0x35, 0xDA, 0x06, + 0x66, 0x2F, 0xE5, 0xAD, 0x2B, 0x09, 0x15, 0x8D, 0x81, 0x3D, 0x39, 0x7F, + 0xCB, 0x50, 0x25, 0x6F, 0x13, 0xF6, 0x46, 0x88, 0x34, 0x60, 0x3C, 0x7A, + 0xFA, 0x90, 0x95, 0x50, 0x81, 0x4F, 0x18, 0x29, 0x74, 0x7A, 0xD2, 0x25, + 0xC8, 0x28, 0xB6, 0x28, 0xC2, 0x80, 0x8B, 0x8F, 0xCC, 0x06, 0x83, 0xFF, + 0x5C, 0x8B, 0x32, 0xAB, 0x79, 0x45, 0x2C, 0xA8, 0x3D, 0xD2, 0x5A, 0x49, + 0x8A, 0xAB, 0xF0, 0x07, 0x88, 0xC2, 0xEF, 0xDB, 0xD0, 0x4B, 0xDE, 0xA9, + 0x50, 0x4E, 0x21, 0xEF, 0x2B, 0x3D, 0x41, 0x4C, 0xF9, 0x39, 0x29, 0xD0, + 0x05, 0xF2, 0x71, 0x42, 0xBF, 0xA8, 0xA3, 0xAB, 0x5B, 0x63, 0x23, 0x3B, + 0x97, 0xA4, 0xE4, 0xD5, 0x91, 0xCB, 0x34, 0xF9, 0x71, 0x25, 0x29, 0x54, + 0xB8, 0xFF, 0x07, 0x31, 0x2B, 0x0A, 0x50, 0x72, 0xD3, 0x68, 0xEC, 0x3A, + 0x8F, 0x9C, 0xC0, 0x5C, 0xD8, 0x59, 0xF9, 0x6F, 0x02, 0x41, 0x85, 0x01, + 0xC6, 0x29, 0x22, 0x4D, 0x64, 0x4D, 0xF9, 0xB0, 0xDA, 0xF9, 0xA2, 0xD1, + 0x8C, 0x62, 0x77, 0x97, 0x38, 0x6D, 0x62, 0x6E, 0xBB, 0x23, 0xEA, 0x22, + 0x64, 0xBC, 0xF6, 0xAE, 0xCC, 0x8D, 0x01, 0xC5, 0x69, 0xF0, 0xD6, 0x3C, + 0x1F, 0x86, 0x1F, 0xA4, 0x24, 0x39, 0xBC, 0x93, 0xBF, 0xF1, 0xB5, 0x66, + 0x45, 0xB5, 0x20, 0xC9, 0x67, 0xBE, 0xBC, 0x79, 0x79, 0x13, 0x1C, 0xFE, + 0x62, 0x1C, 0xC2, 0x93, 0x74, 0x6A, 0x87, 0x14, 0x6D, 0x28, 0x87, 0x95, + 0xC3, 0xBB, 0x0A, 0xF7, 0xF1, 0x28, 0x87, 0x4E, 0x7F, 0x46, 0x6F, 0x20, + 0x99, 0x9D, 0x18, 0x00, 0x15, 0x28, 0xCA, 0xCD, 0xC8, 0xB1, 0x97, 0x56, + 0x75, 0xA7, 0xF4, 0xA4, 0xD0, 0xE5, 0x62, 0xE3, 0x87, 0xF9, 0x57, 0xB7, + 0xF6, 0x21, 0x88, 0x1F, 0xA4, 0xC5, 0xC8, 0xDA, 0xFF, 0xCA, 0x88, 0x8C, + 0x18, 0x50, 0xFF, 0xF6, 0x05, 0xBF, 0xA4, 0xEF, 0x2E, 0xDE, 0x32, 0xD9, + 0x64, 0x1D, 0x26, 0xA5, 0xD6, 0x50, 0x12, 0x30, 0xCA, 0x05, 0x0A, 0x5B, + 0x43, 0x5E, 0x07, 0xC3, 0xE2, 0xCD, 0xD9, 0x6B, 0xB4, 0xB8, 0x21, 0x47, + 0xD6, 0x65, 0x19, 0x98, 0x00, 0x06, 0x17, 0xEA, 0xB1, 0x8B, 0xA1, 0x88, + 0x66, 0x61, 0x06, 0xC3, 0x01, 0xA9, 0xAB, 0x72, 0x4D, 0xFE, 0x96, 0x6B, + 0x36, 0xBD, 0xEE, 0xB8, 0x61, 0x85, 0x1D, 0x4A, 0x44, 0x88, 0xE4, 0x63, + 0x04, 0x14, 0x17, 0x49, 0x4B, 0xFA, 0x9C, 0x27, 0x1D, 0x93, 0x2A, 0x10, + 0xF1, 0xD1, 0x70, 0x56, 0x3F, 0x92, 0x92, 0xAD, 0x50, 0x50, 0xF8, 0xA2, + 0x47, 0x93, 0xBB, 0xF5, 0xEC, 0x20, 0xC8, 0xBB, 0xF4, 0xD8, 0x9A, 0x3D, + 0xF0, 0x92, 0xDF, 0x65, 0x10, 0x6A, 0x9E, 0x52, 0xF8, 0x58, 0x01, 0x8E, + 0xC9, 0x24, 0xBB, 0xD7, 0x68, 0xCF, 0xA1, 0xF9, 0xD1, 0x4E, 0xD3, 0x88, + 0x29, 0x7D, 0x7E, 0xA8, 0x4C, 0x75, 0xDB, 0x96, 0x59, 0x09, 0x91, 0x1C, + 0xE0, 0x3A, 0x92, 0x5D, 0xF3, 0xFE, 0xE0, 0x70, 0xFD, 0x23, 0x5C, 0x3B, + 0x47, 0x91, 0x8D, 0x64, 0x1D, 0xA3, 0x3A, 0x98, 0x53, 0xC1, 0x93, 0x1E, + 0xB0, 0x95, 0xD4, 0xB5, 0x01, 0xAB, 0x22, 0xC1, 0x6B, 0xA9, 0x82, 0xBE, + 0x78, 0x3E, 0x25, 0xF1, 0xCA, 0xEC, 0x08, 0x4A, 0x72, 0x68, 0x3F, 0xC5, + 0xA8, 0x9C, 0x07, 0xD4, 0xCE, 0x87, 0xA0, 0xC9, 0x5E, 0x2D, 0x18, 0x27, + 0x9A, 0x8A, 0xD0, 0xB9, 0x8E, 0x60, 0x3A, 0xFF, 0x4C, 0x8E, 0xC1, 0x70, + 0x0E, 0x12, 0x17, 0xBA, 0x87, 0x8F, 0x3E, 0x01, 0x85, 0x7F, 0x7F, 0x90, + 0x4D, 0xAC, 0xA6, 0xB8, 0x36, 0xA1, 0x77, 0x7D, 0x2B, 0x26, 0xD6, 0xEF, + 0x57, 0xED, 0xA0, 0x13, 0xA2, 0xE3, 0x52, 0x4A, 0x63, 0xC9, 0x73, 0x6B, + 0xF9, 0xAA, 0x24, 0x4D, 0xC9, 0x36, 0x51, 0xFA, 0x74, 0xEF, 0x6F, 0x4D, + 0x31, 0x08, 0x06, 0x4F, 0x12, 0x20, 0x73, 0xCE, 0xDB, 0x8E, 0xEB, 0xFC, + 0x73, 0x7B, 0xC4, 0xA8, 0xFA, 0x15, 0xAB, 0xBE, 0x99, 0x02, 0xA8, 0xCA, + 0x48, 0x65, 0xC2, 0x6A, 0xFA, 0x0B, 0xA9, 0xB6, 0x7F, 0x25, 0x3D, 0xEE, + 0xDF, 0xDA, 0x44, 0x2B, 0x86, 0x28, 0xE6, 0x2E, 0x6A, 0x6C, 0x6D, 0x72, + 0xFD, 0xD3, 0x69, 0x40, 0x9A, 0x07, 0xD0, 0x71, 0x3D, 0xF5, 0x03, 0x5F, + 0x48, 0x5F, 0xBB, 0xFC, 0x2A, 0x57, 0xD3 +}; diff --git a/res/logo.bmp.lzma b/res/logo.bmp.lzma new file mode 100644 index 0000000000000000000000000000000000000000..de64feaa2f08111296ab7e18c1c168ff171f4836 GIT binary patch literal 3076 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 S&#u0>MFc8lVQ&Ba!xfp!aPwvW literal 0 HcmV?d00001 diff --git a/res/logo.bmp.lzma.bck b/res/logo.bmp.lzma.bck new file mode 100644 index 0000000000000000000000000000000000000000..24dbaca50cf2358c0884f4cdbc3cd3749d659e6b GIT binary patch literal 2731 zcmV;c3RLx7004jh|NsC0|NsC003j1n7ZwIE_ZL_|3sd=YYC5yRuYfcjGa)dExK&3#Wf^oh8z zakAAfMyU)CzK!jErRUL~bK(<&y_amy_+(yfCL?8ft1uAZau@`I)BODn5tss{!rhzY zlvZ*lO$!|GcuQ%Fkhj!_i^4|iAI6DJIvBJNUv;P+3&LlA1}>O6@XlIqe`Dg0(hJd= zu2jm(2P#%(4hgVf=N21n=ZH(8l=fPuy(a@)&nbbjjZ$2z6s;Ofq3kPK6~+Wjk4?VcO`^f1ED za88y^22)ndx3X?Z4u$!wHwdi9z!L2ijf-U!?H8jVp;1fmFU1Ar#Uh;0xC8dzasrnk zuLV>9^*GuXe}r1r)hKFVS8}Wh=5uq=C$XU>1iA}{Gn>@7Mag4@L`7o*)?sZ&ENRMQ zB1kXjPr-BKt~LC3-&*#*J#X)J1U7tKCM1Cd*wtqm0V&sH3hME)vjSEuM(=Fg53&XB z>h3D-AL;tnz(vgVG7WP}PBA^3%=RJrTn-Zrl&D$V&>Pkz=&Lwo`0|6!21U={wMlFm z@1*!@)3>E|916M9M>m{Dld}=_e^UOH%H?|kc|`;< zkKms}_a+O$3}~|jBJBE3uWYA~LC9e=CA+8aHVHG;_C)*Y?B&@=V<@EEdab}Qpv~OH z2`S6{$e!jv*;-qhMi3vE$h83JwXJn?>a*f|AsZq*Tpx42mc-#LVy5aG-Z6inf@vD) zux7=6$M9(s&_ol^nlT47Rq63>2&KV>9dO(92A} zPO0%SNkOMm-A|(pYQTr`G&`Y;@&GkH!p}Y~;n0%jzSW1qvW*VC*#AkoB0M&OWUveE zDkz+Hj77Y0_asx#{U>@~@^;4p1$6>|J2TuHEG?SS;gHSVh4XW^5cpQKzJM>l0Fgnq z>pPvAfiM6E$(**9{D+@I-O{&HXMr=%6`P+3S_fO?HI>2fS4oFkM4iczLAAnkL2s@l z&Zmhv>27Ysj^cNNdV5GVgxZ-IcHH-BdixJ+zqAbX{p}l)JG4-PtokU_OOX~i3tzrj zfDR~LV^FS%W7rU;N~jPNLX{D0-DjQWQ1^rceOlxOidU=s`dp-`3CL#0*wYN^Nf|%@ zt)c_SDEBPBZo%ENAzS`PRVDuzB7EF7 zgbvr$@5w>>D!uOtitCD!j?@Z+X#8Mf@t@FP((5qHXL(ggFE!k{SC6#-JHnJLY3(YRNn53pg&sd zNGNp%$-H~Ynl%w9xzE=CgloK#WO$4#D`_-f?N#H%c+0w(%-Fgjg< z{)~#Qk9k93sgd-SQb&g-dyWL(A~PDJXcr(%Gp!L8>WMC2Qbxe7mfp}Ovjs+|8rnGV zi}Mzolxc?K!|hM7!~#vdFHco!Ipg2Ghlse&kF~Q)f;NWiWvk|griNPy<|_zKHI?4U zn`!ei_LB~?^xRHynIicK3~fvTeLY3O0(jvHx}&Fnsd1pBKHU!qVcy^UJsQ|DOGY!a zyI#(BCMVxfB#}03IX7-v3kN3V6%n{()^%4h>8OWQ<(s2MJ!!t~6Q;I3=hUlB-Ibf&~Y>_^faRh9Y9KjY_u{MjH7*gh&tr(u-6HB*v zXAvuQEA#qW21ur){94YeC+PhMm!<*7sQ4qXTFk{|k$M&%na`UX^vX@Lub(&Tm(=IU z0exWLg(tuzA-NxG=1p07kqsV%QydXt{GKJLC6IeGv?m#&*PSeu^^kl=C^LjT_(B}& zQd$@rs<9)-q3%FqlNHJOhkP9M$&2*a23svP>lwvE+9)_paK&Yrp8R@fas)6h=fQJ%8I-<9n@1>>@ar zlJ!K5ttVUPaz85!8(z&HQJdlTHQEMdFXgQ(2^EcjJvo2NP$h2@_C|;_U_5&Ikd;t@ zPZ%k5deSAxD7GlVfQygJ27~`xi!!TuMJ%X2(ppK1tMCVi!tdMAOWvtaP9g6rJwZ(Q zIVsQu@^M1HsH3Y}VXzV(VoWNYzS@~}QL4^Uv zDI!f|P5H3e`J&N`Vt1D~ZDMY_BkCe#y!NiljRD1J@YXyZh99IPIlPm<@wH|}wIIo7 zzPx#P6CD0x9Kw@yYKIhUD2J89y9)R5D2GmeMsFaQofrTWD9X*qv6ohLr}U)I>qdJ&V!IK`amDIHXt0KW`se-v6|26P0;tMJWx{Iu3#qn$ lB|Yxn+C(dcDCRC|Y;AJ=(`i7O2hedn^#fl>U%UJ&SJU+~M&$qi literal 0 HcmV?d00001 diff --git a/res/logo2.bmp b/res/logo2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7a79e63568fa8a4b331d0a0bdacf3a648d373575 GIT binary patch literal 11112 zcmbVS33yahnmuo+)RM|-K_Cg3jX>BT2@nvPeNjY2Q0Nv!1Y8hN3@VP$ASy-?Yz03Z z(Y6)QMqALfwXxN4O;8~NX>`zbnHjrh{B&$}MiGhn&H3+r@71lMh_*?+SGQiJ&iViI zFZaG%8GGsleV~4ZxIizC_V75LhlL0aU~o_1pSLYD=7KPEf3!ixmD0R^%5kbGs5ezB~p{`pN1{Y;xP;mtH#ZlCkMlqyI9K%Yo zF`|1mhIP%sNhP@$QJRBMrMajtbJ0+dg@!5@qk4oesyv3#-E%O$djUpQhcU5V2vhoJ zVM28bW6I+gUlGT+syHU_m{J|bq+T&hsfps`z7b6A7s0fe9L(&ShtujEOdAx&w1E*! z9~{Pv`Yg;G62hzo7js6qm@znlId$1MyCI5+<@uOgk&jcV3NWQCfoT<;aC%iIoYkig zv-=g`=QTx`*FS-|y^1k+PyrT>iegc}63nkH#QZ@CoL85?l3_dscEgI1MOa?f9gQQp z;PL@gxNJ~48V6QkWqk#%s;$DR+MZZlUyW4_F@LOs#S2e@xNK4kE2c(p&8cy$nBm}`X1Q2Bo6loAW7U{0STnRIt{+u_wGBOR z-H0k&Ke7r&}SdrZaPJ-RuZ%o|BC&^Kx;+l&)x+Qi2Vq zlwjjj9+SKCxfHja+#R<~?S{?My5ZJ2`S|tOMYv-|3GSF)io0eN_`}W}b+9 z=5*!zUGSTEopImXF4%CMjg5dzmPKJ~SrEh4g>l@wB!au==i`AT+4$YETs+w5 z;NdH6{C1^{9hXP2>xw9zSe}bNtjNWaS7qa=RS`UWRStHqisISTG3;KMgFjsp$Fr;A z*nWNi?w{Wo+s^HT?F$ol`1}*_@Ztn^Tv&)lFDk@iOAD~$f&?C0)D^py<>Scs4$_){`xF(KQ z*TwP1`Z$_zjNtW~V%T?6HeSCmj=fEB9M~Ae!A;p{+YraWjd8TxYGDtL*4u2fZnm-S zS1t~0v9bSl7yCE6XuH$G!MiNHd22Qf-5$f+TcUXP&Inr86ymjO^YOO_9DKCh#wRPd@b&LcfmOXFU+! z4(FkVw!wWc>mZ!>-hU6F_pLXrH$#W4cdU1!e}VJ)=byvR(RN;0z23Icl5B{;wfxLj31A8uA z5nmF4FWLpe7y9AA24WV%VzXvNk>`WD3 zlqB&JGc!g*c|gW6O&7iRy7D;IYstLG7^-Dy)hK}POH#38qVFsAqxm$e86}kwhH_*> zfuCK;WD6Z9*N(4TgpPMNvW&Q0RLXj}s{$`MW`R1X+!`cWY5!#)W1jpg-q^pO-Vbu1 zFoj7~%L()%aKIx%3X>+t#KeS^H~k04sZ3s$O$AEQ5-jN!YsO>irffYPn?!?A7d9!i z@=TF8NVF$~6voxr#gA%eLn+h#W1_9J(jFuxQvXPLWLSBs`ibjjuuupKAAC+@q&i6- zl3hl30)wq+9C(cig#z6a5sRJ>d`QXjLEWTo6pbeQLDrr|{23L+qB`a=%B9wfU!UTe za?JCPgv2Hnl9Q?E-K-m#zR{!Aq~h+1$3-t)_IQ=HWVDeNg~ntn;Fs9YL$ z{3qf1Q8IfPbxWk$t@9wyLa~S;_UeaeH6tHaZtx_3mF>*{CbFT7%wb-3sT>1jwo>Zw zxxZo{PDUzCt5`HwZ=+T^;9zbU9DOy1?@jo%k8XwIKMM z?}F4sFb4`Y;esxr)X{mv8uVgHVYD{1HpF@eD#27kj{`G3Tyh0-dk#Noc3$GM^J;KY zdm*6Z)SPI_@sxq4(D(tJZ4K;L5faE;A&2Veeq?(Igd*|ilpp#E$@vZsd0*xYKReCd zF;Zv0-#;jkc*G~(D#}Mw*mTF`Ma7t;)qVsWaj@Zw;1fzJ%)<_I6{L~9KJNRH@NLy_ z`s_!*#AHtDY7N9Ev@3ZpRm<^@w3FE0459jg?%hShlif6h#ZFhHTGY`GPvnfU$m~-u zigQVjj#!?oVAFap?}M(d zNd(=WRcNo5N5_bwoe1)s91btR?3+J99eodQybwU?(?N7a7d3)KgM> z$x1mSs%Cbk=|VuGuKaxb0ZV<&jeIN`0M;78)G8%eSG+G#Ryqu-cr^osMB7X_~e)e$CGlSlv*8PPK9q&ZA^l*JO?@rF8;MCuF_d3Y%z z@tT?Wxys}KkuyiWjziLJKgztzv3eQ(t(=|SDK9T~5oISW9yzKLJ?Ux{_U^3~DP%1e zFkk@ht&~)%*+$*r!-qRUDe+;M<~0m&ke5m^r(whhmA$qzY{W3>j`Fa(&zr|=p%vk7 z=bUrS{Q2_{nrkhv234fnGNZ9^G^aC!+<$3l8OcPTH4|Qa{S?uZ_rz;jTbDQ~*2I4Q zhu@P%Tf-^8ba&hC6Mbu{+S~tCTND0|kN+z>O#ayW-+aSVm5gx~eETij@3OwPwkkVx zJQEdU|5;<>nGV7noz&9uT$oz{$P3JHPHk;nACo&9se)*_1@?7qZHs*iR<^fqR`a^8 zEMPXpsK@Q!C?gp21@5=jcUDFl+~tjpMPh?Hy`^OuEyzzQ(R**}-rl^&MxIXMG#hNI zp{?!dsE$eOnfCSu!-g!*r1Or51!3E&j9lPeXq|2NUsOrPiH(g@$XJr|LQ6}Tlnf8w z|Jb^Ht*5dV(0A2iR3``wU`}+mZ7XYM+x`*Yz_up0w{Oof_~~`2^;h>Bt8!>cz9W=q zY`i>2VqP-7rR7rIyQoqk?<5-FEZNt34Y^cTkYqSU`$C~RudVHRM+VNF?d?}k?+8^0 zw0G_~qCB^CAN3+mk3-HGjg4ctFhSIr)6z0Q@=abz)K9OjuAaJg-<}gl>g{W=_n96m z=G@);_n#=t-4C?4S0|e_PZSZDequBk12Z9M@K%Y+?L9lAa9jq zS23NO(%dqK!4yF??;DDDUn}=V8OxsXhHwS$2E-4}M}l@_ z=QlP^1In74U&xWTCzKw_BBjjMf~;J-O`wjbOoVk*KJNiFvo#!LY+$ zzt1idsFCxFe>-&Ot+(EK`|VFZ{dBHOoW3H;68ntCa$s6>%XF22az9EtL>CDJtdmm=!`|Jq&ZEu>^s>jK_L z2KNp%+(pc3Y;G<#czYvsI-;kYzU10{oI}EXH!_i&CQo^0ipz!1Y#e1T}pf3zJ0ChPYn84B9p+% zr!7a1E=HW8cUFG<$rk$S`^iem(v=kc-uko2%kMACoLSAy<5l)}k)80$%P;TQv*(RH zd#*W|GV6U>uCyeubU}iw6NwB_t91W?0~Nd^n#=rU5B=|tx8;h@RQbq}O4$})5c$?k zowH@m()agvPEHQXHJcg_w z*#~rS%C{gUo>DbUfe!5RcG-NNi7vLOMCjN?s;c&pW*HUL7m&SlGfZmidF;>69mdGi zka$G~9*xtlL<9exmfca-6=@!)#{6U>k7V5@D2z96p|q{^)Z0blh^u3jKHizwDe&UN zybO4ZjavB_&T|q})x;j%0iq^I&-&CXN>f#4SKXWZSkWc9_X||epq}Yc4ls08Yu64n z=rH~oTWR1~$vBy{L*t|>Q}SFaJI20DdFjW8dIqZtHKEJCKlNmDEHm`f#-#b3g6q|| zfg8k0<+ejBQi`t;|bR^M}3mB4c>%p{jiY-(x?{ z`ASg(RqlXOR5bFD7UpRSnd=N1DTR#78oH z)cfQCL@)?UBOu2e`Ox)vKnaM@>y`k8mG2ef#!7LEl)v zaDOEn4{QWMC$4W*VQ#N)aBR18B#wKA^x{k(NODF^^Ms~>*t}_*2UJv zp-bQ_Teb|LORc5WQvPq+bJla==i$8g;xFN@b+3iP|4l>IdW4#qnr^xYp&KI`+)W5= z+_Z7y4rIxHr#<>8+{Z#sz}>lP*RHI`ttZ1zSx-mr3vag`avw(M!3Pf>Jc!VHq4yE{ q;DZl7{P4p=A0B!q{1@w8>)ou+t-puAK={iqzx?W}ulO%%*8c;zHbeRV literal 0 HcmV?d00001 diff --git a/res/logov.blz b/res/logov.blz new file mode 100644 index 0000000000000000000000000000000000000000..ce36dafc8ffd31cc22660215e7cd00e6c5c711da GIT binary patch literal 5040 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 I+GvFS12`F}0RR91 literal 0 HcmV?d00001 diff --git a/res/logov.bmp b/res/logov.bmp new file mode 100644 index 0000000000000000000000000000000000000000..124a9e9c81b381eae026b22b3cb8d6fe2f167e68 GIT binary patch literal 21878 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 literal 0 HcmV?d00001 diff --git a/res/logov.rgb b/res/logov.rgb new file mode 100644 index 0000000..b749726 --- /dev/null +++ b/res/logov.rgb @@ -0,0 +1,57 @@ +€²ÈÇÇÇÇÈÈÈÇÇÇÇÈÈÇÇÇÇÇÈÈÇÇÇÇÈÈÈÇÇÇÇÈÈÇÇÇÇÇÈÈÇÇÇÇÈÈÈÇÇÇÇÈÈÇÇÇÇÇÈÈÇÇÇÇÈÈÈÇÇÇÇÈÈÇÇÇÇÇÈÈÇÇÇÇÈÈÈÇÇÇÇÈÈÇÇÇÇÈÈÈ€²™ÔcŒFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfFfeŽ˜Ò™Ô9U=Z˜Ò™Ô5R y¹ |»1N        *C}¶ •Ù •Ù •Ùe•*2P y¹ y¹1N Im ŽÑ •Ù •Ù +ŠÊ@a2P y¹ y¹1N1kž •Ù •Ù •Ùsª$92P x· y¹1N6T„ •Ù •Ù ŽÑPx#2P x· y¹1N&X„ +Õ +“Ø +“Ø }¹.I2Puµ y¹1N%> v° +Õ +Õ +Õ`*2P x·uµ1N Ei +ŠÊ +Õ +Õ†Ä<]2Puµ y¹0N1 e˜ Ô Ö +Õ n¤"92Puµuµ0N* }¹ ŽÔ ŽÔ ŠÍLu  1////////&2Puµuµ1N1 ŒÒ ŽÔ x´-F1 d— ˆÊ ˆÊ ˆÊ ‡Ë ˆÊ ˆÊ ˆÊ ˆÊ ˆÊ:X2Puµuµ0N1 ‰Ì Z‰*5R +~¼ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ ŒÒ<]2Puµuµ0N,6T#Lu €Á ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ ƒÅ9[0Puµuµ-L ((((((((((((( 2Pr²uµ0N2Pr²uµ-L2Pr²r´0N2Pr²p±-L0Pr²r´0N0Pp±p±,J110Np±p±0N& 4V `”~Â9[0No°p±,J )D Tƒ y¹„Ê„Ê„Ê9[0Nm®p±-L 5 +Gqo­ÉÉÉÉÉÉ 4V0No°p±-L, <`dž~ÅÉÉÉÉÉz¾ X‹.I  -Lm®o°-L&0P Zz¾ÉÉÉÉÉ~Åh£ +>e,0Pm®m®-L&@ N}t´€ÇÉÉÉÉÉt´ O}%> -Lm®m®-L4~ŀǀǀǀǀÇu¹ VŠ0N&0Pm®m®,J 5~Å~Å~Åz¾^• 7Z*-Lm®m®,J 5zÂdž +>e10Nj¬m®,J&"9 , +:^ +:^(-Lm®m®,J,J VŠu¹~Å~År´ N}%>-Lj¬j¬,J )DR„r´yÁyÁzÂzÂyÁ`› 7Z,-Liªj¬,J, +>eg¨yÁyÁyÁyÁyÁp± Ky"9-Lj¬j¬,J ,J VŠu¹yÁyÁyÁyÁw½0P-Liªiª,J1 CmiªyÁyÁyÁ 7Z-Liªhª,J&0PYtº 4V-Liªhª,J 54-Lhªhª )I-Lg¨hª,J-Lf¨hª )I-Lf¨f¨,J-Ld¦f¨ )I-Ld¦f¨,J-Ld¦f¨ )I-Ld¦d¦ )I-La¤d¦ )I-Ld¦d¦ )I )Ia¤a¤ )I-La¤a¤ )I&&&&&&&((&(&&&&((  )Ia¤a¤ )I4e®e®e®e®e®e®e®e®e®e®e®e®e®e®e®e®e® 2X-La¤a¤ )I4i´i´i´i´i´i´i´i´i´i´i´i´i´i´i´i´i´ 2X )I`¢`¢ )I1e®e®e®e®e®e®e®e®e®e®e®e®e®e®e®e®e® 2X )N`¢a¤ +(G ,,,,,,,,,,,,,,,,,$ )I`¢`¢ )I )I^¡]  +(G )I^¡`¢ )I )I^¡]  +(G )I^¡^¡ +(G )I\Ÿ]  +(G )I\Ÿ]  +(G )I\Ÿ]  +(G )IY]  +(G )I\ŸY +&E &IY\Ÿ +&E )IYY +&E &IYY +&E ( )IYY +&E(1]DI†Ay,S&,D~ )N &IYY +&E +!>P– X¥ X¥ X¥ X¥ X¥LŽ1 $EP– X¥ )N )IT™Y +&E(P– X¥ X¥ X¥ X¥ X¥ X¥ X¥KŒ$$8k X¥ X¥ X¥ )N &IYY +&E1` X¥ X¥T™8k )N1`T™ X¥ X¥-U 5I‰ X¥ X¥ X¥LŽ1 )IT™T™ +&EI‰"T¢"T¢ &I 5"Pž"T¢L’"Pž"T¢"T¢"T¢8k( &IT™T™ +&E$"Pž"T¢L’ =u X¥"T¢ X¥"T¢P– &I  +&ET™T™ +&E,"Pž"T¢@|1]"T¢"T¢"T¢@|- &IT™T™ +&E,"T¢"T¢;t.\"T¢"T¢1`  +&ET™T™ +&E,"Pž"T¢;t.\"T¢"T¢ !A &IT™T™ +&E,"Pž"T¢;t+W"T¢"T¢ !A +&ET™T™ +&E,"Pž"T¢;t.\"Pž"Pž !A &IR–T™ +&E,#N"Pž;t+W"Pž"Pž;t1`1`1`1`1` 5 +&ER–T™ $E,#N"Pž;t+W"Pž"Pž#N"Pž"Pž"Pž"Pž"Pž &I &IR–T™ $E-#N#N;t+W#N#N#N#N#N#N#N#N"J $EP–P– +&E$.\.\"J ;1`.\1`.\1`.\1`.\ 5 +&ER–P– "D +&EP–P– $E $EP–P– $C $EL’P– $C $EP–P– $C $EL’L’ !A $EL’L’ $E("J ; $EL’L’ !A$ @0k!C‹(C“ &I $EL’L’ $E 5.\$;ƒ(C“(C“(C“(C“"J $EL’L’ !A-$Q!9}'C’(C“(C“(C“(C“(C“!C‹ ; $EL’L’ $C$!F4r!C‹(C“(C“(C“(C“(C“'C’4r"J$ "DL’L’ !A ;-e&=‰(C“(C“(C“(C“(C“(C“$;ƒ.\-  "DL’L’ !A$.\$;ƒ(C“(C“(C“(C“(C“(C“$;ƒ-e ; "DL’ H !A-(C“+;Œ(C“(C“(C“&=‰0kD$ "DHŽL’ !A-(C“(C“+;Œ"1r"J( "DHŽ H !A-&5}$Q- "DHŽHŽ !A $D0k0k @  "DHŽ H !A $Q$;ƒ+;Œ+;Œ+;Œ+;Œ&5}$Q- "DHŽ H !A$D"1r+;Œ+;Œ+;Œ+;Œ+;Œ):‡-e ;  "D!C‹!C‹ !A 2(]):‡+;Œ+;Œ+;Œ+;Œ+;Œ&5}"J$ !A H H !A$D"1r+;Œ+;Œ+;Œ+;Œ+;ŒD "D!C‹!C‹ !A 2(](4€+;Œ+;ŒD !A!C‹!C‹ !A&"J$/sD $E!C‹!C‹ !A   !A!C‹!C‹ !A "D!C‹!C‹ !A !A!C‹!C‹ !A !A!C‹!C‹ !A !A!C‹!C‹ !A !A!C‹!C‹ @ !A"@‡!C‹ @ !A!C‹!C‹ @ !A"@‡!C‹ ; !A"@‡$;ƒ !A @$;ƒ!C‹ ; !A"@‡$;ƒ !A  @$;ƒ!C‹ ; !A$;ƒ$;ƒ @ @$;ƒ!C‹ ; !A$;ƒ$;ƒ ;  @$;ƒ$;ƒ ; @$;ƒ$;ƒ @ @$;ƒ$;ƒ ; @$;ƒ$;ƒ ;  @$;ƒ$;ƒ ; @$;ƒ$;ƒ @ ;$;ƒ$;ƒ ; ;$;ƒ$;ƒ ; D$;ƒ'7€ ; ;&5}$;ƒ ; @$;ƒ(4€ ; @&5}$;ƒ ; @&5}&5} ; ;&5}'7€ ; @&5}&5} ; ;&5}&5} ; @(4~&5} ; ;&5}(4~"J ; 6 ; 6 6 ; 6 6 6 6 6 6 6 6 ; 6 ; 6 6 ; 6 6 6 6 6 ; 6 6 ; 6 6 6 6 6 6 6 6 ; 6 6 ; 6 6 6 6 6 6 ; 6 ; 6 ; 6 6 ; 6 6 6 6 6 ; 6 6 ; 6 6 6 6 6 6 6 6 ; 6 6 ; 6 6 6 6 6 6 6 6 ; 6 ; 6 6 ; 6 6 6 6 6 ; 6 6 ;$Q&5}"1r(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4~(4€(4~(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4~(4€(4€(4~(4€(4€(4€(4€(4€(4€(4~(4€(4~(4€(4€(4€(4€(4~(4€(4€(4€(4€(4€(4~(4€(4€(4~(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€(4~(4€(4~(4€(4€(4~(4€(4€(4€(4€(4€(4€(4€(4€(4€(4€$/s \ No newline at end of file diff --git a/res/logov2.bmp b/res/logov2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5fa466dc066b5d134eec7df9a713faff0e6b2e6c GIT binary patch literal 21878 zcmeHL33wD$67K2g%*7-mA%Tzpk^mtDQ4#_g5DbJXfEW-F(O_IbL{t<+K}`f<4L7LZ zu`V8nF|vvm9(b?_WP$-)aZz+vm-WJ9RaQLK<*KcEue+yvrhBG4Waj&p&tkgY+4a}| zSG}GggU-9@LV;NyNf7d|Hx;j)csT?Qo2T23B!1x}EeP#fI-z|_3EC%1&@n}V&Z!B| zDNTZ0yz*Kn!0Bz=ke`7qUT3zGphs&D6tqi#qV_H*Y|{b?GCj~c(+j=Zd7)2+ANpk_ zLhp_e6z900xU&QUx+K7WY#)?#NQA*1QlKQ)4W;=K4DRNJp*<3y>e38M?#FuJD)$_w2v zwzmt$^+|vWizS%Y-w6}?N^tQx5>%Yyf^yt5zQ_v`&+@{ALO)zm?14#reK0gT8Ajx! z!kEtKa8dVExb%!xP?47j6$L3!d5#yR4Di8}9$8RX&wb;HQEoe$2y^Eyc6b>yW!Sx65KXkg6auQm^-jFR1a)zquRr&i<9BuOWVM`W3%Ai@^4NV%GR*{@^q-3oCbAMTS48GX|Q2hDm-;{ zDr~$q1vXrj1{Z>kxowVO@nj~%ZJ&(?T+FQ9Ix6i&{cg{_$}uQox**@`$0heJ?5_+RcAoLYtxCq6ms&jzst zBR)B(8LVwkn^basmMt8IL*yl= z-r2Eb<;PC2>`kkyv(?}mX3esPV>PJYJ}Ikw7MVR9m4-IppwrNv*pjHAjVX~r*UZM4 zpEvQGhU%swqk!z}@;iA^sLULmX1NLkp%dYl1z|KV4xGWL4D=hVn$C5aFU+@$BQgR~ z*2s~WHmERc#92V^H`7403;r<<)8IC4DbduC}T9g|N#GaOvv>9rVdG)ThfVi-D3 zS}uraD9EQK0*)Cz%~K3`MMvN}vJoeno|B_zGO1dHxRFXrbJ=5QrLv`1#<^2i)P=ow z_)#^u;|Z3{zkT~?)*ZB6wp@z znjT>v)?v>R4s%l)2-x^?q(`zBSOdeD)lEgbdPExGVw5y8^Or9#AstWTvp8E3AZlCI(6DGk_p(I| z4Lwq;8yXt!NRC27UABkgu0iKyw@VIbM4+LeyXq)PhvDeu3LoK7MWX}TwuZsXOGfHq zmzsv|B!NaZMG?#>eS&6#4|~u(Xzy#>TAb&a`uKI21m8v>7*sLY!q?<@`izf`x^( zXIN%>3FJ2)17arx1r`SOTaM!4h8#wR3d4`3pcvy-q=fBj-n!NcX62ko0n>>2YW?OHw!# z$1zQUe!++jrbWpQbv4zf={g*FPs_UL0yi0mu27>Ni*lLKGb|N4y_5mN(MN4}#QCtN zh>uDsl+VUITBK#V$rpA^NLiUCiux}l!7+>>)LoP@;%uV) zkZ#N$6OcWm>ZW$0_|h-SOQQFIkAe7&#Hb3E7luH-iVIpI0tV{V+Iysm~X zCQf>8*REZC)rlw_#Cbk4j!^{8Za2S%D7)S$<|#)ICGcQJhujn#->^Rs$gWp@*P4Rh zo(YFx5puXi$IB7Z2zMJcgE%il){Tcrabvvr4<&1C+%7@3p z)!`|nJOA+T(i!&hxs(2%UzV2 zq9>E3m*J7mD|T?ufp6&QMh3OzmX56cm|J!ur&MhC;T>w3*~4K~fsv+P_5efr+4B3X zr%gUg6TCS)%&z<8mtXoT@kVRy;siAkU48G~*%&E7TEVd&F>sT`f=7jQp*U8< zG~dU;C?F-M*x*nEM4Yv(V}!$&&4P8hwdRzMzKL4FX~OAg<}-BO*Gm)=DnI;N(E5aK zF&h`Jvw@TN&$(VvEPUcK)y_8a8(J*|h;yd-X6=eYO#JNg$4?>h~&EgUiNo=^XM=)QC<%cy<&f)GU;y3uy$#E%ah z`rvH&y$4z0v;P>r7wWvKD3?b^l>U2_io@I!4! z#c#A$2D5>q9^YR34ATnQ>Vc`?P zo|ECj1Y|DBv#D&3lf|(rVXu?q6NaOF^YKzq2_m2O3&S>>Ot>zsV0*_^TueLKS5&ky z*{Mz|K)v?Zz)An_kq61cJ4e2zX6lh66R5RfHgS$JoV`c?MZTvVIT~x6ZyCz8EIO(@)UD`k8+?phMV>=X9kU%O&%MTk=r za}-hR)7&`hEkl9J=Tttei1S{Y_{0n6>t^L+q#J68x-~D3Nll${IA6y}xA@_F*{t=Z z)`3!Z{3k-6FNJSngQEhn&RPHWI2zqhy54c()BCGf25n6h?1=6nPAmd4kkLDyj$|7wOsM4N|jpCv{TCBFJ;F4DtjPum#nr+&+bK zIFu~e@JPH9jNo`l`OKX^&o}qu9a7`npMUxNR~gz*-;4an+Hdd|d?!B)`|ZOJ-dO|@ zek6n%Sh6Z9B}reBeEs`R5o5sv2TX(nS;Pt$V8wa}5FtSp@d5@cu;BwlNRW@ZhG@Y< zfCve)2&)neSnv=aLW0aq3K+29AwYx#S%e?S1}u085FtSpE8M0SC?5|2A|%K)HDibt zJOqf4AlJ05AzJVdAVPv%E%AnE!9#!u339b77@`Fa0U{*G)yimy7CZ!qkRVr^lObC0 z5FkQ=JamE0hG@Y|9O@_I4^KLk>}w@o}bGa@F}}ktnbrgy>Rol#ah;m z1m|w9>rAq^`!>lo>ArQ}iUYk4dL8sSm{tSbx9;1?fj*9&oY2MYo6fJ(+1*9sPu6j6!Ta;vI)ljUIwuw0)USDUc}(xyi^yYp6-@cwTe_t<)||?a zmM)*++9e@PDtaBK&Enics(jo8!;VsV9kkT0DeK^+)Yht6D=De+DFfPL@vbyo!6|jh zogE8XC#BbUCDr^8P0~3_%{`75rBda0&>51N-8WQJjsDp--<0aguTSneul;D39n_p-BKyvN>G@~l&b#~2; z)yn^vI=dI&cI{m=Bs49bhaHM4=cehb(LqR|q|y5xcm2n<5a&gpcDW2MzR*qBR4Tp4ao1>olLtv=i5}}z9A@eP(tWX%0buEI(UbWdJNI)l)^?xnbH)UDJf0TIhMmp(M38P z=Fjr%l!dY!R66c743tPUD9S;nQ?C80HCy*FbuI?B<7#UusPbvO=sV|iop(%W*wuY& zFzKCBRKB^@YWU)@Tn*y@o6Yl`PKOb#+$&>S2~2pijXSvrbRFh;&G+lxKc#F+`_R5I zb(edb{rUN9I;+hv-puD)&YRLP$HtrLFsz=ouSHe8UAxeYV_oNlK_iE|ZzIOs*xh}* zVbI9o?%RklH+FwQ-ww@_$PI6<9mcn=bIqWUW6Q&xeCs+RJ#c+@@1N`bj2-R1jX86D afA{UWKVwHfqi>tl{B3h6f91ME%knP>We{Tk literal 0 HcmV?d00001 diff --git a/res/packages.json b/res/packages.json new file mode 100644 index 0000000..aef7667 --- /dev/null +++ b/res/packages.json @@ -0,0 +1,38 @@ +{ + "packages": [ + { + "name": "Ariane", + "version": "1.0.0", + "type": "Payload", + "author": "eliboa", + "description": "Communicate with device through USB", + "payload": ":/ariane_bin" + }, + { + "name": "Hekate", + "version": "5.3.4", + "type": "Bootloader", + "author": "CTCaer", + "description": "The all in one bootloader for all your needs", + "url": "https://github.com/CTCaer/hekate", + "payload": "packages/Hekate/5.3.4/hekate_ctcaer_5.3.4.bin" + }, + { + "name": "Atmosphere", + "version": "0.14.4", + "author": "SciresM,...", + "description": "Customized firmware for the Nintendo Switch", + "url": "https://github.com/Atmosphere-NX/Atmosphere", + "type": "CFW" + }, + { + "name": "Lockpick_RCM", + "type": "Payload", + "version": "1.8.4", + "author": "shchmue", + "description": "Derives encryption keys", + "url": "https://github.com/shchmue/Lockpick_RCM", + "payload": "packages/Lockpick_RCM/1.8.4/Lockpick_RCM.bin" + } + ] +} diff --git a/res/pix.bmp b/res/pix.bmp new file mode 100644 index 0000000000000000000000000000000000000000..95f310c0b9a9c2bdd87cdf49cfc8ec4e6b64b8ab GIT binary patch literal 58 fcmZ?rwPJt(Ga#h_#Eft(0hV9^lc>c0GBE}KMkxZ4 literal 0 HcmV?d00001 diff --git a/res/pix.rgb b/res/pix.rgb new file mode 100644 index 0000000000000000000000000000000000000000..39df8725bead2eadb135791d6a09219a104cd459 GIT binary patch literal 3 KcmZP&Py_$~L;x}X literal 0 HcmV?d00001 diff --git a/res/switch_logo_black.png b/res/switch_logo_black.png new file mode 100644 index 0000000000000000000000000000000000000000..ff624d55a0bc3c9e241a682508c738758d90116b GIT binary patch literal 14732 zcmb_@i91y78~>P+UW%0LOU+cs8X-$m%#1gp62_LXWsQuji7csP89H_;ONGkN*cld;MY$0O#NNLR z4K5=PNc{Hy?p@$c{k8N#@WbJE8Fvm*{6TyYT{QBqo75MqCnqKVk5&FTEwyR+QW`* z^*uog#ZxNAvu!-vw_2=iHdlIAw@~Z`J@V3~M1DX7qu9lotcos3o}@jNWZ%xnYIlds z+J7~S>!oRGvIYz{Ct7jw@!|(GRfyQ<=3ydz(upHc8S7aeR)&l}n1#NcznU)=`g(lD zB$RKKadM>4X45Wp_BlhU{g*APV!flMZ9cQC-5=GE##-}rx>WZ=5cLo|pG-HXcKP{oFCKEB{*{2UtMbZ-1pBrZ;27e%i9h&`p2|i$_E9kxu z$>EnncPtvzPst?COVZ4atXybRfrsmw+RA17IGB8L<+46I+2`OL&0DAj8rkA53ZIEuZJje0z+~MyQ$4KBqN*=78iWtS>w8 zc{W&Gv;6mr>@po}xUUw9Rm{jl>Ae#Y7UJxAGb04Z4~5)2?%ct&-Psy*>5rS)H31>w zY_jH4hWg~ohXt97Uxhh1E!K#CDf7I-VOcVq!cPYmS0I(^*kRIinyjY_Zc!hy#1NBo z_Li|r?JUW)GOR_096CnsKBakwTU|qGMeVbbRo9%Wmc<~P!A$V=WR37jXB;aY(npiD z7Dg~Lub=L+(OZ4N$vfl{%o2V)CSx_YX8HqgrI1c*(4PYhYGegd^X^U zEvYtuqoKjwTm6Q*{E@qE?s#DnI;E$a7*rUd>?rckx&lv_B%C1EPXEe%uC zH90Mwu;vwd7aGJ!`tTJ03#%-VZqfPIUf9r)LCr+D{iG}l#iN%G`yc|WZ18oe#Jt_* zIn78Tu2?HrJt5ejUXr=8R_hxbBSW3?9Wd1Wb~>!HI92J4zCV?4+sbX6YdYkI|1f`j z&|U7EJA~`y^Gjc}Ma6ty?9aid)0&pYqaH@0aF{I7g?$SVi@TIKN5vK_A@x@_c=P_D%dHt;5-?N627LRbJmG^N|92gtYrqM8wut}wVDgS*H zrrM_-wbWu!KZUG+ATM%Sm_}6G>WvSPWl-LU7Go^P6j$omJ*w~RV9hO`{#p*pS}~q` z&kDZADS&TJ!zqTy5xbZNA6m;}1@IK>VK*qatbU*GnWaQoYO3oBV*o{RbIbDOe5}vK zBPd;!3zzMk*P}Vgg2|9;GK^hbyHFfnG)ZW5v^&M>VThrH-U;F5IeSJ=D<@`)v*vgS zx3%z8alZHv-NfK>{2}lJrX5it*J_s9)FZqYf6q~MG#fh$jmjNeo(pw`5t!@62iXaXC27ld1`%qRwTqJ}kZsfQHSWybQM{ zFCf1&jHn>>6}9OP@IJETD5DzeZt{f~xlqGn+Y(uB%6r_iW$63Npgg%0(fO(l0{D@ ziZ9*vV`Dxz+&$cH01ZcBRHEmOEmH;KSfm35;#y)xSYu#a%UR$|{MnXuwajr-KZccy=!!dhhsg+84<~G4u4e~MZ z(c)s7x$Uoe{}w!Eb#k2V*L-i>ufI3@th zpT7sSrpjjC@Q2%>CbZSX@qq6W{DQCZk<$tgSBkqT(I~={T|V{3P!fCVGt8a;6E;+= zF>HYM+ij|lutx@3(;iT*tq4UcL2CcNxphUf0OvZrLPI&WgY)a%(^Tf|+obRxTMA~C zWB)K}Q0$y(BjAtQx=_GJ6^Q*PZ1%1`h_nvM1Is@O>MJ|Q*;DDgpE+=;PP14^Bh|I) zuvG3tjJe=5_EP_?NHyaoySo<)#IQuZy!n+P8R~~wZfFI|!teSpI}Jsm)5to?tP;l4 z`8X#Xe`?Ovl^A%6(-RCU35Lh8oL}@E0Y+s-dH;>qFr=}aN^jO^l1E= zngAYC&tI=z+5yMdV~J&}<0vi+Z!8@(NjN*iTHCNkYoy!e(x-HeCMtX=X&)0{9WWHM zFijAbig2NF@k~`2!Ka~ElVYq%L`9cLRczet*;5@aZaKrZpehW@*$;nALf%b(&gFx& zYTV{p*bHaSLG=8C@;6)0667h8f;11<93o2|-4T0@Pq2LK10O#sV1N|TKtg`9U)82xv&zi^TxQM>2*NMO`M38uw4lHBrc zBRnYD!fk<;%Y<>K8*|qA@7s)s{q2qT2V-wPOB4M2q$vMXQ z%}{GAzn~z5=Zh)-ox`lv|0xJfKA3?d-;W;dJbC|)?=0HZLKJp zW+&UC9LvSiGGPJ@q`C)ND^Rlp+^;(Y>*ADS3(cf0I|VrfVXnsj8xMJ`Uk8NBYNSzzEsv78pVU*6;m==pV|jK=iHVhOcb2mA7j2R>Ry1avb% z$n;kfhV|`pjNA*;LK|hmu;KyD7vO2X7+n=TA=fn}aex`6zIBbrdA$tKGb@FvNp%;q zK2BYZ9xN~}3_1t%LiWbR;i5n#8tPDNM%A_QD}>WWKfTSK_+>b(a1(~PTh4OvFcd8$ z%Rb+=;HDHBSWjL(t;M>ha_{3s0!P||lVu6jDM+~*OYJoG?yC}{3mI=;$WX(R6FS`; zl>&G;d-BkHGF`83A7!PhaEj*8?@W$M+*?uTs;&U?QokHrk(t@QD0Y0sp5yvOLgV-K z+s{|Cv-^1{gL_tfsucA|q50zAl0C{6G5mzsX#-aJ(^uVB2^;1h1TE?@LbGMWg;hBP zsTRXO%_|=9P(t*JHm570rZC4@nX{NyjWI_#%oc=xykwdFy<0t>dg26;4EtZwZ6L z#X8%XheGl2)P3~rH9Foo-0w>yCuJhc-zmUDfyz76B3h@$dI?5Xj-^6!sqS_j^3>%7 z+alvaKO+2>3pXWqUm=w@QpT!Y{n?$h>%gv&XKwQgCd<3WYVm>~$*pqZA&!aREQZH*rI4MVI=;0wo)WKM#%|Jc`VVB~De z3X&E4S%ou@zW;D%>jkusY?nh}F1?xnUjvC&8S3?MvmCDG-JLkykK;WqT3*17lXNx} z!83hymga86Vom~Jtop)YF5GdCpYjX3{w%ZsV?74KQuqRv2hXNwIqpoy7T>VTF^+Qo;p3tAz?NoQ zc%zU}(4H*09B->Y>}G%f_3_Ig6lvK?aqk34x&~_!^Z3oRb#u4|9LqS&hd64{1SacZ zeq>tfBim}@%!Mxu9-sx`Gmf`u#u?bnr@)y>*+XrWliW%1Xdv zbyox4*xD1U97eW*Oex)Z-c$Xb@|)g+jnL921*MX$b4&%Ve-%}0;{3xX-ShUTMCmtv z@iPyvSK9A639toh!sIDoQzK)qFcntp9hrG+ptA|TJ3()cBnYf<=~E4E&UEUUPwz+m0cR@dH-pelej ztG=Sq^R)`AsGF+rB z#~!xljKrLJ;ZL%jAxyS4j!qITyv%QXQf^InqQ_b_%yLaB$V<2|d^jU0YS@L?{Imie z2S3vZZ~oNy=o3NiQ^4a+vI3JlGM}L1OjNr{s)E;0TqeZ?Es!MKWb2+b)K{RUF5y#1 zzwIqja%s(Q3>ofd&qQlv*`6@vmM5tCQ}dIJ%q!e-BbUkzr(JE|8--f8i6K00SsW|O zb-UZ#1@=@tgpcgk#?vxRO9ktPr9FV7mq}Ge7juO<)b+VM&#P^WzM@5@L`8ic^SQrz zTiJQdfF*MOT@;e%%N{_c#}uL4nlP?ZZi(^G+VAAXN?r>F&Qy*NeS@3iar1(7RByGx z?-z{O_GFP-ozkETl}JHtd^M4JGqOnNKAzD1x$eB0AU+tAWtRU=MmwB+>hQH^;MM33 zS#fx+bsrCan8Y!pkDvtBybvmiTG##_;yce3)vno)KH{s$;KBFb;(= zgU;F-VGakpOERo0{c{9PUBGBo!WLeqO zi1(iwr(Ra__GAD~Nc*E>p^nba&5k@k9ixzi(nfb92ob3OSbo(4|h%BMrCt$6% zs55e+2tm_`?j)pVJ&|@?<7%00S~N^^`qkxl;uZb=IAemJ_XA*9qpnEs4lvQXk1TH= zSc1S)&W5IoI7X;3&iiZMze*UQh*{NZ2cfm|2X=V%?DG_nplAx;iU=6IrH_b!@4=KX|i$;^?qp_H$w;-{CR(9@c@|;k1Uh|CwZAX|MHcA{ofu+ zE!UcAlxlHP7A~KBOZ-7tdLF5!XZZtb;o9K6lW@YHdaIOqJGA%4uRhzLCNx` zexJBJ#PFCrf|Li#NptqBzlppdtT;lBi#-jJ?$q7EuiT@5&Hy0K|Kais*20L3hu{lV zdi63=4W2U(ZJM>nr+k?kVzhu$`u%0X(iJl3Tp?WTh~`qpK_`;H($C);16)Jbh)X60jlHrM^O{SKy)>*uZ$esEf3HTZjFlp>{Z z^_TJy@(%z{)NW4|I+)E#S3~1#w$49rB*bTv|2D0SpL_@uM7NV1m$c0$qr2O?ljEU` zwFBjxxKdwb%z-}ym?wZ=48Xz)E^Yg7pB&Ax3-3olb z-#}AOGL$~=@|Y&%N#h1Dy%DB$%nG@1(-VQVI!E6qiI1tRH_mvLjlFs?Um3WPRKRSY zl%p;}?Yg<_TaHIG-jtEJ_isB^z+Z)7U#K-j*6(45c!*~PlIqM&$pZexqaHnf0pd%M zRb@CXK`z`APtku=u;6THuKGn!F3;Fj0~2{O^~oGYSPF2JIe-gC-;T3=Vfurz67>lT zw6g6%pGJ1)2y!RsqdH{G@_$A%0G~BWp6@yd&W_Bonvy_Ma!9H1 z&lwV^ktens^j!k@GWVDC^L z9Q)PG$i~%c(C$p)QFr;l(Q~0tf}%hix#S%Z=KXx!k$Czwc~EOK_e=Y;LmZDl%#hi` zLrKP+(veNX9fXq5)_BF10ySB_^$cYvuqZ4DXaa^bxBnG>pSb?~ga{AC8GGEW3hdv006T95|LV^b7vSZlx* zi!!-1s#rhJ2n%CCypsa;vLtr(DL6RaGi(&!lG(-?h-ckEE&1 zi?FeGzg>EWcn?s){QR(97p7v*5UMx6_89TJ^TASjySC)K6wM!=M@8Wfgm1tYM8mt*qYPME8uK^bZP`y)aZs=5dod@R{w}u2k6f8yB(*1J zDM~Tt0A!Lzp5gCPC4N&BnreAc;~P7Ka>cL?b&dp%y+-w=teU`7MOUm$mJsP&hJ`~K zW74Jn?gVbrG6Tu;>o-F$O?DuO(?YSX`{9;YL~a|>vu=JM_d60wb&jYQ&Negno+(e= z)hbEp1F;RF(t)qX%j5X2h;gFjk+^iA9RLc{;|AIXbW?_kAXJE->^}t3Nqz}U;S&;n z?uB3fLEu2V%K(G@sfa&U^7pq70Cn2Ra{v)M-&P1Z5|OTIbhqr%9;DbuC=zJU_KocY zc5x6Ywz>TgSq}1@xOAkadd%5$DbBw-_ZZzpApG(p)x;#^5d<+UJR;VCc_6jv*a|p% z5aF*T|L<$V$=hmaM&QuT1-`yXlCn#77svlYm_Q^QD^Gg+;J+z?h>NP3gTde+${PT1 zdqYf!H0ve92CWpMqskgAN_^d*&1zJ z&Q$C=zHuzkD6#5+t!$zZix#*0z#l$F-%z(YQzs49qZLfOhs@CW{>Iy7ld7d3hKfom z#BFi!;`lB%V#yahs7#z^gke1vY8Xan%V-@H*5YooOZ2|*Tt*GUXCKW77Gs~wBkou) zL|Mk_XcKSUZT1D{krrOrq)6cg9{$PfJ~dv(n=QcP9d>6URZEz4(iomj zaP(Yv={;tuCpAT~Xit@>wZXPf4YagUce_3l-l;yi@lBkq{2hlW^=zVzhf->TSwENu z-*+}5@4r2<_j;RZ4pDX{B}uNw?+W}Kk}@uKyR&U6kqEK&IxI7)Gd+@qf0_KpJ_u+hJJh-@yx`KdN0;BX*QHsWAF2P* z`m9O|AAywBwSm@BT3qOWs(|(X383V2IGv^mPLqFL%8(`L(e7U#Hlgt?`Prxr&av{uVo zW|32Zyom8<>w|s}-nU456DXllB!`SrgDA|fMgE=)UO`0W!Xw6O5IYB7GZ6Cp>QBA) zERr+sV+N$-^0@odaaNT!4QZ4H$(KzWSE$ow{%_rJY|y4sU-KQ=xhgQyR(h<#WUh~7s1 z4!E>+%7Ay$ku7j0glR)TBLKmdU?nnwAYw>y*0E#e(*pJp+ z)7nFfpQmp4hySi!WD2vJk zQ*V80L<(nR2cesOm3ccK@*-w$kJwdUV4`TYT`*MMRx!YqpRwM~Zv^mQ2_!x)b-3OC z_5JxbU;;RFfytqInk*|I-sS*<@eo_NPfD>|?K|301qkO8o#h(Ff=avs|cAKm- zj!+A6Ql#!;9$V=H$A{C`w3VN;{p3A&f#kJ`3xLkRdF-xp5!=3>um|MRdwN}JeB)*s zr$7NpS>B33Y7nd3rs_EzNx%`4){X)ZiTZ&&X>HUT51QI-H z3Hk7EeR`t?D-Qjy#YFaH4!ZskrM1T9IcOS)(r?k*`3$h6AJdgXj2pJv#1s`5!~gMg zbggLv@bnE%BR&Io0-&7=ZVPoYrs%a~*&V)sDP%q07??{{U6r)GDY_hZ;+x*oi?$Nd2n(04kM*4IRMx@5PmtqSc2mJ zb;COtt1HS>&HPepiCva6^8iV&7|?)9MJdgbiOqst!PYQcB`<1Q zZU2NiJwdaKH5BbLCXAN5G3j#tJ&-amEU%gG&>${(;#7&#O6;lmSN#8uu2f18`Rxxo zCdsK2vq578d*5}@oHOa<*HTpIk*>UAe>O(r5SWf0ee;`HuA)4RZA0X!Y+aZAbO9v7~Z@n#kF(3v~P?l7D)dgj1= z_m4O}Hujf@VR>V9q=^wBxelNU!GAd@$nQIDJ6@L;F6hzH)xvK)R$~3b&_HXn3yCJ( z3!Kx`MkPi)Pzj4%SKf9_NFLAyF!$D0^hvpx@Q>7C-`i9xav2B|J142s= zKw=FEakZ+KJ#zz^4HdaU(TN3pW%x*nn85C`g{2+o4Iw_K4-s#|YS1*s<3^-m;MaO7 z=J**`8}h$FDIzv$tqjCI7I6EJP6A0dQK#d$lwVSNrhS4lmx;qYq$d`5nsJ8H-qOsa zGVj`8XY*zY!HcwCY3<<+4{FgYA^zV!|B5NqbHy;QbXZ7Jm*@t9_TCuzSANOCO+>vf zJJ3Gy>&ICchKf71hz?6LjUEsGlU>j8jt|v#Fa`j=CfgknpBPPOjc8lhPb>fYwoR-x zcHT0a;|LCf#~^!Le2lYi3Z@5xrrQ1MhxfD=Lt>cCW2`AdUE9?tXaraKd(|8EoIbL0 zbNuqiB;9QEooPsb zW@zE(P&>mx;Q}P#`&yVM_R_Bb00STdh+kmbHg!LYwqXbf`GmFzc1Z#Mm$?6e9^h#} zX~^sTHg<6k4?ryh6%;78v+xhSWQ0u@6ghqofI?l8@*w`lD*#*o9KYf90^86G;?Hk) zxq%y>AcB$#;3qI9M`;^7IEW|lrZ(|A=ne*OdEMV8F?Dy6A{Yfgs%>(ax?nX4FtXwx z9z+6E0D1us35mEZ`{y7ytk6c2qX)t8!XC3+c&S5agr)wz1uJlYh}B zA}^A2F?Vc-u_sln>Ea6EiFv+xXX700ts+lV`yWKZ=?6l?Xb$&C_?QhP!KAb znG{B~59n(uG>Jilvj>nXSie0WzIT6EW%TV1Xo{$;+R#av_ctqdf>NcqRCfxaS@ zce=$If9&pikhbOrcxmu{ddNfZ2?Pv3@bz z8c5JdJ|o5UTl%OXQEAOh;R|%SP%J@n&p>K#uk`!8b0;5Z_-QI~ z+7rr7bvMuYOs4;q5p~!c?jlE88bze|T#-87^=eSI)F%Tu@X_(aQxIqb`)Kf91vbBW zMxzHS#1m+I0y$$i{ByZUMWX%@H^mfZvOPtW_#O~t@NxIz(wsNt8~}JlAP?(EPq-H^ z#8YVs<~%@pMhy3mD`;Wx6eun~Yep7U?nrcC)Qhmsf+BAva@q{aPIEU8j9>T5Ku&`k zuX1AV5T4x6O<6awd*-p<2T1ufy3p5MVsS!gmEaYPUscRF!0^_GFJvHo3$b3~tZ`1zE z-YUPlZFEY4pX=c{8v#63QyTk9XU(GsbRhg1WxRB;E^2t7Q()|n475>@wlbBhQe+95 z8eXH+q;#sA$55cU5*L5;+@bLd%ZmBeS#G)X^Q0TDx_e5mO+?qKCnj`7lmPRaRM=LH zA!}J`eEgM_=d%HzS!9lp1;9w*gfeu8V%KWLWkQ}S#$(1^nurGkfIR+X~U?u{W z;=TbIHdsnWw}{q1C!iSyt?Xe5h-2T3Lwh> z)T}ig=mcFN#_$qA%py@+HO9H_G5o@>bv$0uMgocs;$>GHyF(Rwtl1Nw|0LH6;DWWA zvX^J|pJ;q?j7X^ps?RabeAuc1>*r=`(U2aw^g9x3Rxrt>KUENbp9N31o`S0Ny9Zsv z?kSEtTPCHpyWc87t#X`yjrOfh%{1<0KpLmNJpbF@A*U0$V%1-EBjv_l{uoj0%3r?? z--A-O=5jc><-g!JL*UI(ovhry6}A#T9B|lD|1_F8=!A|k2+X!Uy8#+6ZCRAojx_g7 z>-jsd{jgYDxn|IV5Je)JdGIsP&N1K1ptGXC_=LRbXyyw4$GeuvpxUW1A2MSsInr6mg{v2(4a3}10EO>Q!|mO84!V<4k#Z6er1Kf- z*RvU61}qbOLVy7NM*LtKt4&2B>cm0(#1}CSNgz-_3H9clB&We5-KSjhn}a35=IXg}%(z=~`XZ z69xygXh2Aj=Raq&X?eu*0@iazBF+cH$|O)&hEcXsTaNH|Hd0xGTfXJ^JR!_IBR=iu z(aC;G0LVymDQa+Q~orKCT8H z2|MF;-_=S0eX(KCCt!u~cTyo_MmX3IJE%Y$gkwChEH;^R;EZ=n2iN%>U6)R(9CO7< z?$Zn*f^e9uBPFL%H}Ql|AZ$O=Ng`B~ee(#P`;xM|VB`M7pB4BHY~0956u?g`-($FC z{W^VbU6*#@$jYk?c~;9@|4`JsSjU}HDO}OiHWb3QQO<5Wj8?(pgo}fKV;K9xbkgSeqv`%DIh8+1g0w6xyQ%JE(acAt}$%BVS z;~V#W(J#AQ10?cd+O#+wvx$8FRxU{|omTt1-7v7;#5TzucX@a&GboQr>WJ0JHRe(> z4H>Qi#+YLm$_VdSKb{z6=E@bjSB4rmlL*O|vOfEz&aXhVWs7l!k_FJc{!~+An;5FX zma+9(_Un}9fu5dVg{>N!AhYdXJJyJMkyp}IrE$km`+@3vq1&CTr_)02c1gAQUjy-{ zee56=^s7}-20YGqnmiapB_>!qX$#;tY>%_%Avx1x0wQ<7e?dDy zM9HEdnu(?YZp;m|kAj)oxzHEywHXasG{+h+b^QLEd}*;V=)jfDj><6I@AkL%=51WY zxg}PU%^YoY29A*^W!5zeYWNR$@BHq0wf(8SBj4d7hT<*Be~R8bx`Xu8V()9u#Dty# zOXM{>K5u>sEih;QV$0CyHce$f9b`KPb&v*HSASn=tb{+*mX-$C<> z*oMyM{okK8^QIm>=do-L*)v z_n)G}JRaZhDU%UR~ z*QlZ7q1E<~h~`TKh1Mu^Z|wRS%>4x%t@1s-kTynAOcV6t1MkxA=LK6pwkkTHt!2{& zw9)el>My)xWMenM(wAkZsd8b_aH4~^ynou^$IqG_!AA_{+H$NoLtS5Zf{ko{Mzybfsu#VSALWi?RiP#5$aq|r*7kJLQoW@_yCj3P`@4cXfZ+(jNG!k|mp)XK0|zL>-iLseVv zdGAwGqE;069n?CiHy<-n&@?i7ewWVz#{|VU%iGyjQJCg;q~i*^oxw&?&y${EV>R4E z6cYKqx`dcK2sx72d?lXy6?BQPAPucycpt!#`2lKH_v+9Jk~zN@46_{mIR(d@9d=H} znCp&Gnq9pQER073f zfK#|L9S9j25cpZ&Duj-AeXm7T&sWB9cvbHl9RDl~f!{dJHgYV_+h@RgRMWMDkpnBSXVtCrYd_|Dl9wGuEZ z7(rgwKjP!y^YJ#?N6Bm#{M%5sNv(tD-3dSEBeAkWvfqI;Rbb*MruWF}mAJ=xiOs$D zYI*|`yh?D+?JKT=H`pCskVJWfL|Lps<>1E6VMhPfll2K!_DI(H#9~A1=s4{nyIsMw z)A?CXgY(@?4F y*Pr!jtY+D)t@h6!{r~+{;lJw%mputw-QsvgG&S6`BMxle{2OCpP<)PX=l=jcYxY0@ literal 0 HcmV?d00001 diff --git a/tegrarcmgui.cpp b/tegrarcmgui.cpp index aec7205..74c76df 100644 --- a/tegrarcmgui.cpp +++ b/tegrarcmgui.cpp @@ -3,6 +3,9 @@ #include "qutils.h" #include #include +#include + +QNetworkAccessManager *nMgr(); QMouseEvent MouseLeftButtonEvent(QEvent::MouseButtonPress, QPoint(0,0), Qt::LeftButton, nullptr, nullptr); @@ -24,18 +27,26 @@ TegraRcmGUI::TegraRcmGUI(QWidget *parent) : QMainWindow(parent) , ui(new Ui::TegraRcmGUI) { - ui->setupUi(this); + ui->setupUi(this); // Set a static instance to handle hotplug callback Q_ASSERT(!hasInstance()); m_instance = this; - // Init acces to builtin resources + // Init access to builtin resources Q_INIT_RESOURCE(qresources); // Load settings userSettings = new QSettings("nx", "TegraRcmGUI"); + // Start update manager + /* + qRegisterMetaType("download_t"); + m_um = new UpdateManager(this); + connect(m_um, &UpdateManager::new_update_available, this, &TegraRcmGUI::updateAvailable); + //m_um->start(); + */ + // Tray icon init trayIcon = new QSystemTrayIcon; trayIcon->setIcon(switchOffIcon); @@ -43,22 +54,29 @@ TegraRcmGUI::TegraRcmGUI(QWidget *parent) connect(trayIcon, &QSystemTrayIcon::activated, this, &TegraRcmGUI::trayIconActivated); trayIconMenu = trayIcon->contextMenu(); + m_progressWidget = new qProgressWidget("", this); + // Create a qKourou instance to invoke Kourou methods (asynchronously) using signals and slots m_kourou = new QKourou(this, &m_device, this); m_kourou->autoLaunchAriane = userSettings->value("autoAriane").toBool(); m_kourou->autoInjectPayload = userSettings->value("autoInject").toBool(); - // Init tabs + // Create tabs ui->tabWidget->tabBar()->setCursor(Qt::PointingHandCursor); ui->push_layout->setAlignment(Qt::AlignTop); - ui->pushLayoutWidget->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->pushLayoutWidget->setAttribute(Qt::WA_TransparentForMouseEvents); payloadTab = new QPayloadWidget(this); ui->tabWidget->addTab(payloadTab, tr("PAYLOAD")); + hekateTab = new qHekate(this); + ui->tabWidget->addTab(hekateTab, tr("HEKATE / AMS")); toolsTab = new qTools(this); ui->tabWidget->addTab(toolsTab, tr("TOOLS")); settingsTab = new qSettings(this); ui->tabWidget->addTab(settingsTab, tr("SETTINGS")); + connect(ui->tabWidget, &QTabWidget::currentChanged, [=](int idx) { + if (idx == 1) hekateTab->on_tabActivated(); + }); // Load builtin Ariane payload QFile file(":/ariane_bin"); @@ -89,6 +107,7 @@ TegraRcmGUI::TegraRcmGUI(QWidget *parent) pushTimer->start(1000); // Every second m_kourou->initNoDriverDeviceLookUpLoop(); + m_pkgs.setParent(this); /// GUI inits // Set stylesheets @@ -100,14 +119,22 @@ TegraRcmGUI::TegraRcmGUI(QWidget *parent) ui->deviceInfoBoxFrame->setStyleSheet(GetStyleSheetFromResFile(":/res/QFrame_box01.qss")); ui->closeAppBtn->setCursor(Qt::PointingHandCursor); - connect(ui->closeAppBtn, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->closeAppBtn, SIGNAL(clicked()), this, SLOT(on_appClose())); + ui->minimizeAppBtn->setCursor(Qt::PointingHandCursor); + connect(ui->minimizeAppBtn, SIGNAL(clicked()), this, SLOT(showMinimized())); clearDeviceInfo(); + ui->di_tableWidget->setColumnCount(2); + ui->di_tableWidget->setColumnWidth(0, 95); + ui->di_tableWidget->setColumnWidth(1, 75); + ui->di_tableWidget->horizontalScrollBar()->setStyleSheet("QScrollBar {height:0px;}"); + ui->di_tableWidget->setStyleSheet(GetStyleSheetFromResFile(":/res/QTableWidget.qss")); + Switch *_switch = new Switch(m_kourou->autoLaunchAriane ? true : false, 52); ui->verticalLayout->addWidget(_switch); connect(_switch, SIGNAL(clicked(bool)), this, SLOT(on_autoLaunchAriane_toggled(bool))); - ui->centralwidget->setFixedSize(680, 400); + ui->centralwidget->setFixedSize(690, 400); this->adjustSize(); } @@ -118,6 +145,73 @@ TegraRcmGUI::~TegraRcmGUI() delete trayIcon; delete ui; + + //QMainWindow::~QMainWindow(); +} + +void TegraRcmGUI::updateAvailable() +{ + /* + auto queue = m_um->getDownloadQueue(); + if (!queue.size()) + return; + + QString message; + QTextStream messageStr(&message); + messageStr << tr("New updates available :\n\n"); + QString buff; + for (auto item : queue) + { + if (item.dest_path != buff) + messageStr << item.dest_path << "\n"; + + messageStr << "- " << QFileInfo(item.url.path()).fileName() << "\n"; + buff = item.dest_path; + } + if(QMessageBox::question(this, "Update", message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + { + //QtConcurrent::run(m_um, &UpdateManager::download_all); + //m_um->download_all(); + auto dialog = new UM_Dialog(m_um, this); + dialog->exec(); + } + */ +} + +void TegraRcmGUI::on_appClose() +{ + if (userSettings->value("minToTray").toBool()) + { + showMinimized(); + trayIcon->showMessage("", tr("TegraRcmGUI is still running in system tray"), m_device.isReadyToReceivePayload() ? switchOnIcon : switchOffIcon, 3000); + } + else close(); +} + +void TegraRcmGUI::changeEvent(QEvent* e) +{ + int t; + QEvent::Type typ = e->type(); + switch (e->type()) + { + case QEvent::LanguageChange: + this->ui->retranslateUi(this); + break; + case QEvent::WindowStateChange: + { + if (this->windowState() & Qt::WindowMinimized) + { + if (userSettings->value("minToTray").toBool()) + QTimer::singleShot(250, this, SLOT(hide())); + } + this->adjustSize(); + break; + } + default: + break; + } + + QMainWindow::changeEvent(e); } void TegraRcmGUI::hotPlugEvent(bool added, KLST_DEVINFO_HANDLE deviceInfo) @@ -139,10 +233,11 @@ void TegraRcmGUI::deviceInfoTimer() void TegraRcmGUI::on_deviceStateChange() { + // Device status box ui->devStatusLbl_2->setText(tr("DEVICE STATUS")); ui->devStatusFrame->setStyleSheet(m_device.getStatus() == CONNECTED ? statusOnStyleSht : statusOffStyleSht); ui->rcmStatusLbl_2->setText(m_device.rcmIsReady() ? tr("READY") : tr("OFF")); - QString arianeStatus, arianeStyle; + QString arianeStatus = "", arianeStyle = ""; if (m_kourou->arianeIsLoading) { arianeStatus.append(tr("LOADING")); @@ -169,16 +264,25 @@ void TegraRcmGUI::on_deviceStateChange() if (!m_device.arianeIsReady()) clearDeviceInfo(); - if (m_device.rcmIsReady() || m_device.arianeIsReady()) + // Icons + if (m_device.isReadyToReceivePayload()) + { trayIcon->setIcon(switchOnIcon); + setWindowIcon(switchOnIcon); + } else + { trayIcon->setIcon(switchOffIcon); + setWindowIcon(switchOffIcon); + } - if (m_device.getStatus() != CONNECTED || !m_device.rcmIsReady()) - m_deviceInfoAvailable = false; + if (m_device.arianeIsReady() && m_pkgs.hasPendingDevInstalls()) + m_pkgs.devInstall(); payloadTab->on_deviceStateChange(); toolsTab->on_deviceStateChange(); + hekateTab->on_deviceStateChange(); + } void TegraRcmGUI::on_autoLaunchAriane_toggled(bool value) @@ -200,26 +304,17 @@ void TegraRcmGUI::on_autoLaunchAriane_toggled(bool value) bool TegraRcmGUI::enableWidget(QWidget *widget, bool enable) { widget->setEnabled(enable); + return true; } void TegraRcmGUI::clearDeviceInfo() { ui->deviceInfoFrame->setStyleSheet(statusOffStyleSht); - ui->deviceInfoLbl->setStyleSheet(statusOffStyleSht); - ui->batteryLevel->hide(); - ui->batteryLevel->setValue(0); - ui->burntFusesLbl2->setText(""); - ui->sdfsLbl2->setText(""); - ui->sdfsLbl2->setText(""); - ui->fsTotSizeLbl2->setText(""); - ui->fsFreeSpaceLbl2->setText(""); + ui->deviceInfoLbl->setStyleSheet(statusOffStyleSht); + + ui->di_tableWidget->setRowCount(0); if (!m_kourou->autoLaunchAriane) { - ui->batteryLbl->hide(); - ui->burntFusesLbl1->hide(); - ui->sdfsLbl1->hide(); - ui->fsTotSizeLbl1->hide(); - ui->fsFreeSpaceLbl1->hide(); ui->devInfoDisableLbl->show(); } else ui->devInfoDisableLbl->hide(); @@ -227,45 +322,61 @@ void TegraRcmGUI::clearDeviceInfo() void TegraRcmGUI::on_deviceInfo_received(UC_DeviceInfo di) { - if (!m_deviceInfoAvailable) - { - m_deviceInfoAvailable = true; - toolsTab->on_deviceStateChange(); - } - else m_deviceInfoAvailable = true; - ui->batteryLbl->show(); - ui->burntFusesLbl1->show(); - ui->sdfsLbl1->show(); - ui->fsTotSizeLbl1->show(); - ui->fsFreeSpaceLbl1->show(); + ui->devInfoDisableLbl->hide(); ui->deviceInfoLbl->setStyleSheet(GetStyleSheetFromResFile(":/res/QLabel_title01.qss")); - ui->batteryLevel->show(); - ui->batteryLevel->setValue(int(di.battery_capacity)); - ui->burntFusesLbl2->setText(QString().asprintf("%u", di.burnt_fuses)); - ui->sdfsLbl2->setText(QString().asprintf("%s", di.sdmmc_initialized ? "Yes" : "No")); + + ui->di_tableWidget->setRowCount(0); + auto addTableWidgetRow = [&](const QString &label, const QString &value, bool tooltip = false) { + auto di_t = ui->di_tableWidget; + di_t->insertRow(di_t->rowCount()); + auto label_i = new QTableWidgetItem(label + ":"); + label_i->setTextAlignment(Qt::AlignRight |Qt::AlignVCenter); + label_i->setFlags(label_i->flags() ^ Qt::ItemIsEditable); + auto value_i = new QTableWidgetItem(value); + value_i->setTextAlignment(Qt::AlignLeft |Qt::AlignVCenter); + value_i->setFlags(value_i->flags() ^ Qt::ItemIsEditable); + if (tooltip) value_i->setToolTip(value); + di_t->setItem(di_t->rowCount()-1, 0, label_i); + di_t->setItem(di_t->rowCount()-1, 1, value_i); + }; + + if (strlen(di.deviceId)) + addTableWidgetRow(tr("NX ID"), QString(di.deviceId), true); + + addTableWidgetRow(tr("Battery charge"), QString().asprintf("%u%%", di.battery_capacity)); + addTableWidgetRow(tr("Burnt fuses"), QString().asprintf("%u", di.burnt_fuses)); + + if (strlen(di.fw_version)) + addTableWidgetRow(tr("Firmware (SYS)"), QString(di.fw_version) + (di.exFat_driver ? tr(" exFAT") : ""), true); + + if (di.emunand_type) + addTableWidgetRow(tr("Emunand"), di.emunand_type == FILEBASED ? tr("File based") : tr("RAW based")); + + if (strlen(di.emu_fw_version)) + addTableWidgetRow(tr("Firmware (EMU)"), QString(di.emu_fw_version) + (di.emu_exFat_driver ? tr(" exFAT") : ""), true); + if (di.sdmmc_initialized) { QString fs; - if (di.emmc_fs_type == FS_FAT32) fs.append("FAT32"); - else if (di.emmc_fs_type == FS_EXFAT) fs.append("exFAT"); + if (di.mmc_fs_type == FS_FAT32) fs.append("FAT32"); + else if (di.mmc_fs_type == FS_EXFAT) fs.append("exFAT"); else fs.append("UNKNOWN"); - ui->sdfsLbl2->setText(fs); + addTableWidgetRow(tr("SD Filesystem"), fs); - qint64 fs_size = 0x200 * (qint64)di.emmc_fs_cl_size * ((qint64)di.emmc_fs_last_cl + 1); - qint64 fs_free_space = 0x200 * (qint64)di.emmc_fs_cl_size * (qint64)di.emmc_fs_free_cl; - ui->fsTotSizeLbl2->setText(GetReadableSize(fs_size)); - ui->fsFreeSpaceLbl2->setText(GetReadableSize(fs_free_space)); - } - else - { - ui->sdfsLbl2->setText("N/A"); - ui->fsTotSizeLbl2->setText("N/A"); - ui->fsFreeSpaceLbl2->setText("N/A"); - } + qint64 fs_size = 0x200 * (qint64)di.mmc_fs_cl_size * ((qint64)di.mmc_fs_last_cl + 1); + qint64 fs_free_space = 0x200 * (qint64)di.mmc_fs_cl_size * (qint64)di.mmc_fs_free_cl; + addTableWidgetRow(tr("FS Total size"), GetReadableSize(fs_size)); + if (fs_free_space) + addTableWidgetRow(tr("FS Free space"), GetReadableSize(fs_free_space)); + } if (di.autoRCM != toolsTab->autoRCM_switch->isActive()) toolsTab->autoRCM_switch->toggle(); + + + toolsTab->on_deviceStateChange(); + hekateTab->on_deviceInfo_received(); } void TegraRcmGUI::error(int error) @@ -283,11 +394,22 @@ void TegraRcmGUI::error(int error) if (!err_label.size()) err_label.append(QString().asprintf("Error %d", error)); - QMessageBox::critical(this, "Error", err_label); + if (!isVisible()) + trayIcon->showMessage("", err_label, QSystemTrayIcon::Critical, 3000); + else + QMessageBox::critical(this, "Error", err_label); } -void TegraRcmGUI::pushMessage(QString message) +void TegraRcmGUI::pushMessage(const QString message) { + // Send message from tray if app is not visible + if (!isVisible()) + { + trayIcon->showMessage("", message, QSystemTrayIcon::Information, 3000); + return; + } + + // Otherwise, push in-app message AnimatedLabel *push = new AnimatedLabel; QPropertyAnimation *animation = new QPropertyAnimation(push, "color"); animation->setDuration(800); @@ -298,7 +420,6 @@ void TegraRcmGUI::pushMessage(QString message) push->setMaximumHeight(80); ui->push_layout->addWidget(push); animation->start(); - push_ts.push_back(QDateTime::currentSecsSinceEpoch()); } @@ -356,13 +477,12 @@ void TegraRcmGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) int t; switch (reason) { case QSystemTrayIcon::Trigger: - t = 0; + showNormal(); + activateWindow(); break; case QSystemTrayIcon::DoubleClick: - t = 0; break; case QSystemTrayIcon::MiddleClick: - t = 0; break; case QSystemTrayIcon::Context: drawTrayContextMenu(); @@ -383,28 +503,35 @@ void TegraRcmGUI::drawTrayContextMenu() "color: rgb(255, 255, 255);" "}"; + if (nullptr != trayIconMenu) + delete trayIconMenu; - QMenu *menu = new QMenu; - menu->setStyleSheet(menu_ss); - menu->setContextMenuPolicy(Qt::CustomContextMenu); - menu->addAction("Exit",this,SLOT(close())); + trayIconMenu = new QMenu; + trayIconMenu->setStyleSheet(menu_ss); + trayIconMenu->setContextMenuPolicy(Qt::CustomContextMenu); + if (!isVisible()) + trayIconMenu->addAction("Show",this,SLOT(showNormal())); + trayIconMenu->addAction("Close",this,SLOT(close())); + trayIconMenu->addSeparator(); - QMenu *fav_menu = new QMenu; - fav_menu->setStyleSheet(menu_ss); - fav_menu->setContextMenuPolicy(Qt::CustomContextMenu); - fav_menu->setTitle("Favorites"); - - for (payload_t payload : payloadTab->getPayloads()) + if (m_device.isReadyToReceivePayload()) { - QMenu *p_menu = new QMenu; - p_menu->setStyleSheet(menu_ss); - p_menu->setContextMenuPolicy(Qt::CustomContextMenu); - p_menu->setTitle(payload.name); - fav_menu->addMenu(p_menu); + QMenu *fav_menu = new QMenu; + fav_menu->setStyleSheet(menu_ss); + fav_menu->setContextMenuPolicy(Qt::CustomContextMenu); + fav_menu->setTitle("Favorites"); + QSignalMapper* signalmapper = new QSignalMapper(); + for (payload_t payload : payloadTab->getPayloads()) + { + + QAction *action = new QAction(payload.name); + connect (action, SIGNAL(triggered()), signalmapper, SLOT(map())); + signalmapper ->setMapping (action, payload.path); + connect (signalmapper , SIGNAL(mapped(QString)), payloadTab, SLOT(on_injectPayload(QString))); + fav_menu->addAction(action); + } + trayIconMenu->addMenu(fav_menu); } - - menu->addMenu(fav_menu); - - trayIcon->setContextMenu(menu); + trayIcon->setContextMenu(trayIconMenu); trayIcon->contextMenu()->popup(QCursor::pos()); } diff --git a/tegrarcmgui.h b/tegrarcmgui.h index 133570a..b80a05f 100644 --- a/tegrarcmgui.h +++ b/tegrarcmgui.h @@ -5,16 +5,24 @@ #include #include #include "qpayload.h" +#include "qhekate.h" #include "qtools.h" #include "qsettings.h" #include "kourou/kourou.h" #include "kourou/usb_command.h" #include "qkourou.h" +#include "qprogress_widget.h" +#include "qobjects/custombutton.h" +#include "packages.h" +#include "packagemanager.h" class QPayloadWidget; +class qHekate; class qTools; class qSettings; class QKourou; +class qProgressWidget; +class Packages; QT_BEGIN_NAMESPACE namespace Ui { class TegraRcmGUI; } @@ -27,7 +35,7 @@ class TegraRcmGUI : public QMainWindow static TegraRcmGUI* m_instance; public: TegraRcmGUI(QWidget *parent = nullptr); - ~TegraRcmGUI(); + ~TegraRcmGUI() override; static bool hasInstance() { return m_instance; } static TegraRcmGUI * instance() { if (!m_instance) m_instance = new TegraRcmGUI; @@ -38,24 +46,30 @@ public: Kourou m_device; QKourou *m_kourou; QPayloadWidget *payloadTab; + qHekate *hekateTab; qTools *toolsTab; qSettings *settingsTab; + qProgressWidget *m_progressWidget = nullptr; + Packages m_pkgs; + bool enableWidget(QWidget *widget, bool enable); - bool isDeviceInfoAvailable() { return m_deviceInfoAvailable; } + void changeEvent(QEvent* e) override; private slots: void on_deviceInfo_received(UC_DeviceInfo di); void on_autoLaunchAriane_toggled(bool value); + void updateAvailable(); void pushTimer(); void on_Kourou_finished(int res); void trayIconActivated(QSystemTrayIcon::ActivationReason reason); + void on_appClose(); public slots: void hotPlugEvent(bool added, KLST_DEVINFO_HANDLE deviceInfo); void deviceInfoTimer(); void error(int error); void on_deviceStateChange(); - void pushMessage(QString message); + void pushMessage(const QString message); signals: void sign_hotPlugEvent(bool added, KLST_DEVINFO_HANDLE); @@ -63,7 +77,6 @@ signals: private: Ui::TegraRcmGUI *ui; KHOT_HANDLE m_hotHandle = nullptr; - bool m_deviceInfoAvailable = false; std::string tmp_string; QVector push_ts; int tsToDeleteCount = 0; @@ -72,7 +85,7 @@ private: const QIcon switchOnIcon = QIcon(":/res/switch_logo_on.png"); const QIcon switchOffIcon = QIcon(":/res/switch_logo_off.png"); QSystemTrayIcon *trayIcon; - QMenu *trayIconMenu; + QMenu *trayIconMenu = nullptr; void drawTrayContextMenu(); void clearDeviceInfo(); diff --git a/tegrarcmgui.ui b/tegrarcmgui.ui index c0ff3ed..479ef26 100644 --- a/tegrarcmgui.ui +++ b/tegrarcmgui.ui @@ -6,10 +6,22 @@ 0 0 - 677 - 435 + 690 + 428 + + + 690 + 420 + + + + + 690 + 440 + + TegraRcmGUI @@ -23,7 +35,7 @@ - 190 + 200 30 481 371 @@ -167,275 +179,17 @@ QLabel{font: 75 11pt "Calibri"; color: rgb(255, 255, 255);} - - - - 10 - 150 - 171 - 251 - - - - font: 10pt "Calibri"; -border:0px; -QLabel{ -background-color: rgb(255, 255, 255); -color: rgb(37, 37, 38); -} - - - - - - true - - - - - 0 - 10 - 171 - 241 - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 20 - 81 - 20 - - - - font: 10pt "Calibri"; -QLabel{ -background-color: rgb(255, 255, 255); -color: rgb(37, 37, 38); -} - - - Battery charge: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 40 - 81 - 20 - - - - font: 10pt "Calibri"; - - - - Burnt fuses: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 60 - 81 - 20 - - - - font: 10pt "Calibri"; - - - - SD Filesystem: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 80 - 81 - 20 - - - - font: 10pt "Calibri"; - - - FS Total size: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 100 - 81 - 20 - - - - font: 10pt "Calibri"; - - - FS Free space: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 100 - 100 - 71 - 20 - - - - font: 10pt "Calibri"; - - - - - - - - - 100 - 80 - 71 - 20 - - - - font: 10pt "Calibri"; - - - - - - - - - 100 - 60 - 71 - 20 - - - - font: 10pt "Calibri"; - - - - - - - - - 100 - 40 - 71 - 20 - - - - font: 10pt "Calibri"; - - - - - - - - - 100 - 20 - 51 - 20 - - - - QProgressBar { - border: 2px solid grey; - border-radius: 5px; - text-align: center; -} - -QProgressBar::chunk { - background-color: #009688; - width: 1px; -} - - - 24 - - - %p% - - - - - - 10 - 10 - 151 - 221 - - - - font: 10pt "Calibri"; - - - Enable Ariane autoboot - to display device info - - - Qt::AlignCenter - - - - 20 150 - 100 + 101 20 - - - + QFrame::StyledPanel @@ -447,9 +201,9 @@ QProgressBar::chunk { 0 - 0 - 100 - 20 + -1 + 101 + 21 @@ -469,7 +223,7 @@ font: 9pt "Calibri"; 10 40 - 171 + 181 101 @@ -492,7 +246,7 @@ font: 9pt "Calibri"; - font: 10pt "Calibri"; + RCM status: @@ -511,8 +265,7 @@ font: 9pt "Calibri"; - font: 10pt "Calibri"; - + Ariane autoboot: @@ -530,10 +283,6 @@ font: 9pt "Calibri"; 20 - - font: 10pt "Calibri"; - - Ariane status: @@ -545,9 +294,9 @@ font: 9pt "Calibri"; - 390 + 380 20 - 291 + 311 381 @@ -565,7 +314,7 @@ font: 9pt "Calibri"; -1 0 - 685 + 691 21 @@ -583,15 +332,15 @@ font: 9pt "Calibri"; 10 0 - 151 + 191 20 - + font: 75 8pt "Rubik"; - TegraRcmGUI v3.0 + TegraRcmGUI v3.0-a by eliboa Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -600,7 +349,7 @@ font: 9pt "Calibri"; - 655 + 665 0 21 20 @@ -618,11 +367,108 @@ font: 9pt "Calibri"; -1 0 - 651 + 641 20 + + + + 640 + 0 + 21 + 20 + + + + + + + - + + + + + + + 10 + 160 + 181 + 241 + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 20 + 161 + 211 + + + + Enable Ariane autoboot + to display device info + + + Qt::AlignCenter + + + + + + 5 + 15 + 171 + 220 + + + + + 0 + 0 + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectItems + + + false + + + false + + + 100 + + + false + + + 18 + + + 18 + + + di_tableWidget + devInfoDisableLbl statusBoxFrame tabWidget @@ -630,10 +476,10 @@ font: 9pt "Calibri"; rcmStatusFrame arianeStatusFrame verticalLayoutWidget - devInfoBox - deviceInfoFrame pushLayoutWidget titleBarFrame + deviceInfoBoxFrame + deviceInfoFrame diff --git a/types.h b/types.h index aded598..073de53 100644 --- a/types.h +++ b/types.h @@ -15,6 +15,8 @@ using s32 = std::int32_t; using s16 = std::int16_t; using s8 = std::int8_t; +using Bytes = std::vector; + using std::vector; using std::string; using std::array; diff --git a/update_manager/github_api.cpp b/update_manager/github_api.cpp new file mode 100644 index 0000000..edd1c6f --- /dev/null +++ b/update_manager/github_api.cpp @@ -0,0 +1,112 @@ +#include "github_api.h" + +GitHubAPI::GitHubAPI(QObject *parent) + : QObject(parent) +{ + +} + +bool GitHubAPI::getLatestRelease(const QString &owner, const QString &repo, QString *latest_release) +{ + if (!GET_sync(QString("/repos/%1/%2/releases/latest").arg(owner).arg(repo))) + return false; + + QJsonDocument jsonResponse = QJsonDocument::fromJson(m_pReply->readAll()); + QJsonObject jsonObj = jsonResponse.object(); + + QString lr = jsonObj["tag_name"].toString(); + + if (!lr.size()) + return false; + + *latest_release = lr; + return true; +} + +// API GET synchronous +bool GitHubAPI::GET_sync(const QString &endpoint) +{ + QUrl url(QString(GITH_API_URL) + endpoint); + + QNetworkRequest request(url); + request.setRawHeader("Accept", "application/vnd.github.v3+json"); + + m_pReply = manager.get(request); + + if (m_pReply == nullptr) + { + qDebug() << "GitHubAPI::api_GET_sync(): network error"; + return false; + } + + if (!waitForConnect(10000)) + { + qDebug() << "GitHubAPI::api_GET_sync(): timeout"; + m_NetworkError = QNetworkReply::TimeoutError; + return false; + } + + if (m_pReply == nullptr) + { + qDebug() << "GitHubAPI::api_GET_sync(): cancelled"; + m_NetworkError = QNetworkReply::OperationCanceledError; + return false; + } + + if (m_pReply->error() != QNetworkReply::NoError) + { + qDebug() << "GitHubAPI::api_GET_sync(): error" << m_pReply->errorString(); + m_NetworkError = m_pReply->error(); + return false; + } + + return true; +} + +// QNetworkManager is designed to work asynchronously +// We'll use a QEventLoop to wait until we receive the response and a QTimer to set a timeout +bool GitHubAPI::waitForConnect(int nTimeOutms) +{ + QTimer *timer = nullptr; + QEventLoop eventLoop; + bool bReadTimeOut = false; + + if (nTimeOutms > 0) + { + timer = new QTimer(this); + + connect(timer, SIGNAL(timeout()), this, SLOT(slotWaitTimeout())); + timer->setSingleShot(true); + timer->start(nTimeOutms); + + connect(this, SIGNAL(signalReadTimeout()), &eventLoop, SLOT(quit())); + } + + // Wait on QNetworkManager reply here + connect(&manager, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit())); + + if (m_pReply != nullptr) + { + // We wait for the first reply which comes faster than the finished signal + connect(m_pReply, SIGNAL(readyRead()), &eventLoop, SLOT(quit())); + } + eventLoop.exec(); + + if (timer != nullptr) + { + timer->stop(); + delete timer; + timer = nullptr; + } + + bReadTimeOut = m_bReadTimeOut; + m_bReadTimeOut = false; + + return !bReadTimeOut; +} + +void GitHubAPI::slotWaitTimeout() +{ + m_bReadTimeOut = true; // Report timeout + emit signalReadTimeout(); +} diff --git a/update_manager/github_api.h b/update_manager/github_api.h new file mode 100644 index 0000000..2ab0ff2 --- /dev/null +++ b/update_manager/github_api.h @@ -0,0 +1,34 @@ +#ifndef GITH_API_H +#define GITH_API_H + +#include +#include + +#define GITH_API_URL "https://api.github.com" + +class GitHubAPI: public QObject +{ + Q_OBJECT +public: + explicit GitHubAPI(QObject *parent = nullptr); + bool GET_sync(const QString &endpoint); + bool getLatestRelease(const QString &owner, const QString &repo, QString *latest_release); + +private: + QNetworkAccessManager manager; + bool waitForConnect(int nTimeOutms); + +protected: + QNetworkReply *m_pReply; + QNetworkReply::NetworkError m_NetworkError; + bool m_bReadTimeOut = false; + +private slots: + void slotWaitTimeout(); + +signals: + void signalReadTimeout(); +}; + +#endif + diff --git a/update_manager/um_dialog.cpp b/update_manager/um_dialog.cpp new file mode 100644 index 0000000..7c36688 --- /dev/null +++ b/update_manager/um_dialog.cpp @@ -0,0 +1,14 @@ +#include "um_dialog.h" +#include "ui_um_dialog.h" + +UM_Dialog::UM_Dialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::UM_Dialog) +{ + ui->setupUi(this); +} + +UM_Dialog::~UM_Dialog() +{ + delete ui; +} diff --git a/update_manager/um_dialog.h b/update_manager/um_dialog.h new file mode 100644 index 0000000..5ce8bb7 --- /dev/null +++ b/update_manager/um_dialog.h @@ -0,0 +1,22 @@ +#ifndef UM_DIALOG_H +#define UM_DIALOG_H + +#include + +namespace Ui { +class UM_Dialog; +} + +class UM_Dialog : public QWidget +{ + Q_OBJECT + +public: + explicit UM_Dialog(QWidget *parent = nullptr); + ~UM_Dialog(); + +private: + Ui::UM_Dialog *ui; +}; + +#endif // UM_DIALOG_H diff --git a/update_manager/um_dialog.ui b/update_manager/um_dialog.ui new file mode 100644 index 0000000..7f6780b --- /dev/null +++ b/update_manager/um_dialog.ui @@ -0,0 +1,21 @@ + + + + + UM_Dialog + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/update_manager/update_manager.cpp b/update_manager/update_manager.cpp new file mode 100644 index 0000000..b849e46 --- /dev/null +++ b/update_manager/update_manager.cpp @@ -0,0 +1,6 @@ +#include "update_manager.h" + +UpdateManager::UpdateManager(QObject *parent) : QObject(parent) +{ + +} diff --git a/update_manager/update_manager.h b/update_manager/update_manager.h new file mode 100644 index 0000000..244d17d --- /dev/null +++ b/update_manager/update_manager.h @@ -0,0 +1,17 @@ +#ifndef UPDATEMANAGER_H +#define UPDATEMANAGER_H + +#include + +class UpdateManager : public QObject +{ + Q_OBJECT +public: + explicit UpdateManager(QObject *parent = nullptr); + +signals: + +public slots: +}; + +#endif // UPDATEMANAGER_H

XvJk=}sBcM6!8EabbBc1bo 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⪙cZuOE0SsRwhVKc6 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